mirror of https://github.com/apache/druid.git
Process pure ordering changes with windowing operators (#15241)
- adds a new query build path: DruidQuery#toScanAndSortQuery which: - builds a ScanQuery without considering the current ordering - builds an operator to execute the sort - fixes a null string to "null" literal string conversion in the frame serializer code - fixes some DrillWindowQueryTest cases - fix NPE in NaiveSortOperator in case there was no input - enables back CoreRules.AGGREGATE_REMOVE - adds a processing level OffsetLimit class and uses that instead of just the limit in the rac parts - earlier window expressions on top of a subquery with an offset may have ignored the offset
This commit is contained in:
parent
737947754d
commit
f4a74710e6
|
@ -868,6 +868,11 @@ public class Druids
|
||||||
dataSource = new TableDataSource(ds);
|
dataSource = new TableDataSource(ds);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public ScanQueryBuilder dataSource(Query<?> q)
|
||||||
|
{
|
||||||
|
dataSource = new QueryDataSource(q);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ScanQueryBuilder dataSource(DataSource ds)
|
public ScanQueryBuilder dataSource(DataSource ds)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class NaivePartitioningOperatorFactory implements OperatorFactory
|
public class NaivePartitioningOperatorFactory implements OperatorFactory
|
||||||
{
|
{
|
||||||
|
@ -65,4 +66,23 @@ public class NaivePartitioningOperatorFactory implements OperatorFactory
|
||||||
"partitionColumns=" + partitionColumns +
|
"partitionColumns=" + partitionColumns +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hash(partitionColumns);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || obj.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NaivePartitioningOperatorFactory other = (NaivePartitioningOperatorFactory) obj;
|
||||||
|
return Objects.equals(partitionColumns, other.partitionColumns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.druid.query.rowsandcols.semantic.NaiveSortMaker;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A naive sort operator is an operation that sorts a stream of data in-place. Generally speaking this means
|
* A naive sort operator is an operation that sorts a stream of data in-place. Generally speaking this means
|
||||||
|
@ -33,11 +34,11 @@ import java.util.ArrayList;
|
||||||
public class NaiveSortOperator implements Operator
|
public class NaiveSortOperator implements Operator
|
||||||
{
|
{
|
||||||
private final Operator child;
|
private final Operator child;
|
||||||
private final ArrayList<ColumnWithDirection> sortColumns;
|
private final List<ColumnWithDirection> sortColumns;
|
||||||
|
|
||||||
public NaiveSortOperator(
|
public NaiveSortOperator(
|
||||||
Operator child,
|
Operator child,
|
||||||
ArrayList<ColumnWithDirection> sortColumns
|
List<ColumnWithDirection> sortColumns
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.child = child;
|
this.child = child;
|
||||||
|
@ -57,7 +58,7 @@ public class NaiveSortOperator implements Operator
|
||||||
public Signal push(RowsAndColumns rac)
|
public Signal push(RowsAndColumns rac)
|
||||||
{
|
{
|
||||||
if (sorter == null) {
|
if (sorter == null) {
|
||||||
sorter = NaiveSortMaker.fromRAC(rac).make(sortColumns);
|
sorter = NaiveSortMaker.fromRAC(rac).make(new ArrayList<>(sortColumns));
|
||||||
} else {
|
} else {
|
||||||
sorter.moreData(rac);
|
sorter.moreData(rac);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +68,9 @@ public class NaiveSortOperator implements Operator
|
||||||
@Override
|
@Override
|
||||||
public void completed()
|
public void completed()
|
||||||
{
|
{
|
||||||
|
if (sorter != null) {
|
||||||
receiver.push(sorter.complete());
|
receiver.push(sorter.complete());
|
||||||
|
}
|
||||||
receiver.completed();
|
receiver.completed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,22 +22,23 @@ package org.apache.druid.query.operator;
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class NaiveSortOperatorFactory implements OperatorFactory
|
public class NaiveSortOperatorFactory implements OperatorFactory
|
||||||
{
|
{
|
||||||
private final ArrayList<ColumnWithDirection> sortColumns;
|
private final List<ColumnWithDirection> sortColumns;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public NaiveSortOperatorFactory(
|
public NaiveSortOperatorFactory(
|
||||||
@JsonProperty("columns") ArrayList<ColumnWithDirection> sortColumns
|
@JsonProperty("columns") List<ColumnWithDirection> sortColumns
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.sortColumns = sortColumns;
|
this.sortColumns = sortColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("columns")
|
@JsonProperty("columns")
|
||||||
public ArrayList<ColumnWithDirection> getSortColumns()
|
public List<ColumnWithDirection> getSortColumns()
|
||||||
{
|
{
|
||||||
return sortColumns;
|
return sortColumns;
|
||||||
}
|
}
|
||||||
|
@ -56,4 +57,29 @@ public class NaiveSortOperatorFactory implements OperatorFactory
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hash(sortColumns);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NaiveSortOperatorFactory other = (NaiveSortOperatorFactory) obj;
|
||||||
|
return Objects.equals(sortColumns, other.sortColumns);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "NaiveSortOperatorFactory{sortColumns=" + sortColumns + "}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.druid.query.operator;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class OffsetLimit
|
||||||
|
{
|
||||||
|
protected final long offset;
|
||||||
|
protected final long limit;
|
||||||
|
|
||||||
|
public static final OffsetLimit NONE = new OffsetLimit(0, -1);
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public OffsetLimit(
|
||||||
|
@JsonProperty("offset") long offset,
|
||||||
|
@JsonProperty("limit") long limit)
|
||||||
|
{
|
||||||
|
Preconditions.checkArgument(offset >= 0, "offset >= 0");
|
||||||
|
this.offset = offset;
|
||||||
|
this.limit = limit < 0 ? -1 : limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty("offset")
|
||||||
|
public long getOffset()
|
||||||
|
{
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty("limit")
|
||||||
|
public long getLimit()
|
||||||
|
{
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPresent()
|
||||||
|
{
|
||||||
|
return hasOffset() || hasLimit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasOffset()
|
||||||
|
{
|
||||||
|
return offset > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasLimit()
|
||||||
|
{
|
||||||
|
return limit >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OffsetLimit limit(int limit2)
|
||||||
|
{
|
||||||
|
return new OffsetLimit(0, limit2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLimitOrMax()
|
||||||
|
{
|
||||||
|
if (limit < 0) {
|
||||||
|
return Long.MAX_VALUE;
|
||||||
|
} else {
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object o)
|
||||||
|
{
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof OffsetLimit)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
OffsetLimit that = (OffsetLimit) o;
|
||||||
|
return limit == that.limit && offset == that.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hash(limit, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "OffsetLimit{" +
|
||||||
|
"offset=" + offset +
|
||||||
|
", limit=" + limit +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first row index to fetch.
|
||||||
|
*
|
||||||
|
* @param maxIndex maximal index accessible
|
||||||
|
*/
|
||||||
|
public long getFromIndex(long maxIndex)
|
||||||
|
{
|
||||||
|
if (maxIndex <= offset) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last row index to fetch (non-inclusive).
|
||||||
|
*
|
||||||
|
* @param maxIndex maximal index accessible
|
||||||
|
*/
|
||||||
|
public long getToIndex(long maxIndex)
|
||||||
|
{
|
||||||
|
if (maxIndex <= offset) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (hasLimit()) {
|
||||||
|
long toIndex = limit + offset;
|
||||||
|
return Math.min(maxIndex, toIndex);
|
||||||
|
} else {
|
||||||
|
return maxIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ public class ScanOperator implements Operator
|
||||||
private final Operator subOperator;
|
private final Operator subOperator;
|
||||||
private final Interval timeRange;
|
private final Interval timeRange;
|
||||||
private final Filter filter;
|
private final Filter filter;
|
||||||
private final int limit;
|
private final OffsetLimit offsetLimit;
|
||||||
private final List<String> projectedColumns;
|
private final List<String> projectedColumns;
|
||||||
private final VirtualColumns virtualColumns;
|
private final VirtualColumns virtualColumns;
|
||||||
private final List<ColumnWithDirection> ordering;
|
private final List<ColumnWithDirection> ordering;
|
||||||
|
@ -55,7 +55,7 @@ public class ScanOperator implements Operator
|
||||||
Interval timeRange,
|
Interval timeRange,
|
||||||
Filter filter,
|
Filter filter,
|
||||||
List<ColumnWithDirection> ordering,
|
List<ColumnWithDirection> ordering,
|
||||||
int limit
|
OffsetLimit offsetLimit
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.subOperator = subOperator;
|
this.subOperator = subOperator;
|
||||||
|
@ -64,7 +64,7 @@ public class ScanOperator implements Operator
|
||||||
this.timeRange = timeRange;
|
this.timeRange = timeRange;
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.ordering = ordering;
|
this.ordering = ordering;
|
||||||
this.limit = limit;
|
this.offsetLimit = offsetLimit == null ? OffsetLimit.NONE : offsetLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -93,8 +93,8 @@ public class ScanOperator implements Operator
|
||||||
decor.limitTimeRange(timeRange);
|
decor.limitTimeRange(timeRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (limit > 0) {
|
if (offsetLimit.isPresent()) {
|
||||||
decor.setLimit(limit);
|
decor.setOffsetLimit(offsetLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(ordering == null || ordering.isEmpty())) {
|
if (!(ordering == null || ordering.isEmpty())) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class ScanOperatorFactory implements OperatorFactory
|
||||||
{
|
{
|
||||||
private final Interval timeRange;
|
private final Interval timeRange;
|
||||||
private final DimFilter filter;
|
private final DimFilter filter;
|
||||||
private final int limit;
|
private final OffsetLimit offsetLimit;
|
||||||
private final List<String> projectedColumns;
|
private final List<String> projectedColumns;
|
||||||
private final VirtualColumns virtualColumns;
|
private final VirtualColumns virtualColumns;
|
||||||
private final List<ColumnWithDirection> ordering;
|
private final List<ColumnWithDirection> ordering;
|
||||||
|
@ -39,7 +39,7 @@ public class ScanOperatorFactory implements OperatorFactory
|
||||||
public ScanOperatorFactory(
|
public ScanOperatorFactory(
|
||||||
@JsonProperty("timeRange") final Interval timeRange,
|
@JsonProperty("timeRange") final Interval timeRange,
|
||||||
@JsonProperty("filter") final DimFilter filter,
|
@JsonProperty("filter") final DimFilter filter,
|
||||||
@JsonProperty("limit") final Integer limit,
|
@JsonProperty("offsetLimit") final OffsetLimit offsetLimit,
|
||||||
@JsonProperty("projectedColumns") final List<String> projectedColumns,
|
@JsonProperty("projectedColumns") final List<String> projectedColumns,
|
||||||
@JsonProperty("virtualColumns") final VirtualColumns virtualColumns,
|
@JsonProperty("virtualColumns") final VirtualColumns virtualColumns,
|
||||||
@JsonProperty("ordering") final List<ColumnWithDirection> ordering
|
@JsonProperty("ordering") final List<ColumnWithDirection> ordering
|
||||||
|
@ -47,7 +47,7 @@ public class ScanOperatorFactory implements OperatorFactory
|
||||||
{
|
{
|
||||||
this.timeRange = timeRange;
|
this.timeRange = timeRange;
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.limit = limit == null ? -1 : limit;
|
this.offsetLimit = offsetLimit;
|
||||||
this.projectedColumns = projectedColumns;
|
this.projectedColumns = projectedColumns;
|
||||||
this.virtualColumns = virtualColumns;
|
this.virtualColumns = virtualColumns;
|
||||||
this.ordering = ordering;
|
this.ordering = ordering;
|
||||||
|
@ -66,9 +66,9 @@ public class ScanOperatorFactory implements OperatorFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
public int getLimit()
|
public OffsetLimit getOffsetLimit()
|
||||||
{
|
{
|
||||||
return limit;
|
return offsetLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
|
@ -99,7 +99,7 @@ public class ScanOperatorFactory implements OperatorFactory
|
||||||
timeRange,
|
timeRange,
|
||||||
filter == null ? null : filter.toFilter(),
|
filter == null ? null : filter.toFilter(),
|
||||||
ordering,
|
ordering,
|
||||||
limit
|
offsetLimit
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,18 +119,32 @@ public class ScanOperatorFactory implements OperatorFactory
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ScanOperatorFactory that = (ScanOperatorFactory) o;
|
ScanOperatorFactory that = (ScanOperatorFactory) o;
|
||||||
return limit == that.limit && Objects.equals(timeRange, that.timeRange) && Objects.equals(
|
return Objects.equals(offsetLimit, that.offsetLimit)
|
||||||
filter,
|
&& Objects.equals(timeRange, that.timeRange)
|
||||||
that.filter
|
&& Objects.equals(filter, that.filter)
|
||||||
) && Objects.equals(projectedColumns, that.projectedColumns) && Objects.equals(
|
&& Objects.equals(projectedColumns, that.projectedColumns)
|
||||||
virtualColumns,
|
&& Objects.equals(virtualColumns, that.virtualColumns)
|
||||||
that.virtualColumns
|
&& Objects.equals(ordering, that.ordering);
|
||||||
) && Objects.equals(ordering, that.ordering);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
{
|
{
|
||||||
return Objects.hash(timeRange, filter, limit, projectedColumns, virtualColumns, ordering);
|
return Objects.hash(timeRange, filter, offsetLimit, projectedColumns, virtualColumns, ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "ScanOperatorFactory{" +
|
||||||
|
"timeRange=" + timeRange +
|
||||||
|
", filter=" + filter +
|
||||||
|
", offsetLimit=" + offsetLimit +
|
||||||
|
", projectedColumns=" + projectedColumns +
|
||||||
|
", virtualColumns=" + virtualColumns +
|
||||||
|
", ordering=" + ordering
|
||||||
|
+ "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,11 +34,13 @@ import org.apache.druid.query.spec.QuerySegmentSpec;
|
||||||
import org.apache.druid.segment.column.RowSignature;
|
import org.apache.druid.segment.column.RowSignature;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A query that can compute window functions on top of a completely in-memory inline datasource or query results.
|
* A query that can compute window functions on top of a completely in-memory inline datasource or query results.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -122,14 +124,17 @@ public class WindowOperatorQuery extends BaseQuery<RowsAndColumns>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (ordering.isEmpty()) {
|
||||||
|
ordering = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.leafOperators.add(
|
this.leafOperators.add(
|
||||||
new ScanOperatorFactory(
|
new ScanOperatorFactory(
|
||||||
null,
|
null,
|
||||||
scan.getFilter(),
|
scan.getFilter(),
|
||||||
(int) scan.getScanRowsLimit(),
|
scan.getOffsetLimit(),
|
||||||
scan.getColumns(),
|
scan.getColumns(),
|
||||||
scan.getVirtualColumns(),
|
scan.getVirtualColumns().isEmpty() ? null : scan.getVirtualColumns(),
|
||||||
ordering
|
ordering
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -242,16 +247,15 @@ public class WindowOperatorQuery extends BaseQuery<RowsAndColumns>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WindowOperatorQuery that = (WindowOperatorQuery) o;
|
WindowOperatorQuery that = (WindowOperatorQuery) o;
|
||||||
return Objects.equals(rowSignature, that.rowSignature) && Objects.equals(
|
return Objects.equals(rowSignature, that.rowSignature)
|
||||||
operators,
|
&& Objects.equals(operators, that.operators)
|
||||||
that.operators
|
&& Objects.equals(leafOperators, that.leafOperators);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
{
|
{
|
||||||
return Objects.hash(super.hashCode(), rowSignature, operators);
|
return Objects.hash(super.hashCode(), rowSignature, operators, leafOperators);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -263,6 +267,7 @@ public class WindowOperatorQuery extends BaseQuery<RowsAndColumns>
|
||||||
", context=" + getContext() +
|
", context=" + getContext() +
|
||||||
", rowSignature=" + rowSignature +
|
", rowSignature=" + rowSignature +
|
||||||
", operators=" + operators +
|
", operators=" + operators +
|
||||||
|
", leafOperators=" + leafOperators +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ import org.apache.druid.query.operator.Operator;
|
||||||
import org.apache.druid.query.operator.OperatorFactory;
|
import org.apache.druid.query.operator.OperatorFactory;
|
||||||
import org.apache.druid.query.operator.WindowProcessorOperator;
|
import org.apache.druid.query.operator.WindowProcessorOperator;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class WindowOperatorFactory implements OperatorFactory
|
public class WindowOperatorFactory implements OperatorFactory
|
||||||
{
|
{
|
||||||
private Processor processor;
|
private Processor processor;
|
||||||
|
@ -67,4 +69,25 @@ public class WindowOperatorFactory implements OperatorFactory
|
||||||
"processor=" + processor +
|
"processor=" + processor +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hash(processor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || obj.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WindowOperatorFactory other = (WindowOperatorFactory) obj;
|
||||||
|
return Objects.equals(processor, other.processor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.druid.query.rowsandcols.column.IntArrayColumn;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Processor assumes that data has already been sorted for it. It does not re-sort the data and if it is given
|
* This Processor assumes that data has already been sorted for it. It does not re-sort the data and if it is given
|
||||||
|
@ -105,4 +106,29 @@ public class WindowRankProcessor extends WindowRankingProcessorBase
|
||||||
", asPercent=" + asPercent +
|
", asPercent=" + asPercent +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
final int prime = 31;
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = prime * result + Objects.hash(asPercent);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!super.equals(obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WindowRankProcessor other = (WindowRankProcessor) obj;
|
||||||
|
return asPercent == other.asPercent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.druid.query.rowsandcols.semantic.ClusteredGroupPartitioner;
|
||||||
import org.apache.druid.query.rowsandcols.semantic.DefaultClusteredGroupPartitioner;
|
import org.apache.druid.query.rowsandcols.semantic.DefaultClusteredGroupPartitioner;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,4 +101,27 @@ public abstract class WindowRankingProcessorBase implements Processor
|
||||||
return "groupingCols=" + groupingCols +
|
return "groupingCols=" + groupingCols +
|
||||||
", outputColumn='" + outputColumn + '\'';
|
", outputColumn='" + outputColumn + '\'';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hash(groupingCols, outputColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WindowRankingProcessorBase other = (WindowRankingProcessorBase) obj;
|
||||||
|
return Objects.equals(groupingCols, other.groupingCols) && Objects.equals(outputColumn, other.outputColumn);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.apache.druid.java.util.common.guava.Sequence;
|
||||||
import org.apache.druid.query.filter.Filter;
|
import org.apache.druid.query.filter.Filter;
|
||||||
import org.apache.druid.query.filter.ValueMatcher;
|
import org.apache.druid.query.filter.ValueMatcher;
|
||||||
import org.apache.druid.query.operator.ColumnWithDirection;
|
import org.apache.druid.query.operator.ColumnWithDirection;
|
||||||
|
import org.apache.druid.query.operator.OffsetLimit;
|
||||||
import org.apache.druid.query.rowsandcols.column.Column;
|
import org.apache.druid.query.rowsandcols.column.Column;
|
||||||
import org.apache.druid.query.rowsandcols.column.ColumnAccessor;
|
import org.apache.druid.query.rowsandcols.column.ColumnAccessor;
|
||||||
import org.apache.druid.query.rowsandcols.concrete.FrameRowsAndColumns;
|
import org.apache.druid.query.rowsandcols.concrete.FrameRowsAndColumns;
|
||||||
|
@ -73,7 +74,7 @@ public class LazilyDecoratedRowsAndColumns implements RowsAndColumns
|
||||||
private Interval interval;
|
private Interval interval;
|
||||||
private Filter filter;
|
private Filter filter;
|
||||||
private VirtualColumns virtualColumns;
|
private VirtualColumns virtualColumns;
|
||||||
private int limit;
|
private OffsetLimit limit;
|
||||||
private LinkedHashSet<String> viewableColumns;
|
private LinkedHashSet<String> viewableColumns;
|
||||||
private List<ColumnWithDirection> ordering;
|
private List<ColumnWithDirection> ordering;
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ public class LazilyDecoratedRowsAndColumns implements RowsAndColumns
|
||||||
Interval interval,
|
Interval interval,
|
||||||
Filter filter,
|
Filter filter,
|
||||||
VirtualColumns virtualColumns,
|
VirtualColumns virtualColumns,
|
||||||
int limit,
|
OffsetLimit limit,
|
||||||
List<ColumnWithDirection> ordering,
|
List<ColumnWithDirection> ordering,
|
||||||
LinkedHashSet<String> viewableColumns
|
LinkedHashSet<String> viewableColumns
|
||||||
)
|
)
|
||||||
|
@ -175,7 +176,7 @@ public class LazilyDecoratedRowsAndColumns implements RowsAndColumns
|
||||||
|
|
||||||
private boolean needsMaterialization()
|
private boolean needsMaterialization()
|
||||||
{
|
{
|
||||||
return interval != null || filter != null || limit != -1 || ordering != null || virtualColumns != null;
|
return interval != null || filter != null || limit.isPresent() || ordering != null || virtualColumns != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<byte[], RowSignature> materialize()
|
private Pair<byte[], RowSignature> materialize()
|
||||||
|
@ -198,7 +199,7 @@ public class LazilyDecoratedRowsAndColumns implements RowsAndColumns
|
||||||
interval = null;
|
interval = null;
|
||||||
filter = null;
|
filter = null;
|
||||||
virtualColumns = null;
|
virtualColumns = null;
|
||||||
limit = -1;
|
limit = OffsetLimit.NONE;
|
||||||
viewableColumns = null;
|
viewableColumns = null;
|
||||||
ordering = null;
|
ordering = null;
|
||||||
}
|
}
|
||||||
|
@ -238,7 +239,8 @@ public class LazilyDecoratedRowsAndColumns implements RowsAndColumns
|
||||||
throw new ISE("accumulated[%s] non-null, why did we get multiple cursors?", accumulated);
|
throw new ISE("accumulated[%s] non-null, why did we get multiple cursors?", accumulated);
|
||||||
}
|
}
|
||||||
|
|
||||||
int theLimit = limit == -1 ? Integer.MAX_VALUE : limit;
|
long remainingRowsToSkip = limit.getOffset();
|
||||||
|
long remainingRowsToFetch = limit.getLimitOrMax();
|
||||||
|
|
||||||
final ColumnSelectorFactory columnSelectorFactory = in.getColumnSelectorFactory();
|
final ColumnSelectorFactory columnSelectorFactory = in.getColumnSelectorFactory();
|
||||||
final RowSignature.Builder sigBob = RowSignature.builder();
|
final RowSignature.Builder sigBob = RowSignature.builder();
|
||||||
|
@ -284,12 +286,12 @@ public class LazilyDecoratedRowsAndColumns implements RowsAndColumns
|
||||||
);
|
);
|
||||||
|
|
||||||
final FrameWriter frameWriter = frameWriterFactory.newFrameWriter(columnSelectorFactory);
|
final FrameWriter frameWriter = frameWriterFactory.newFrameWriter(columnSelectorFactory);
|
||||||
while (!in.isDoneOrInterrupted()) {
|
for (; !in.isDoneOrInterrupted() && remainingRowsToSkip > 0; remainingRowsToSkip--) {
|
||||||
|
in.advance();
|
||||||
|
}
|
||||||
|
for (; !in.isDoneOrInterrupted() && remainingRowsToFetch > 0; remainingRowsToFetch--) {
|
||||||
frameWriter.addSelection();
|
frameWriter.addSelection();
|
||||||
in.advance();
|
in.advance();
|
||||||
if (--theLimit <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return frameWriter;
|
return frameWriter;
|
||||||
|
@ -390,12 +392,8 @@ public class LazilyDecoratedRowsAndColumns implements RowsAndColumns
|
||||||
sigBob.add(column, racColumn.toAccessor().getType());
|
sigBob.add(column, racColumn.toAccessor().getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
final int limitedNumRows;
|
long remainingRowsToSkip = limit.getOffset();
|
||||||
if (limit == -1) {
|
long remainingRowsToFetch = limit.getLimitOrMax();
|
||||||
limitedNumRows = Integer.MAX_VALUE;
|
|
||||||
} else {
|
|
||||||
limitedNumRows = limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
final FrameWriter frameWriter = FrameWriters.makeFrameWriterFactory(
|
final FrameWriter frameWriter = FrameWriters.makeFrameWriterFactory(
|
||||||
FrameType.COLUMNAR,
|
FrameType.COLUMNAR,
|
||||||
|
@ -405,11 +403,16 @@ public class LazilyDecoratedRowsAndColumns implements RowsAndColumns
|
||||||
).newFrameWriter(selectorFactory);
|
).newFrameWriter(selectorFactory);
|
||||||
|
|
||||||
rowId.set(0);
|
rowId.set(0);
|
||||||
for (; rowId.get() < numRows && frameWriter.getNumRows() < limitedNumRows; rowId.incrementAndGet()) {
|
for (; rowId.get() < numRows && remainingRowsToFetch > 0; rowId.incrementAndGet()) {
|
||||||
final int theId = rowId.get();
|
final int theId = rowId.get();
|
||||||
if (rowsToSkip != null && rowsToSkip.get(theId)) {
|
if (rowsToSkip != null && rowsToSkip.get(theId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (remainingRowsToSkip > 0) {
|
||||||
|
remainingRowsToSkip--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
remainingRowsToFetch--;
|
||||||
frameWriter.addSelection();
|
frameWriter.addSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,9 @@ public class DefaultColumnSelectorFactoryMaker implements ColumnSelectorFactoryM
|
||||||
protected String getValue()
|
protected String getValue()
|
||||||
{
|
{
|
||||||
final Object retVal = columnAccessor.getObject(cellIdSupplier.get());
|
final Object retVal = columnAccessor.getObject(cellIdSupplier.get());
|
||||||
|
if (retVal == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (retVal instanceof ByteBuffer) {
|
if (retVal instanceof ByteBuffer) {
|
||||||
return StringUtils.fromUtf8(((ByteBuffer) retVal).asReadOnlyBuffer());
|
return StringUtils.fromUtf8(((ByteBuffer) retVal).asReadOnlyBuffer());
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.druid.query.rowsandcols.semantic;
|
||||||
|
|
||||||
import org.apache.druid.query.filter.Filter;
|
import org.apache.druid.query.filter.Filter;
|
||||||
import org.apache.druid.query.operator.ColumnWithDirection;
|
import org.apache.druid.query.operator.ColumnWithDirection;
|
||||||
|
import org.apache.druid.query.operator.OffsetLimit;
|
||||||
import org.apache.druid.query.rowsandcols.LazilyDecoratedRowsAndColumns;
|
import org.apache.druid.query.rowsandcols.LazilyDecoratedRowsAndColumns;
|
||||||
import org.apache.druid.query.rowsandcols.RowsAndColumns;
|
import org.apache.druid.query.rowsandcols.RowsAndColumns;
|
||||||
import org.apache.druid.segment.VirtualColumn;
|
import org.apache.druid.segment.VirtualColumn;
|
||||||
|
@ -39,14 +40,14 @@ public class DefaultRowsAndColumnsDecorator implements RowsAndColumnsDecorator
|
||||||
private Interval interval;
|
private Interval interval;
|
||||||
private Filter filter;
|
private Filter filter;
|
||||||
private VirtualColumns virtualColumns;
|
private VirtualColumns virtualColumns;
|
||||||
private int limit;
|
private OffsetLimit offsetLimit;
|
||||||
private List<ColumnWithDirection> ordering;
|
private List<ColumnWithDirection> ordering;
|
||||||
|
|
||||||
public DefaultRowsAndColumnsDecorator(
|
public DefaultRowsAndColumnsDecorator(
|
||||||
RowsAndColumns base
|
RowsAndColumns base
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this(base, null, null, null, -1, null);
|
this(base, null, null, null, OffsetLimit.NONE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultRowsAndColumnsDecorator(
|
public DefaultRowsAndColumnsDecorator(
|
||||||
|
@ -54,7 +55,7 @@ public class DefaultRowsAndColumnsDecorator implements RowsAndColumnsDecorator
|
||||||
Interval interval,
|
Interval interval,
|
||||||
Filter filter,
|
Filter filter,
|
||||||
VirtualColumns virtualColumns,
|
VirtualColumns virtualColumns,
|
||||||
int limit,
|
OffsetLimit limit,
|
||||||
List<ColumnWithDirection> ordering
|
List<ColumnWithDirection> ordering
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -62,7 +63,7 @@ public class DefaultRowsAndColumnsDecorator implements RowsAndColumnsDecorator
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.virtualColumns = virtualColumns;
|
this.virtualColumns = virtualColumns;
|
||||||
this.limit = limit;
|
this.offsetLimit = limit;
|
||||||
this.ordering = ordering;
|
this.ordering = ordering;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,13 +112,9 @@ public class DefaultRowsAndColumnsDecorator implements RowsAndColumnsDecorator
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLimit(int numRows)
|
public void setOffsetLimit(OffsetLimit offsetLimit)
|
||||||
{
|
{
|
||||||
if (this.limit == -1) {
|
this.offsetLimit = offsetLimit;
|
||||||
this.limit = numRows;
|
|
||||||
} else {
|
|
||||||
this.limit = Math.min(limit, numRows);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -134,7 +131,7 @@ public class DefaultRowsAndColumnsDecorator implements RowsAndColumnsDecorator
|
||||||
interval,
|
interval,
|
||||||
filter,
|
filter,
|
||||||
virtualColumns,
|
virtualColumns,
|
||||||
limit,
|
offsetLimit,
|
||||||
ordering,
|
ordering,
|
||||||
columns == null ? null : new LinkedHashSet<>(columns)
|
columns == null ? null : new LinkedHashSet<>(columns)
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.druid.query.rowsandcols.semantic;
|
||||||
|
|
||||||
import org.apache.druid.query.filter.Filter;
|
import org.apache.druid.query.filter.Filter;
|
||||||
import org.apache.druid.query.operator.ColumnWithDirection;
|
import org.apache.druid.query.operator.ColumnWithDirection;
|
||||||
|
import org.apache.druid.query.operator.OffsetLimit;
|
||||||
import org.apache.druid.query.rowsandcols.RowsAndColumns;
|
import org.apache.druid.query.rowsandcols.RowsAndColumns;
|
||||||
import org.apache.druid.segment.VirtualColumns;
|
import org.apache.druid.segment.VirtualColumns;
|
||||||
import org.joda.time.Interval;
|
import org.joda.time.Interval;
|
||||||
|
@ -61,7 +62,7 @@ public interface RowsAndColumnsDecorator
|
||||||
|
|
||||||
void addVirtualColumns(VirtualColumns virtualColumn);
|
void addVirtualColumns(VirtualColumns virtualColumn);
|
||||||
|
|
||||||
void setLimit(int numRows);
|
void setOffsetLimit(OffsetLimit offsetLimit);
|
||||||
|
|
||||||
void setOrdering(List<ColumnWithDirection> ordering);
|
void setOrdering(List<ColumnWithDirection> ordering);
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.apache.druid.query.DataSource;
|
||||||
import org.apache.druid.query.Druids;
|
import org.apache.druid.query.Druids;
|
||||||
import org.apache.druid.query.Queries;
|
import org.apache.druid.query.Queries;
|
||||||
import org.apache.druid.query.filter.DimFilter;
|
import org.apache.druid.query.filter.DimFilter;
|
||||||
|
import org.apache.druid.query.operator.OffsetLimit;
|
||||||
import org.apache.druid.query.spec.QuerySegmentSpec;
|
import org.apache.druid.query.spec.QuerySegmentSpec;
|
||||||
import org.apache.druid.segment.VirtualColumns;
|
import org.apache.druid.segment.VirtualColumns;
|
||||||
import org.apache.druid.segment.column.ColumnHolder;
|
import org.apache.druid.segment.column.ColumnHolder;
|
||||||
|
@ -325,6 +326,11 @@ public class ScanQuery extends BaseQuery<ScanResultValue>
|
||||||
return scanRowsLimit;
|
return scanRowsLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OffsetLimit getOffsetLimit()
|
||||||
|
{
|
||||||
|
return new OffsetLimit(scanRowsOffset, scanRowsLimit);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this query is limited or not. Because {@link Long#MAX_VALUE} is used to signify unlimitedness,
|
* Returns whether this query is limited or not. Because {@link Long#MAX_VALUE} is used to signify unlimitedness,
|
||||||
* this is equivalent to {@code getScanRowsLimit() != Long.Max_VALUE}.
|
* this is equivalent to {@code getScanRowsLimit() != Long.Max_VALUE}.
|
||||||
|
@ -667,4 +673,5 @@ public class ScanQuery extends BaseQuery<ScanResultValue>
|
||||||
return obj instanceof Integer && (int) obj == DEFAULT_BATCH_SIZE;
|
return obj instanceof Integer && (int) obj == DEFAULT_BATCH_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,10 @@ import org.apache.druid.java.util.common.guava.BaseSequence;
|
||||||
import org.apache.druid.java.util.common.guava.Sequence;
|
import org.apache.druid.java.util.common.guava.Sequence;
|
||||||
import org.apache.druid.java.util.common.guava.Sequences;
|
import org.apache.druid.java.util.common.guava.Sequences;
|
||||||
import org.apache.druid.java.util.common.io.Closer;
|
import org.apache.druid.java.util.common.io.Closer;
|
||||||
|
import org.apache.druid.query.DataSource;
|
||||||
import org.apache.druid.query.FrameSignaturePair;
|
import org.apache.druid.query.FrameSignaturePair;
|
||||||
import org.apache.druid.query.GenericQueryMetricsFactory;
|
import org.apache.druid.query.GenericQueryMetricsFactory;
|
||||||
|
import org.apache.druid.query.InlineDataSource;
|
||||||
import org.apache.druid.query.IterableRowsCursorHelper;
|
import org.apache.druid.query.IterableRowsCursorHelper;
|
||||||
import org.apache.druid.query.Query;
|
import org.apache.druid.query.Query;
|
||||||
import org.apache.druid.query.QueryMetrics;
|
import org.apache.druid.query.QueryMetrics;
|
||||||
|
@ -57,6 +59,8 @@ import org.apache.druid.segment.column.ColumnType;
|
||||||
import org.apache.druid.segment.column.RowSignature;
|
import org.apache.druid.segment.column.RowSignature;
|
||||||
import org.apache.druid.utils.CloseableUtils;
|
import org.apache.druid.utils.CloseableUtils;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -196,8 +200,7 @@ public class ScanQueryQueryToolChest extends QueryToolChest<ScanResultValue, Sca
|
||||||
final ColumnCapabilities capabilities = virtualColumn.capabilities(c -> null, columnName);
|
final ColumnCapabilities capabilities = virtualColumn.capabilities(c -> null, columnName);
|
||||||
columnType = capabilities != null ? capabilities.toColumnType() : null;
|
columnType = capabilities != null ? capabilities.toColumnType() : null;
|
||||||
} else {
|
} else {
|
||||||
// Unknown type. In the future, it would be nice to have a way to fill these in.
|
columnType = getDataSourceColumnType(query.getDataSource(), columnName);
|
||||||
columnType = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.add(columnName, columnType);
|
builder.add(columnName, columnType);
|
||||||
|
@ -207,6 +210,20 @@ public class ScanQueryQueryToolChest extends QueryToolChest<ScanResultValue, Sca
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ColumnType getDataSourceColumnType(DataSource dataSource, String columnName)
|
||||||
|
{
|
||||||
|
if (dataSource instanceof InlineDataSource) {
|
||||||
|
InlineDataSource inlineDataSource = (InlineDataSource) dataSource;
|
||||||
|
ColumnCapabilities caps = inlineDataSource.getRowSignature().getColumnCapabilities(columnName);
|
||||||
|
if (caps != null) {
|
||||||
|
return caps.toColumnType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Unknown type. In the future, it would be nice to have a way to fill these in.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This batches the fetched {@link ScanResultValue}s which have similar signatures and are consecutives. In best case
|
* This batches the fetched {@link ScanResultValue}s which have similar signatures and are consecutives. In best case
|
||||||
* it would return a single frame, and in the worst case, it would return as many frames as the number of {@link ScanResultValue}
|
* it would return a single frame, and in the worst case, it would return as many frames as the number of {@link ScanResultValue}
|
||||||
|
|
|
@ -53,6 +53,9 @@ public class TypeStrategies
|
||||||
@Nullable
|
@Nullable
|
||||||
public static TypeStrategy<?> getComplex(String typeName)
|
public static TypeStrategy<?> getComplex(String typeName)
|
||||||
{
|
{
|
||||||
|
if (typeName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return COMPLEX_STRATEGIES.get(typeName);
|
return COMPLEX_STRATEGIES.get(typeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.druid.query.operator;
|
||||||
|
|
||||||
|
import nl.jqno.equalsverifier.EqualsVerifier;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class NaivePartitioningOperatorFactoryTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testEquals()
|
||||||
|
{
|
||||||
|
EqualsVerifier.forClass(NaivePartitioningOperatorFactory.class)
|
||||||
|
.usingGetClass()
|
||||||
|
.verify();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.druid.query.operator;
|
||||||
|
|
||||||
|
import nl.jqno.equalsverifier.EqualsVerifier;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class NaiveSortOperatorFactoryTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testEquals()
|
||||||
|
{
|
||||||
|
EqualsVerifier.forClass(NaiveSortOperatorFactory.class)
|
||||||
|
.usingGetClass()
|
||||||
|
.verify();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.druid.query.operator;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import org.apache.druid.query.operator.Operator.Signal;
|
||||||
|
import org.apache.druid.query.operator.window.RowsAndColumnsHelper;
|
||||||
|
import org.apache.druid.query.rowsandcols.MapOfColumnsRowsAndColumns;
|
||||||
|
import org.apache.druid.query.rowsandcols.RowsAndColumns;
|
||||||
|
import org.apache.druid.query.rowsandcols.column.Column;
|
||||||
|
import org.apache.druid.query.rowsandcols.column.IntArrayColumn;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class NaiveSortOperatorTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testNoInputisHandledCorrectly()
|
||||||
|
{
|
||||||
|
NaiveSortOperator op = new NaiveSortOperator(
|
||||||
|
InlineScanOperator.make(),
|
||||||
|
ImmutableList.of(ColumnWithDirection.ascending("someColumn"))
|
||||||
|
);
|
||||||
|
|
||||||
|
new OperatorTestHelper()
|
||||||
|
.withPushFn(() -> (someRac) -> Signal.GO)
|
||||||
|
.runToCompletion(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSortAscending()
|
||||||
|
{
|
||||||
|
RowsAndColumns rac1 = racForColumn("c", new int[] {5, 3, 1});
|
||||||
|
RowsAndColumns rac2 = racForColumn("c", new int[] {2, 6, 4});
|
||||||
|
|
||||||
|
NaiveSortOperator op = new NaiveSortOperator(
|
||||||
|
InlineScanOperator.make(rac1, rac2),
|
||||||
|
ImmutableList.of(ColumnWithDirection.ascending("c"))
|
||||||
|
);
|
||||||
|
|
||||||
|
new OperatorTestHelper()
|
||||||
|
.expectAndStopAfter(
|
||||||
|
new RowsAndColumnsHelper()
|
||||||
|
.expectColumn("c", new int[] {1, 2, 3, 4, 5, 6})
|
||||||
|
)
|
||||||
|
.runToCompletion(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSortDescending()
|
||||||
|
{
|
||||||
|
RowsAndColumns rac1 = racForColumn("c", new int[] {5, 3, 1});
|
||||||
|
RowsAndColumns rac2 = racForColumn("c", new int[] {2, 6, 4});
|
||||||
|
|
||||||
|
NaiveSortOperator op = new NaiveSortOperator(
|
||||||
|
InlineScanOperator.make(rac1, rac2),
|
||||||
|
ImmutableList.of(ColumnWithDirection.descending("c"))
|
||||||
|
);
|
||||||
|
|
||||||
|
new OperatorTestHelper()
|
||||||
|
.expectAndStopAfter(
|
||||||
|
new RowsAndColumnsHelper()
|
||||||
|
.expectColumn("c", new int[] {6, 5, 4, 3, 2, 1})
|
||||||
|
)
|
||||||
|
.runToCompletion(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapOfColumnsRowsAndColumns racForColumn(String k1, Object arr)
|
||||||
|
{
|
||||||
|
if (int.class.equals(arr.getClass().getComponentType())) {
|
||||||
|
return racForColumn(k1, new IntArrayColumn((int[]) arr));
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Not yet supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapOfColumnsRowsAndColumns racForColumn(String k1, Column v1)
|
||||||
|
{
|
||||||
|
return MapOfColumnsRowsAndColumns.fromMap(ImmutableMap.of(k1, v1));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.druid.query.operator;
|
||||||
|
|
||||||
|
import nl.jqno.equalsverifier.EqualsVerifier;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class OffsetLimitTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testNone()
|
||||||
|
{
|
||||||
|
assertFalse(OffsetLimit.NONE.isPresent());
|
||||||
|
assertFalse(OffsetLimit.NONE.hasOffset());
|
||||||
|
assertFalse(OffsetLimit.NONE.hasLimit());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOffset()
|
||||||
|
{
|
||||||
|
int offset = 3;
|
||||||
|
OffsetLimit ol = new OffsetLimit(offset, -1);
|
||||||
|
assertTrue(ol.hasOffset());
|
||||||
|
assertFalse(ol.hasLimit());
|
||||||
|
assertEquals(offset, ol.getOffset());
|
||||||
|
assertEquals(-1, ol.getLimit());
|
||||||
|
assertEquals(Long.MAX_VALUE, ol.getLimitOrMax());
|
||||||
|
assertEquals(offset, ol.getFromIndex(Long.MAX_VALUE));
|
||||||
|
assertEquals(Long.MAX_VALUE, ol.getToIndex(Long.MAX_VALUE));
|
||||||
|
assertEquals(0, ol.getFromIndex(1));
|
||||||
|
assertEquals(0, ol.getFromIndex(offset));
|
||||||
|
assertEquals(0, ol.getToIndex(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLimit()
|
||||||
|
{
|
||||||
|
OffsetLimit ol = new OffsetLimit(0, 4);
|
||||||
|
assertFalse(ol.hasOffset());
|
||||||
|
assertTrue(ol.hasLimit());
|
||||||
|
assertEquals(0, ol.getOffset());
|
||||||
|
assertEquals(4, ol.getLimit());
|
||||||
|
assertEquals(4, ol.getLimitOrMax());
|
||||||
|
assertEquals(0, ol.getFromIndex(Long.MAX_VALUE));
|
||||||
|
assertEquals(4, ol.getToIndex(Long.MAX_VALUE));
|
||||||
|
assertEquals(0, ol.getFromIndex(2));
|
||||||
|
assertEquals(2, ol.getToIndex(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOffsetLimit()
|
||||||
|
{
|
||||||
|
int offset = 3;
|
||||||
|
int limit = 10;
|
||||||
|
OffsetLimit ol = new OffsetLimit(offset, limit);
|
||||||
|
assertTrue(ol.hasOffset());
|
||||||
|
assertTrue(ol.hasLimit());
|
||||||
|
assertEquals(offset, ol.getOffset());
|
||||||
|
assertEquals(limit, ol.getLimit());
|
||||||
|
assertEquals(limit, ol.getLimitOrMax());
|
||||||
|
assertEquals(offset, ol.getFromIndex(Long.MAX_VALUE));
|
||||||
|
assertEquals(offset + limit, ol.getToIndex(Long.MAX_VALUE));
|
||||||
|
assertEquals(0, ol.getFromIndex(offset));
|
||||||
|
assertEquals(0, ol.getToIndex(offset));
|
||||||
|
assertEquals(offset, ol.getFromIndex(offset + 1));
|
||||||
|
assertEquals(offset + 1, ol.getToIndex(offset + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testInvalidOffset()
|
||||||
|
{
|
||||||
|
new OffsetLimit(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNegativeLimitsAreNotDifferent()
|
||||||
|
{
|
||||||
|
OffsetLimit ol1 = new OffsetLimit(1, -1);
|
||||||
|
OffsetLimit ol2 = new OffsetLimit(1, -2);
|
||||||
|
assertEquals(ol1, ol2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEquals()
|
||||||
|
{
|
||||||
|
EqualsVerifier.forClass(OffsetLimit.class).verify();
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ public class ScanOperatorFactoryTest
|
||||||
final Builder bob = new Builder();
|
final Builder bob = new Builder();
|
||||||
bob.timeRange = Intervals.utc(0, 6);
|
bob.timeRange = Intervals.utc(0, 6);
|
||||||
bob.filter = DimFilters.dimEquals("abc", "b");
|
bob.filter = DimFilters.dimEquals("abc", "b");
|
||||||
bob.limit = 48;
|
bob.offsetLimit = OffsetLimit.limit(48);
|
||||||
bob.projectedColumns = Arrays.asList("a", "b");
|
bob.projectedColumns = Arrays.asList("a", "b");
|
||||||
bob.virtualColumns = VirtualColumns.EMPTY;
|
bob.virtualColumns = VirtualColumns.EMPTY;
|
||||||
bob.ordering = Collections.singletonList(ColumnWithDirection.ascending("a"));
|
bob.ordering = Collections.singletonList(ColumnWithDirection.ascending("a"));
|
||||||
|
@ -72,7 +72,7 @@ public class ScanOperatorFactoryTest
|
||||||
|
|
||||||
Assert.assertNotEquals(factory, bob.copy().setTimeRange(null).build());
|
Assert.assertNotEquals(factory, bob.copy().setTimeRange(null).build());
|
||||||
Assert.assertNotEquals(factory, bob.copy().setFilter(null).build());
|
Assert.assertNotEquals(factory, bob.copy().setFilter(null).build());
|
||||||
Assert.assertNotEquals(factory, bob.copy().setLimit(null).build());
|
Assert.assertNotEquals(factory, bob.copy().setOffsetLimit(null).build());
|
||||||
Assert.assertNotEquals(factory, bob.copy().setProjectedColumns(null).build());
|
Assert.assertNotEquals(factory, bob.copy().setProjectedColumns(null).build());
|
||||||
Assert.assertNotEquals(factory, bob.copy().setVirtualColumns(null).build());
|
Assert.assertNotEquals(factory, bob.copy().setVirtualColumns(null).build());
|
||||||
Assert.assertNotEquals(factory, bob.copy().setOrdering(null).build());
|
Assert.assertNotEquals(factory, bob.copy().setOrdering(null).build());
|
||||||
|
@ -132,7 +132,7 @@ public class ScanOperatorFactoryTest
|
||||||
"interval[%s], filter[%s], limit[%s], ordering[%s], projection[%s], virtual[%s]",
|
"interval[%s], filter[%s], limit[%s], ordering[%s], projection[%s], virtual[%s]",
|
||||||
interval,
|
interval,
|
||||||
filter,
|
filter,
|
||||||
limit,
|
OffsetLimit.limit(limit),
|
||||||
ordering,
|
ordering,
|
||||||
projection,
|
projection,
|
||||||
virtual
|
virtual
|
||||||
|
@ -141,7 +141,7 @@ public class ScanOperatorFactoryTest
|
||||||
ScanOperatorFactory factory = new ScanOperatorFactory(
|
ScanOperatorFactory factory = new ScanOperatorFactory(
|
||||||
interval,
|
interval,
|
||||||
filter,
|
filter,
|
||||||
limit,
|
OffsetLimit.limit(limit),
|
||||||
projection,
|
projection,
|
||||||
virtual,
|
virtual,
|
||||||
ordering
|
ordering
|
||||||
|
@ -182,7 +182,7 @@ public class ScanOperatorFactoryTest
|
||||||
(TestRowsAndColumnsDecorator.DecoratedRowsAndColumns) inRac;
|
(TestRowsAndColumnsDecorator.DecoratedRowsAndColumns) inRac;
|
||||||
|
|
||||||
Assert.assertEquals(msg, factory.getTimeRange(), rac.getTimeRange());
|
Assert.assertEquals(msg, factory.getTimeRange(), rac.getTimeRange());
|
||||||
Assert.assertEquals(msg, factory.getLimit(), rac.getLimit());
|
Assert.assertEquals(msg, factory.getOffsetLimit(), rac.getOffsetLimit());
|
||||||
Assert.assertEquals(msg, factory.getVirtualColumns(), rac.getVirtualColumns());
|
Assert.assertEquals(msg, factory.getVirtualColumns(), rac.getVirtualColumns());
|
||||||
validateList(msg, factory.getOrdering(), rac.getOrdering());
|
validateList(msg, factory.getOrdering(), rac.getOrdering());
|
||||||
validateList(msg, factory.getProjectedColumns(), rac.getProjectedColumns());
|
validateList(msg, factory.getProjectedColumns(), rac.getProjectedColumns());
|
||||||
|
@ -228,7 +228,7 @@ public class ScanOperatorFactoryTest
|
||||||
{
|
{
|
||||||
private Interval timeRange;
|
private Interval timeRange;
|
||||||
private DimFilter filter;
|
private DimFilter filter;
|
||||||
private Integer limit;
|
private OffsetLimit offsetLimit;
|
||||||
private List<String> projectedColumns;
|
private List<String> projectedColumns;
|
||||||
private VirtualColumns virtualColumns;
|
private VirtualColumns virtualColumns;
|
||||||
private List<ColumnWithDirection> ordering;
|
private List<ColumnWithDirection> ordering;
|
||||||
|
@ -245,9 +245,9 @@ public class ScanOperatorFactoryTest
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setLimit(Integer limit)
|
public Builder setOffsetLimit(OffsetLimit offsetLimit)
|
||||||
{
|
{
|
||||||
this.limit = limit;
|
this.offsetLimit = offsetLimit;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ public class ScanOperatorFactoryTest
|
||||||
Builder retVal = new Builder();
|
Builder retVal = new Builder();
|
||||||
retVal.timeRange = timeRange;
|
retVal.timeRange = timeRange;
|
||||||
retVal.filter = filter;
|
retVal.filter = filter;
|
||||||
retVal.limit = limit;
|
retVal.offsetLimit = offsetLimit;
|
||||||
retVal.projectedColumns = projectedColumns;
|
retVal.projectedColumns = projectedColumns;
|
||||||
retVal.virtualColumns = virtualColumns;
|
retVal.virtualColumns = virtualColumns;
|
||||||
retVal.ordering = ordering;
|
retVal.ordering = ordering;
|
||||||
|
@ -286,7 +286,7 @@ public class ScanOperatorFactoryTest
|
||||||
return new ScanOperatorFactory(
|
return new ScanOperatorFactory(
|
||||||
timeRange,
|
timeRange,
|
||||||
filter,
|
filter,
|
||||||
limit,
|
offsetLimit,
|
||||||
projectedColumns,
|
projectedColumns,
|
||||||
virtualColumns,
|
virtualColumns,
|
||||||
ordering
|
ordering
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.druid.query.operator;
|
||||||
|
|
||||||
|
import nl.jqno.equalsverifier.EqualsVerifier;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class WindowOperatorFactoryTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testEquals()
|
||||||
|
{
|
||||||
|
EqualsVerifier.forClass(NaivePartitioningOperatorFactory.class)
|
||||||
|
.usingGetClass()
|
||||||
|
.verify();
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ package org.apache.druid.query.operator;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import nl.jqno.equalsverifier.EqualsVerifier;
|
||||||
import org.apache.druid.java.util.common.Intervals;
|
import org.apache.druid.java.util.common.Intervals;
|
||||||
import org.apache.druid.query.InlineDataSource;
|
import org.apache.druid.query.InlineDataSource;
|
||||||
import org.apache.druid.query.QueryContext;
|
import org.apache.druid.query.QueryContext;
|
||||||
|
@ -131,8 +132,11 @@ public class WindowOperatorQueryTest
|
||||||
@Test
|
@Test
|
||||||
public void testEquals()
|
public void testEquals()
|
||||||
{
|
{
|
||||||
Assert.assertEquals(query, query);
|
EqualsVerifier.simple().forClass(WindowOperatorQuery.class)
|
||||||
Assert.assertEquals(query, query.withDataSource(query.getDataSource()));
|
.withNonnullFields("duration", "querySegmentSpec")
|
||||||
|
.usingGetClass()
|
||||||
|
.verify();
|
||||||
|
|
||||||
Assert.assertNotEquals(query, query.toString());
|
Assert.assertNotEquals(query, query.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
package org.apache.druid.query.rowsandcols.concrete;
|
package org.apache.druid.query.rowsandcols.concrete;
|
||||||
|
|
||||||
|
import org.apache.druid.query.operator.OffsetLimit;
|
||||||
import org.apache.druid.query.rowsandcols.LazilyDecoratedRowsAndColumns;
|
import org.apache.druid.query.rowsandcols.LazilyDecoratedRowsAndColumns;
|
||||||
import org.apache.druid.query.rowsandcols.MapOfColumnsRowsAndColumns;
|
import org.apache.druid.query.rowsandcols.MapOfColumnsRowsAndColumns;
|
||||||
import org.apache.druid.query.rowsandcols.RowsAndColumnsTestBase;
|
import org.apache.druid.query.rowsandcols.RowsAndColumnsTestBase;
|
||||||
|
@ -38,7 +39,7 @@ public class FrameRowsAndColumnsTest extends RowsAndColumnsTestBase
|
||||||
|
|
||||||
private static FrameRowsAndColumns buildFrame(MapOfColumnsRowsAndColumns input)
|
private static FrameRowsAndColumns buildFrame(MapOfColumnsRowsAndColumns input)
|
||||||
{
|
{
|
||||||
LazilyDecoratedRowsAndColumns rac = new LazilyDecoratedRowsAndColumns(input, null, null, null, Integer.MAX_VALUE, null, null);
|
LazilyDecoratedRowsAndColumns rac = new LazilyDecoratedRowsAndColumns(input, null, null, null, OffsetLimit.limit(Integer.MAX_VALUE), null, null);
|
||||||
|
|
||||||
rac.numRows(); // materialize
|
rac.numRows(); // materialize
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.druid.java.util.common.guava.Sequence;
|
||||||
import org.apache.druid.query.filter.Filter;
|
import org.apache.druid.query.filter.Filter;
|
||||||
import org.apache.druid.query.filter.InDimFilter;
|
import org.apache.druid.query.filter.InDimFilter;
|
||||||
import org.apache.druid.query.operator.ColumnWithDirection;
|
import org.apache.druid.query.operator.ColumnWithDirection;
|
||||||
|
import org.apache.druid.query.operator.OffsetLimit;
|
||||||
import org.apache.druid.query.rowsandcols.MapOfColumnsRowsAndColumns;
|
import org.apache.druid.query.rowsandcols.MapOfColumnsRowsAndColumns;
|
||||||
import org.apache.druid.query.rowsandcols.RowsAndColumns;
|
import org.apache.druid.query.rowsandcols.RowsAndColumns;
|
||||||
import org.apache.druid.query.rowsandcols.column.ColumnAccessor;
|
import org.apache.druid.query.rowsandcols.column.ColumnAccessor;
|
||||||
|
@ -121,7 +122,7 @@ public class RowsAndColumnsDecoratorTest extends SemanticTestBase
|
||||||
for (int k = 0; k <= limits.length; ++k) {
|
for (int k = 0; k <= limits.length; ++k) {
|
||||||
int limit = (k == 0 ? -1 : limits[k - 1]);
|
int limit = (k == 0 ? -1 : limits[k - 1]);
|
||||||
for (int l = 0; l <= orderings.length; ++l) {
|
for (int l = 0; l <= orderings.length; ++l) {
|
||||||
validateDecorated(base, siggy, vals, interval, filter, limit, l == 0 ? null : orderings[l - 1]);
|
validateDecorated(base, siggy, vals, interval, filter, OffsetLimit.limit(limit), l == 0 ? null : orderings[l - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +135,7 @@ public class RowsAndColumnsDecoratorTest extends SemanticTestBase
|
||||||
Object[][] originalVals,
|
Object[][] originalVals,
|
||||||
Interval interval,
|
Interval interval,
|
||||||
Filter filter,
|
Filter filter,
|
||||||
int limit,
|
OffsetLimit limit,
|
||||||
List<ColumnWithDirection> ordering
|
List<ColumnWithDirection> ordering
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -211,10 +212,10 @@ public class RowsAndColumnsDecoratorTest extends SemanticTestBase
|
||||||
vals.sort(comparator);
|
vals.sort(comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (limit != -1) {
|
if (limit.isPresent()) {
|
||||||
decor.setLimit(limit);
|
decor.setOffsetLimit(limit);
|
||||||
|
int size = vals.size();
|
||||||
vals = vals.subList(0, Math.min(vals.size(), limit));
|
vals = vals.subList((int) limit.getFromIndex(size), (int) limit.getToIndex(vals.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ordering != null) {
|
if (ordering != null) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.druid.query.rowsandcols.semantic;
|
||||||
|
|
||||||
import org.apache.druid.query.filter.Filter;
|
import org.apache.druid.query.filter.Filter;
|
||||||
import org.apache.druid.query.operator.ColumnWithDirection;
|
import org.apache.druid.query.operator.ColumnWithDirection;
|
||||||
|
import org.apache.druid.query.operator.OffsetLimit;
|
||||||
import org.apache.druid.query.rowsandcols.RowsAndColumns;
|
import org.apache.druid.query.rowsandcols.RowsAndColumns;
|
||||||
import org.apache.druid.query.rowsandcols.column.Column;
|
import org.apache.druid.query.rowsandcols.column.Column;
|
||||||
import org.apache.druid.segment.VirtualColumns;
|
import org.apache.druid.segment.VirtualColumns;
|
||||||
|
@ -35,7 +36,7 @@ public class TestRowsAndColumnsDecorator implements RowsAndColumnsDecorator
|
||||||
private Interval timeRange;
|
private Interval timeRange;
|
||||||
private Filter filter;
|
private Filter filter;
|
||||||
private VirtualColumns virtualColumns;
|
private VirtualColumns virtualColumns;
|
||||||
private int limit = -1;
|
private OffsetLimit offsetLimit = OffsetLimit.NONE;
|
||||||
private List<ColumnWithDirection> ordering;
|
private List<ColumnWithDirection> ordering;
|
||||||
private List<String> projectedColumns;
|
private List<String> projectedColumns;
|
||||||
|
|
||||||
|
@ -58,9 +59,9 @@ public class TestRowsAndColumnsDecorator implements RowsAndColumnsDecorator
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLimit(int numRows)
|
public void setOffsetLimit(OffsetLimit offsetLimit)
|
||||||
{
|
{
|
||||||
this.limit = numRows;
|
this.offsetLimit = offsetLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -99,9 +100,9 @@ public class TestRowsAndColumnsDecorator implements RowsAndColumnsDecorator
|
||||||
return virtualColumns;
|
return virtualColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLimit()
|
public OffsetLimit getOffsetLimit()
|
||||||
{
|
{
|
||||||
return limit;
|
return offsetLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ColumnWithDirection> getOrdering()
|
public List<ColumnWithDirection> getOrdering()
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.druid.query.rowsandcols.semantic;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.apache.druid.query.expression.TestExprMacroTable;
|
import org.apache.druid.query.expression.TestExprMacroTable;
|
||||||
|
import org.apache.druid.query.operator.OffsetLimit;
|
||||||
import org.apache.druid.query.operator.window.RowsAndColumnsHelper;
|
import org.apache.druid.query.operator.window.RowsAndColumnsHelper;
|
||||||
import org.apache.druid.query.rowsandcols.LazilyDecoratedRowsAndColumns;
|
import org.apache.druid.query.rowsandcols.LazilyDecoratedRowsAndColumns;
|
||||||
import org.apache.druid.query.rowsandcols.MapOfColumnsRowsAndColumns;
|
import org.apache.druid.query.rowsandcols.MapOfColumnsRowsAndColumns;
|
||||||
|
@ -74,7 +75,7 @@ public class TestVirtualColumnEvaluationRowsAndColumnsTest extends SemanticTestB
|
||||||
"val * 2",
|
"val * 2",
|
||||||
ColumnType.LONG,
|
ColumnType.LONG,
|
||||||
TestExprMacroTable.INSTANCE)),
|
TestExprMacroTable.INSTANCE)),
|
||||||
Integer.MAX_VALUE,
|
OffsetLimit.NONE,
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ import javax.annotation.Nullable;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
public class TypeStrategiesTest
|
public class TypeStrategiesTest
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(1 << 16);
|
ByteBuffer buffer = ByteBuffer.allocate(1 << 16);
|
||||||
|
@ -692,4 +694,10 @@ public class TypeStrategiesTest
|
||||||
return read(ByteBuffer.wrap(value));
|
return read(ByteBuffer.wrap(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getComplexTypeNull()
|
||||||
|
{
|
||||||
|
assertNull(TypeStrategies.getComplex(null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,11 +177,7 @@ public class CalciteRulesManager
|
||||||
private static final List<RelOptRule> ABSTRACT_RELATIONAL_RULES =
|
private static final List<RelOptRule> ABSTRACT_RELATIONAL_RULES =
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
AbstractConverter.ExpandConversionRule.INSTANCE,
|
AbstractConverter.ExpandConversionRule.INSTANCE,
|
||||||
// Removing CoreRules.AGGREGATE_REMOVE rule here
|
CoreRules.AGGREGATE_REMOVE,
|
||||||
// as after the Calcite upgrade, it would plan queries to a scan over a group by
|
|
||||||
// with ordering on a non-time column
|
|
||||||
// which is not allowed in Druid. We should add that rule back
|
|
||||||
// once Druid starts to support non-time ordering over scan queries
|
|
||||||
CoreRules.UNION_TO_DISTINCT,
|
CoreRules.UNION_TO_DISTINCT,
|
||||||
CoreRules.PROJECT_REMOVE,
|
CoreRules.PROJECT_REMOVE,
|
||||||
CoreRules.AGGREGATE_JOIN_TRANSPOSE,
|
CoreRules.AGGREGATE_JOIN_TRANSPOSE,
|
||||||
|
@ -237,7 +233,13 @@ public class CalciteRulesManager
|
||||||
|
|
||||||
boolean isDebug = plannerContext.queryContext().isDebug();
|
boolean isDebug = plannerContext.queryContext().isDebug();
|
||||||
return ImmutableList.of(
|
return ImmutableList.of(
|
||||||
Programs.sequence(preProgram, Programs.ofRules(druidConventionRuleSet(plannerContext))),
|
Programs.sequence(
|
||||||
|
new LoggingProgram("Start", isDebug),
|
||||||
|
preProgram,
|
||||||
|
new LoggingProgram("After PreProgram", isDebug),
|
||||||
|
Programs.ofRules(druidConventionRuleSet(plannerContext)),
|
||||||
|
new LoggingProgram("After volcano planner program", isDebug)
|
||||||
|
),
|
||||||
Programs.sequence(preProgram, Programs.ofRules(bindableConventionRuleSet(plannerContext))),
|
Programs.sequence(preProgram, Programs.ofRules(bindableConventionRuleSet(plannerContext))),
|
||||||
Programs.sequence(
|
Programs.sequence(
|
||||||
// currently, adding logging program after every stage for easier debugging
|
// currently, adding logging program after every stage for easier debugging
|
||||||
|
|
|
@ -76,6 +76,11 @@ public class OffsetLimit
|
||||||
return limit != null;
|
return limit != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNone()
|
||||||
|
{
|
||||||
|
return !hasLimit() && !hasOffset();
|
||||||
|
}
|
||||||
|
|
||||||
public long getLimit()
|
public long getLimit()
|
||||||
{
|
{
|
||||||
Preconditions.checkState(limit != null, "limit is not present");
|
Preconditions.checkState(limit != null, "limit is not present");
|
||||||
|
@ -162,4 +167,13 @@ public class OffsetLimit
|
||||||
", limit=" + limit +
|
", limit=" + limit +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public org.apache.druid.query.operator.OffsetLimit toOperatorOffsetLimit()
|
||||||
|
{
|
||||||
|
if (hasLimit()) {
|
||||||
|
return new org.apache.druid.query.operator.OffsetLimit(offset, limit);
|
||||||
|
} else {
|
||||||
|
return new org.apache.druid.query.operator.OffsetLimit(offset, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,14 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public class DruidOuterQueryRel extends DruidRel<DruidOuterQueryRel>
|
public class DruidOuterQueryRel extends DruidRel<DruidOuterQueryRel>
|
||||||
{
|
{
|
||||||
private static final TableDataSource DUMMY_DATA_SOURCE = new TableDataSource("__subquery__");
|
private static final TableDataSource DUMMY_DATA_SOURCE = new TableDataSource("__subquery__")
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean isConcrete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private static final QueryDataSource DUMMY_QUERY_DATA_SOURCE = new QueryDataSource(
|
private static final QueryDataSource DUMMY_QUERY_DATA_SOURCE = new QueryDataSource(
|
||||||
Druids.newScanQueryBuilder().dataSource("__subquery__").eternityInterval().build()
|
Druids.newScanQueryBuilder().dataSource("__subquery__").eternityInterval().build()
|
||||||
|
|
|
@ -67,6 +67,9 @@ import org.apache.druid.query.groupby.GroupByQuery;
|
||||||
import org.apache.druid.query.groupby.having.DimFilterHavingSpec;
|
import org.apache.druid.query.groupby.having.DimFilterHavingSpec;
|
||||||
import org.apache.druid.query.groupby.orderby.DefaultLimitSpec;
|
import org.apache.druid.query.groupby.orderby.DefaultLimitSpec;
|
||||||
import org.apache.druid.query.groupby.orderby.OrderByColumnSpec;
|
import org.apache.druid.query.groupby.orderby.OrderByColumnSpec;
|
||||||
|
import org.apache.druid.query.operator.ColumnWithDirection;
|
||||||
|
import org.apache.druid.query.operator.ColumnWithDirection.Direction;
|
||||||
|
import org.apache.druid.query.operator.NaiveSortOperatorFactory;
|
||||||
import org.apache.druid.query.operator.OperatorFactory;
|
import org.apache.druid.query.operator.OperatorFactory;
|
||||||
import org.apache.druid.query.operator.ScanOperatorFactory;
|
import org.apache.druid.query.operator.ScanOperatorFactory;
|
||||||
import org.apache.druid.query.operator.WindowOperatorQuery;
|
import org.apache.druid.query.operator.WindowOperatorQuery;
|
||||||
|
@ -1014,11 +1017,16 @@ public class DruidQuery
|
||||||
return groupByQuery;
|
return groupByQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ScanQuery scanQuery = toScanQuery();
|
final ScanQuery scanQuery = toScanQuery(true);
|
||||||
if (scanQuery != null) {
|
if (scanQuery != null) {
|
||||||
return scanQuery;
|
return scanQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final WindowOperatorQuery scanAndSortQuery = toScanAndSortQuery();
|
||||||
|
if (scanAndSortQuery != null) {
|
||||||
|
return scanAndSortQuery;
|
||||||
|
}
|
||||||
|
|
||||||
throw new CannotBuildQueryException("Cannot convert query parts into an actual query");
|
throw new CannotBuildQueryException("Cannot convert query parts into an actual query");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1439,6 +1447,11 @@ public class DruidQuery
|
||||||
if (windowing == null) {
|
if (windowing == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is not yet supported
|
||||||
|
if (dataSource.isConcrete()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (dataSource instanceof TableDataSource) {
|
if (dataSource instanceof TableDataSource) {
|
||||||
// We need a scan query to pull the results up for us before applying the window
|
// We need a scan query to pull the results up for us before applying the window
|
||||||
// Returning null here to ensure that the planner generates that alternative
|
// Returning null here to ensure that the planner generates that alternative
|
||||||
|
@ -1473,13 +1486,83 @@ public class DruidQuery
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an OperatorQuery which runs an order on top of a scan.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private WindowOperatorQuery toScanAndSortQuery()
|
||||||
|
{
|
||||||
|
if (sorting == null
|
||||||
|
|| sorting.getOrderBys().isEmpty()
|
||||||
|
|| sorting.getProjection() != null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanQuery scan = toScanQuery(false);
|
||||||
|
if (scan == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSource.isConcrete()) {
|
||||||
|
// Currently only non-time orderings of subqueries are allowed.
|
||||||
|
List<String> orderByColumnNames = sorting.getOrderBys()
|
||||||
|
.stream().map(OrderByColumnSpec::getDimension)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
plannerContext.setPlanningError(
|
||||||
|
"SQL query requires ordering a table by non-time column [%s], which is not supported.",
|
||||||
|
orderByColumnNames
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryDataSource newDataSource = new QueryDataSource(scan);
|
||||||
|
List<ColumnWithDirection> sortColumns = getColumnWithDirectionsFromOrderBys(sorting.getOrderBys());
|
||||||
|
RowSignature signature = getOutputRowSignature();
|
||||||
|
List<OperatorFactory> operators = new ArrayList<>();
|
||||||
|
|
||||||
|
operators.add(new NaiveSortOperatorFactory(sortColumns));
|
||||||
|
if (!sorting.getOffsetLimit().isNone()) {
|
||||||
|
operators.add(
|
||||||
|
new ScanOperatorFactory(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
sorting.getOffsetLimit().toOperatorOffsetLimit(),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WindowOperatorQuery(
|
||||||
|
newDataSource,
|
||||||
|
new LegacySegmentSpec(Intervals.ETERNITY),
|
||||||
|
plannerContext.queryContextMap(),
|
||||||
|
signature,
|
||||||
|
operators,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<ColumnWithDirection> getColumnWithDirectionsFromOrderBys(List<OrderByColumnSpec> orderBys)
|
||||||
|
{
|
||||||
|
ArrayList<ColumnWithDirection> ordering = new ArrayList<>();
|
||||||
|
for (OrderByColumnSpec orderBySpec : orderBys) {
|
||||||
|
Direction direction = orderBySpec.getDirection() == OrderByColumnSpec.Direction.ASCENDING
|
||||||
|
? ColumnWithDirection.Direction.ASC
|
||||||
|
: ColumnWithDirection.Direction.DESC;
|
||||||
|
ordering.add(new ColumnWithDirection(orderBySpec.getDimension(), direction));
|
||||||
|
}
|
||||||
|
return ordering;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return this query as a Scan query, or null if this query is not compatible with Scan.
|
* Return this query as a Scan query, or null if this query is not compatible with Scan.
|
||||||
*
|
* @param considerSorting can be used to ignore the current sorting requirements {@link #toScanAndSortQuery()} uses it to produce the non-sorted part
|
||||||
* @return query or null
|
* @return query or null
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private ScanQuery toScanQuery()
|
private ScanQuery toScanQuery(final boolean considerSorting)
|
||||||
{
|
{
|
||||||
if (grouping != null || windowing != null) {
|
if (grouping != null || windowing != null) {
|
||||||
// Scan cannot GROUP BY or do windows.
|
// Scan cannot GROUP BY or do windows.
|
||||||
|
@ -1504,7 +1587,7 @@ public class DruidQuery
|
||||||
long scanOffset = 0L;
|
long scanOffset = 0L;
|
||||||
long scanLimit = 0L;
|
long scanLimit = 0L;
|
||||||
|
|
||||||
if (sorting != null) {
|
if (considerSorting && sorting != null) {
|
||||||
scanOffset = sorting.getOffsetLimit().getOffset();
|
scanOffset = sorting.getOffsetLimit().getOffset();
|
||||||
|
|
||||||
if (sorting.getOffsetLimit().hasLimit()) {
|
if (sorting.getOffsetLimit().hasLimit()) {
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.druid.query;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import org.apache.druid.query.filter.DimFilter;
|
||||||
|
import org.apache.druid.query.operator.ColumnWithDirection;
|
||||||
|
import org.apache.druid.query.operator.ColumnWithDirection.Direction;
|
||||||
|
import org.apache.druid.query.operator.NaivePartitioningOperatorFactory;
|
||||||
|
import org.apache.druid.query.operator.NaiveSortOperatorFactory;
|
||||||
|
import org.apache.druid.query.operator.OffsetLimit;
|
||||||
|
import org.apache.druid.query.operator.OperatorFactory;
|
||||||
|
import org.apache.druid.query.operator.ScanOperatorFactory;
|
||||||
|
import org.apache.druid.query.operator.window.ComposingProcessor;
|
||||||
|
import org.apache.druid.query.operator.window.Processor;
|
||||||
|
import org.apache.druid.query.operator.window.WindowOperatorFactory;
|
||||||
|
import org.apache.druid.query.operator.window.ranking.WindowRankProcessor;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class OperatorFactoryBuilders
|
||||||
|
{
|
||||||
|
|
||||||
|
public static ScanOperatorFactoryBuilder scanOperatorFactoryBuilder()
|
||||||
|
{
|
||||||
|
return new ScanOperatorFactoryBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ScanOperatorFactoryBuilder
|
||||||
|
{
|
||||||
|
private OffsetLimit offsetLimit;
|
||||||
|
private DimFilter filter;
|
||||||
|
private List<String> projectedColumns;
|
||||||
|
|
||||||
|
public OperatorFactory build()
|
||||||
|
{
|
||||||
|
return new ScanOperatorFactory(null, filter, offsetLimit, projectedColumns, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanOperatorFactoryBuilder setOffsetLimit(long offset, long limit)
|
||||||
|
{
|
||||||
|
offsetLimit = new OffsetLimit(offset, limit);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanOperatorFactoryBuilder setFilter(DimFilter filter)
|
||||||
|
{
|
||||||
|
this.filter = filter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanOperatorFactoryBuilder setProjectedColumns(String... columns)
|
||||||
|
{
|
||||||
|
this.projectedColumns = Arrays.asList(columns);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OperatorFactory naiveSortOperator(ColumnWithDirection... colWithDirs)
|
||||||
|
{
|
||||||
|
return new NaiveSortOperatorFactory(Arrays.asList(colWithDirs));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OperatorFactory naiveSortOperator(String column, Direction direction)
|
||||||
|
{
|
||||||
|
return naiveSortOperator(new ColumnWithDirection(column, direction));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OperatorFactory naivePartitionOperator(String... columns)
|
||||||
|
{
|
||||||
|
return new NaivePartitioningOperatorFactory(Arrays.asList(columns));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WindowOperatorFactory windowOperators(Processor... processors)
|
||||||
|
{
|
||||||
|
Preconditions.checkArgument(processors.length > 0, "You must specify at least one processor!");
|
||||||
|
return new WindowOperatorFactory(processors.length == 1 ? processors[0] : new ComposingProcessor(processors));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Processor rankProcessor(String outputColumn, String... groupingColumns)
|
||||||
|
{
|
||||||
|
return new WindowRankProcessor(Arrays.asList(groupingColumns), outputColumn, false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.druid.query;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.apache.druid.java.util.common.Intervals;
|
||||||
|
import org.apache.druid.query.operator.OperatorFactory;
|
||||||
|
import org.apache.druid.query.operator.WindowOperatorQuery;
|
||||||
|
import org.apache.druid.query.spec.LegacySegmentSpec;
|
||||||
|
import org.apache.druid.query.spec.QuerySegmentSpec;
|
||||||
|
import org.apache.druid.segment.column.RowSignature;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class WindowOperatorQueryBuilder
|
||||||
|
{
|
||||||
|
private DataSource dataSource;
|
||||||
|
private QuerySegmentSpec intervals = new LegacySegmentSpec(Intervals.ETERNITY);
|
||||||
|
private Map<String, Object> context;
|
||||||
|
private RowSignature rowSignature;
|
||||||
|
private List<OperatorFactory> operators;
|
||||||
|
private List<OperatorFactory> leafOperators;
|
||||||
|
|
||||||
|
public static WindowOperatorQueryBuilder builder()
|
||||||
|
{
|
||||||
|
return new WindowOperatorQueryBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowOperatorQueryBuilder setDataSource(DataSource dataSource)
|
||||||
|
{
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowOperatorQueryBuilder setDataSource(String dataSource)
|
||||||
|
{
|
||||||
|
return setDataSource(new TableDataSource(dataSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowOperatorQueryBuilder setDataSource(Query<?> query)
|
||||||
|
{
|
||||||
|
return setDataSource(new QueryDataSource(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowOperatorQueryBuilder setSignature(RowSignature rowSignature)
|
||||||
|
{
|
||||||
|
this.rowSignature = rowSignature;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Query<?> build()
|
||||||
|
{
|
||||||
|
return new WindowOperatorQuery(
|
||||||
|
dataSource,
|
||||||
|
intervals,
|
||||||
|
context,
|
||||||
|
rowSignature,
|
||||||
|
operators,
|
||||||
|
leafOperators);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowOperatorQueryBuilder setOperators(OperatorFactory... operators)
|
||||||
|
{
|
||||||
|
this.operators = Lists.newArrayList(operators);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowOperatorQueryBuilder setLeafOperators(OperatorFactory... operators)
|
||||||
|
{
|
||||||
|
this.leafOperators = Lists.newArrayList(operators);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,6 +50,7 @@ import org.apache.druid.query.aggregation.DoubleSumAggregatorFactory;
|
||||||
import org.apache.druid.query.aggregation.ExpressionLambdaAggregatorFactory;
|
import org.apache.druid.query.aggregation.ExpressionLambdaAggregatorFactory;
|
||||||
import org.apache.druid.query.aggregation.FilteredAggregatorFactory;
|
import org.apache.druid.query.aggregation.FilteredAggregatorFactory;
|
||||||
import org.apache.druid.query.aggregation.LongSumAggregatorFactory;
|
import org.apache.druid.query.aggregation.LongSumAggregatorFactory;
|
||||||
|
import org.apache.druid.query.aggregation.post.ExpressionPostAggregator;
|
||||||
import org.apache.druid.query.dimension.DefaultDimensionSpec;
|
import org.apache.druid.query.dimension.DefaultDimensionSpec;
|
||||||
import org.apache.druid.query.expression.TestExprMacroTable;
|
import org.apache.druid.query.expression.TestExprMacroTable;
|
||||||
import org.apache.druid.query.extraction.SubstringDimExtractionFn;
|
import org.apache.druid.query.extraction.SubstringDimExtractionFn;
|
||||||
|
@ -3171,13 +3172,12 @@ public class CalciteArraysQueryTest extends BaseCalciteQueryTest
|
||||||
public void testArrayAggGroupByArrayAggFromSubquery()
|
public void testArrayAggGroupByArrayAggFromSubquery()
|
||||||
{
|
{
|
||||||
cannotVectorize();
|
cannotVectorize();
|
||||||
skipVectorize();
|
|
||||||
testQuery(
|
testQuery(
|
||||||
"SELECT dim2, arr, COUNT(*) FROM (SELECT dim2, ARRAY_AGG(DISTINCT dim1) as arr FROM foo WHERE dim1 is not null GROUP BY 1 LIMIT 5) GROUP BY 1,2",
|
"SELECT dim2, arr, COUNT(*) FROM (SELECT dim2, ARRAY_AGG(DISTINCT dim1) as arr FROM foo WHERE dim1 is not null GROUP BY 1 LIMIT 5) GROUP BY 1,2",
|
||||||
QUERY_CONTEXT_NO_STRINGIFY_ARRAY,
|
QUERY_CONTEXT_NO_STRINGIFY_ARRAY,
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
GroupByQuery.builder()
|
new TopNQueryBuilder()
|
||||||
.setDataSource(new TopNQueryBuilder()
|
|
||||||
.dataSource(CalciteTests.DATASOURCE1)
|
.dataSource(CalciteTests.DATASOURCE1)
|
||||||
.dimension(new DefaultDimensionSpec(
|
.dimension(new DefaultDimensionSpec(
|
||||||
"dim2",
|
"dim2",
|
||||||
|
@ -3209,16 +3209,7 @@ public class CalciteArraysQueryTest extends BaseCalciteQueryTest
|
||||||
.intervals(querySegmentSpec(Filtration.eternity()))
|
.intervals(querySegmentSpec(Filtration.eternity()))
|
||||||
.granularity(Granularities.ALL)
|
.granularity(Granularities.ALL)
|
||||||
.context(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
|
.context(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
|
||||||
.build()
|
.postAggregators(new ExpressionPostAggregator("s0", "1", null, ExprMacroTable.nil()))
|
||||||
)
|
|
||||||
.setInterval(querySegmentSpec(Filtration.eternity()))
|
|
||||||
.setGranularity(Granularities.ALL)
|
|
||||||
.setDimensions(
|
|
||||||
new DefaultDimensionSpec("d0", "_d0", ColumnType.STRING),
|
|
||||||
new DefaultDimensionSpec("a0", "_d1", ColumnType.STRING_ARRAY)
|
|
||||||
)
|
|
||||||
.setAggregatorSpecs(new CountAggregatorFactory("_a0"))
|
|
||||||
.setContext(QUERY_CONTEXT_DEFAULT)
|
|
||||||
.build()
|
.build()
|
||||||
),
|
),
|
||||||
useDefault ?
|
useDefault ?
|
||||||
|
|
|
@ -5381,8 +5381,6 @@ public class CalciteJoinQueryTest extends BaseCalciteQueryTest
|
||||||
@Test
|
@Test
|
||||||
public void testPlanWithInFilterMoreThanInSubQueryThreshold()
|
public void testPlanWithInFilterMoreThanInSubQueryThreshold()
|
||||||
{
|
{
|
||||||
skipVectorize();
|
|
||||||
cannotVectorize();
|
|
||||||
String query = "SELECT l1 FROM numfoo WHERE l1 IN (4842, 4844, 4845, 14905, 4853, 29064)";
|
String query = "SELECT l1 FROM numfoo WHERE l1 IN (4842, 4844, 4845, 14905, 4853, 29064)";
|
||||||
|
|
||||||
Map<String, Object> queryContext = new HashMap<>(QUERY_CONTEXT_DEFAULT);
|
Map<String, Object> queryContext = new HashMap<>(QUERY_CONTEXT_DEFAULT);
|
||||||
|
@ -5399,9 +5397,7 @@ public class CalciteJoinQueryTest extends BaseCalciteQueryTest
|
||||||
.dataSource(
|
.dataSource(
|
||||||
JoinDataSource.create(
|
JoinDataSource.create(
|
||||||
new TableDataSource(CalciteTests.DATASOURCE3),
|
new TableDataSource(CalciteTests.DATASOURCE3),
|
||||||
new QueryDataSource(
|
InlineDataSource.fromIterable(
|
||||||
GroupByQuery.builder()
|
|
||||||
.setDataSource(InlineDataSource.fromIterable(
|
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
new Object[]{4842L},
|
new Object[]{4842L},
|
||||||
new Object[]{4844L},
|
new Object[]{4844L},
|
||||||
|
@ -5413,18 +5409,9 @@ public class CalciteJoinQueryTest extends BaseCalciteQueryTest
|
||||||
RowSignature.builder()
|
RowSignature.builder()
|
||||||
.add("ROW_VALUE", ColumnType.LONG)
|
.add("ROW_VALUE", ColumnType.LONG)
|
||||||
.build()
|
.build()
|
||||||
)
|
|
||||||
)
|
|
||||||
.setInterval(querySegmentSpec(Filtration.eternity()))
|
|
||||||
.setDimensions(
|
|
||||||
new DefaultDimensionSpec("ROW_VALUE", "d0", ColumnType.LONG)
|
|
||||||
)
|
|
||||||
.setGranularity(Granularities.ALL)
|
|
||||||
.setLimitSpec(NoopLimitSpec.instance())
|
|
||||||
.build()
|
|
||||||
),
|
),
|
||||||
"j0.",
|
"j0.",
|
||||||
"(\"l1\" == \"j0.d0\")",
|
"(\"l1\" == \"j0.ROW_VALUE\")",
|
||||||
JoinType.INNER,
|
JoinType.INNER,
|
||||||
null,
|
null,
|
||||||
ExprMacroTable.nil(),
|
ExprMacroTable.nil(),
|
||||||
|
|
|
@ -39,11 +39,13 @@ import org.apache.druid.query.Druids;
|
||||||
import org.apache.druid.query.InlineDataSource;
|
import org.apache.druid.query.InlineDataSource;
|
||||||
import org.apache.druid.query.JoinDataSource;
|
import org.apache.druid.query.JoinDataSource;
|
||||||
import org.apache.druid.query.LookupDataSource;
|
import org.apache.druid.query.LookupDataSource;
|
||||||
|
import org.apache.druid.query.OperatorFactoryBuilders;
|
||||||
import org.apache.druid.query.Query;
|
import org.apache.druid.query.Query;
|
||||||
import org.apache.druid.query.QueryContexts;
|
import org.apache.druid.query.QueryContexts;
|
||||||
import org.apache.druid.query.QueryDataSource;
|
import org.apache.druid.query.QueryDataSource;
|
||||||
import org.apache.druid.query.TableDataSource;
|
import org.apache.druid.query.TableDataSource;
|
||||||
import org.apache.druid.query.UnionDataSource;
|
import org.apache.druid.query.UnionDataSource;
|
||||||
|
import org.apache.druid.query.WindowOperatorQueryBuilder;
|
||||||
import org.apache.druid.query.aggregation.AggregatorFactory;
|
import org.apache.druid.query.aggregation.AggregatorFactory;
|
||||||
import org.apache.druid.query.aggregation.CountAggregatorFactory;
|
import org.apache.druid.query.aggregation.CountAggregatorFactory;
|
||||||
import org.apache.druid.query.aggregation.DoubleMaxAggregatorFactory;
|
import org.apache.druid.query.aggregation.DoubleMaxAggregatorFactory;
|
||||||
|
@ -96,6 +98,7 @@ import org.apache.druid.query.groupby.orderby.NoopLimitSpec;
|
||||||
import org.apache.druid.query.groupby.orderby.OrderByColumnSpec;
|
import org.apache.druid.query.groupby.orderby.OrderByColumnSpec;
|
||||||
import org.apache.druid.query.groupby.orderby.OrderByColumnSpec.Direction;
|
import org.apache.druid.query.groupby.orderby.OrderByColumnSpec.Direction;
|
||||||
import org.apache.druid.query.lookup.RegisteredLookupExtractionFn;
|
import org.apache.druid.query.lookup.RegisteredLookupExtractionFn;
|
||||||
|
import org.apache.druid.query.operator.ColumnWithDirection;
|
||||||
import org.apache.druid.query.ordering.StringComparators;
|
import org.apache.druid.query.ordering.StringComparators;
|
||||||
import org.apache.druid.query.scan.ScanQuery;
|
import org.apache.druid.query.scan.ScanQuery;
|
||||||
import org.apache.druid.query.scan.ScanQuery.ResultFormat;
|
import org.apache.druid.query.scan.ScanQuery.ResultFormat;
|
||||||
|
@ -2725,7 +2728,7 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.CANNOT_CONVERT)
|
@NotYetSupported(Modes.CANNOT_APPLY_VIRTUAL_COL)
|
||||||
@Test
|
@Test
|
||||||
public void testGroupByWithSelectAndOrderByProjections()
|
public void testGroupByWithSelectAndOrderByProjections()
|
||||||
{
|
{
|
||||||
|
@ -2810,7 +2813,7 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.CANNOT_CONVERT)
|
@NotYetSupported(Modes.CANNOT_APPLY_VIRTUAL_COL)
|
||||||
@Test
|
@Test
|
||||||
public void testTopNWithSelectAndOrderByProjections()
|
public void testTopNWithSelectAndOrderByProjections()
|
||||||
{
|
{
|
||||||
|
@ -4692,7 +4695,7 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.CANNOT_CONVERT)
|
@NotYetSupported(Modes.CANNOT_APPLY_VIRTUAL_COL)
|
||||||
@Test
|
@Test
|
||||||
public void testGroupByWithSortOnPostAggregationDefault()
|
public void testGroupByWithSortOnPostAggregationDefault()
|
||||||
{
|
{
|
||||||
|
@ -4724,7 +4727,7 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.CANNOT_CONVERT)
|
@NotYetSupported(Modes.CANNOT_APPLY_VIRTUAL_COL)
|
||||||
@Test
|
@Test
|
||||||
public void testGroupByWithSortOnPostAggregationNoTopNConfig()
|
public void testGroupByWithSortOnPostAggregationNoTopNConfig()
|
||||||
{
|
{
|
||||||
|
@ -4768,7 +4771,7 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.CANNOT_CONVERT)
|
@NotYetSupported(Modes.CANNOT_APPLY_VIRTUAL_COL)
|
||||||
@Test
|
@Test
|
||||||
public void testGroupByWithSortOnPostAggregationNoTopNContext()
|
public void testGroupByWithSortOnPostAggregationNoTopNContext()
|
||||||
{
|
{
|
||||||
|
@ -5370,7 +5373,7 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
final Map<String, String> queries = ImmutableMap.of(
|
final Map<String, String> queries = ImmutableMap.of(
|
||||||
// SELECT query with order by non-__time.
|
// SELECT query with order by non-__time.
|
||||||
"SELECT dim1 FROM druid.foo ORDER BY dim1",
|
"SELECT dim1 FROM druid.foo ORDER BY dim1",
|
||||||
"SQL query requires order by non-time column [[dim1 ASC]], which is not supported.",
|
"SQL query requires ordering a table by non-time column [[dim1]], which is not supported.",
|
||||||
|
|
||||||
// JOIN condition with not-equals (<>).
|
// JOIN condition with not-equals (<>).
|
||||||
"SELECT foo.dim1, foo.dim2, l.k, l.v\n"
|
"SELECT foo.dim1, foo.dim2, l.k, l.v\n"
|
||||||
|
@ -13949,30 +13952,13 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
+ "group by 1",
|
+ "group by 1",
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
GroupByQuery.builder()
|
GroupByQuery.builder()
|
||||||
.setDataSource(GroupByQuery.builder()
|
|
||||||
.setDataSource(CalciteTests.DATASOURCE3)
|
.setDataSource(CalciteTests.DATASOURCE3)
|
||||||
.setInterval(querySegmentSpec(Intervals.ETERNITY))
|
.setInterval(querySegmentSpec(Intervals.ETERNITY))
|
||||||
.setGranularity(Granularities.ALL)
|
.setGranularity(Granularities.ALL)
|
||||||
.addDimension(new DefaultDimensionSpec(
|
.addDimension(new DefaultDimensionSpec("dim1", "_d0", ColumnType.STRING))
|
||||||
"dim1",
|
|
||||||
"_d0",
|
|
||||||
ColumnType.STRING
|
|
||||||
))
|
|
||||||
.addAggregator(new LongSumAggregatorFactory("a0", "l1"))
|
.addAggregator(new LongSumAggregatorFactory("a0", "l1"))
|
||||||
.build()
|
.setPostAggregatorSpecs(ImmutableList.of(
|
||||||
)
|
expressionPostAgg("p0", "case_searched((\"a0\" == 0),1,0)")))
|
||||||
.setInterval(querySegmentSpec(Intervals.ETERNITY))
|
|
||||||
.setDimensions(new DefaultDimensionSpec("_d0", "d0", ColumnType.STRING))
|
|
||||||
.setAggregatorSpecs(aggregators(
|
|
||||||
new FilteredAggregatorFactory(
|
|
||||||
new CountAggregatorFactory("_a0"),
|
|
||||||
useDefault ?
|
|
||||||
selector("a0", "0") :
|
|
||||||
equality("a0", 0, ColumnType.LONG)
|
|
||||||
)
|
|
||||||
))
|
|
||||||
.setGranularity(Granularities.ALL)
|
|
||||||
.setContext(QUERY_CONTEXT_DEFAULT)
|
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
),
|
),
|
||||||
|
@ -14309,7 +14295,9 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
{
|
{
|
||||||
skipVectorize();
|
skipVectorize();
|
||||||
cannotVectorize();
|
cannotVectorize();
|
||||||
testQuery(
|
|
||||||
|
testBuilder()
|
||||||
|
.sql(
|
||||||
"with t AS (SELECT m2, COUNT(m1) as trend_score\n"
|
"with t AS (SELECT m2, COUNT(m1) as trend_score\n"
|
||||||
+ "FROM \"foo\"\n"
|
+ "FROM \"foo\"\n"
|
||||||
+ "GROUP BY 1 \n"
|
+ "GROUP BY 1 \n"
|
||||||
|
@ -14318,57 +14306,66 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
+ "select m2, (MAX(trend_score)) from t\n"
|
+ "select m2, (MAX(trend_score)) from t\n"
|
||||||
+ "where m2 > 2\n"
|
+ "where m2 > 2\n"
|
||||||
+ "GROUP BY 1 \n"
|
+ "GROUP BY 1 \n"
|
||||||
+ "ORDER BY 2 DESC",
|
+ "ORDER BY 2 DESC"
|
||||||
QUERY_CONTEXT_DEFAULT,
|
)
|
||||||
ImmutableList.of(
|
.expectedQuery(
|
||||||
new GroupByQuery.Builder()
|
WindowOperatorQueryBuilder.builder()
|
||||||
.setDataSource(
|
.setDataSource(
|
||||||
new TopNQueryBuilder()
|
new TopNQueryBuilder()
|
||||||
.dataSource(CalciteTests.DATASOURCE1)
|
.dataSource(CalciteTests.DATASOURCE1)
|
||||||
.intervals(querySegmentSpec(Filtration.eternity()))
|
.intervals(querySegmentSpec(Filtration.eternity()))
|
||||||
.dimension(new DefaultDimensionSpec("m2", "d0", ColumnType.DOUBLE))
|
.dimension(new DefaultDimensionSpec("m2", "d0", ColumnType.DOUBLE))
|
||||||
.threshold(10)
|
.threshold(10)
|
||||||
.aggregators(aggregators(
|
.aggregators(
|
||||||
|
aggregators(
|
||||||
useDefault
|
useDefault
|
||||||
? new CountAggregatorFactory("a0")
|
? new CountAggregatorFactory("a0")
|
||||||
: new FilteredAggregatorFactory(
|
: new FilteredAggregatorFactory(
|
||||||
new CountAggregatorFactory("a0"),
|
new CountAggregatorFactory("a0"),
|
||||||
notNull("m1")
|
notNull("m1")
|
||||||
)
|
)
|
||||||
))
|
)
|
||||||
|
)
|
||||||
.metric(new DimensionTopNMetricSpec(null, StringComparators.NUMERIC))
|
.metric(new DimensionTopNMetricSpec(null, StringComparators.NUMERIC))
|
||||||
.context(OUTER_LIMIT_CONTEXT)
|
.context(OUTER_LIMIT_CONTEXT)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setInterval(querySegmentSpec(Filtration.eternity()))
|
.setSignature(
|
||||||
.setGranularity(Granularities.ALL)
|
RowSignature.builder()
|
||||||
.setDimensions(
|
.add("d0", ColumnType.DOUBLE)
|
||||||
new DefaultDimensionSpec("d0", "_d0", ColumnType.DOUBLE)
|
.add("a0", ColumnType.LONG)
|
||||||
)
|
|
||||||
.setDimFilter(
|
|
||||||
useDefault ?
|
|
||||||
bound("d0", "2", null, true, false, null, StringComparators.NUMERIC) :
|
|
||||||
new RangeFilter("d0", ColumnType.LONG, 2L, null, true, false, null)
|
|
||||||
)
|
|
||||||
.setAggregatorSpecs(aggregators(
|
|
||||||
new LongMaxAggregatorFactory("_a0", "a0")
|
|
||||||
))
|
|
||||||
.setLimitSpec(
|
|
||||||
DefaultLimitSpec
|
|
||||||
.builder()
|
|
||||||
.orderBy(new OrderByColumnSpec("_a0", Direction.DESCENDING, StringComparators.NUMERIC))
|
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setContext(OUTER_LIMIT_CONTEXT)
|
.setOperators(
|
||||||
|
OperatorFactoryBuilders.naiveSortOperator("a0", ColumnWithDirection.Direction.DESC)
|
||||||
|
)
|
||||||
|
.setLeafOperators(
|
||||||
|
OperatorFactoryBuilders.scanOperatorFactoryBuilder()
|
||||||
|
.setOffsetLimit(0, Long.MAX_VALUE)
|
||||||
|
.setFilter(
|
||||||
|
range(
|
||||||
|
"d0",
|
||||||
|
ColumnType.LONG,
|
||||||
|
2L,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setProjectedColumns("a0", "d0")
|
||||||
.build()
|
.build()
|
||||||
),
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.expectedResults(
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
new Object[] {3.0D, 1L},
|
new Object[] {3.0D, 1L},
|
||||||
new Object[] {4.0D, 1L},
|
new Object[] {4.0D, 1L},
|
||||||
new Object[] {5.0D, 1L},
|
new Object[] {5.0D, 1L},
|
||||||
new Object[] {6.0D, 1L}
|
new Object[] {6.0D, 1L}
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -14376,8 +14373,7 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
{
|
{
|
||||||
skipVectorize();
|
skipVectorize();
|
||||||
cannotVectorize();
|
cannotVectorize();
|
||||||
testQuery(
|
String sql = "with t AS (SELECT m2 as mo, COUNT(m1) as trend_score\n"
|
||||||
"with t AS (SELECT m2 as mo, COUNT(m1) as trend_score\n"
|
|
||||||
+ "FROM \"foo\"\n"
|
+ "FROM \"foo\"\n"
|
||||||
+ "GROUP BY 1\n"
|
+ "GROUP BY 1\n"
|
||||||
+ "ORDER BY trend_score DESC\n"
|
+ "ORDER BY trend_score DESC\n"
|
||||||
|
@ -14385,56 +14381,167 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
+ "select mo, (MAX(trend_score)) from t\n"
|
+ "select mo, (MAX(trend_score)) from t\n"
|
||||||
+ "where mo > 2\n"
|
+ "where mo > 2\n"
|
||||||
+ "GROUP BY 1 \n"
|
+ "GROUP BY 1 \n"
|
||||||
+ "ORDER BY 2 DESC LIMIT 2\n",
|
+ "ORDER BY 2 DESC LIMIT 2 OFFSET 1\n";
|
||||||
QUERY_CONTEXT_DEFAULT,
|
ImmutableList<Object[]> expectedResults = ImmutableList.of(
|
||||||
ImmutableList.of(
|
new Object[] {4.0D, 1L},
|
||||||
new GroupByQuery.Builder()
|
new Object[] {5.0D, 1L}
|
||||||
|
);
|
||||||
|
|
||||||
|
testBuilder()
|
||||||
|
.sql(sql)
|
||||||
|
.expectedQuery(
|
||||||
|
WindowOperatorQueryBuilder.builder()
|
||||||
.setDataSource(
|
.setDataSource(
|
||||||
new TopNQueryBuilder()
|
new TopNQueryBuilder()
|
||||||
.dataSource(CalciteTests.DATASOURCE1)
|
.dataSource(CalciteTests.DATASOURCE1)
|
||||||
.intervals(querySegmentSpec(Filtration.eternity()))
|
.intervals(querySegmentSpec(Filtration.eternity()))
|
||||||
.dimension(new DefaultDimensionSpec("m2", "d0", ColumnType.DOUBLE))
|
.dimension(new DefaultDimensionSpec("m2", "d0", ColumnType.DOUBLE))
|
||||||
.threshold(10)
|
.threshold(10)
|
||||||
.aggregators(aggregators(
|
.aggregators(
|
||||||
|
aggregators(
|
||||||
useDefault
|
useDefault
|
||||||
? new CountAggregatorFactory("a0")
|
? new CountAggregatorFactory("a0")
|
||||||
: new FilteredAggregatorFactory(
|
: new FilteredAggregatorFactory(
|
||||||
new CountAggregatorFactory("a0"),
|
new CountAggregatorFactory("a0"),
|
||||||
notNull("m1")
|
notNull("m1")
|
||||||
)
|
)
|
||||||
))
|
)
|
||||||
|
)
|
||||||
.metric(new NumericTopNMetricSpec("a0"))
|
.metric(new NumericTopNMetricSpec("a0"))
|
||||||
.context(OUTER_LIMIT_CONTEXT)
|
.context(OUTER_LIMIT_CONTEXT)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
|
.setSignature(
|
||||||
|
RowSignature.builder()
|
||||||
|
.add("d0", ColumnType.DOUBLE)
|
||||||
|
.add("a0", ColumnType.LONG)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.setOperators(
|
||||||
|
OperatorFactoryBuilders.naiveSortOperator("a0", ColumnWithDirection.Direction.DESC),
|
||||||
|
OperatorFactoryBuilders.scanOperatorFactoryBuilder()
|
||||||
|
.setOffsetLimit(1, 2)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.setLeafOperators(
|
||||||
|
OperatorFactoryBuilders.scanOperatorFactoryBuilder()
|
||||||
|
.setOffsetLimit(0, Long.MAX_VALUE)
|
||||||
|
.setFilter(
|
||||||
|
range(
|
||||||
|
"d0",
|
||||||
|
ColumnType.LONG,
|
||||||
|
2L,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setProjectedColumns("a0", "d0")
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.expectedResults(expectedResults)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotYetSupported(Modes.CANNOT_TRANSLATE)
|
||||||
|
@Test
|
||||||
|
public void testWindowingWithScanAndSort()
|
||||||
|
{
|
||||||
|
skipVectorize();
|
||||||
|
cannotVectorize();
|
||||||
|
msqIncompatible();
|
||||||
|
String sql = "with t AS (\n"
|
||||||
|
+ "SELECT \n"
|
||||||
|
+ " RANK() OVER (PARTITION BY m2 ORDER BY m2 ASC) \n"
|
||||||
|
+ " AS ranking,\n"
|
||||||
|
+ " COUNT(m1) as trend_score\n"
|
||||||
|
+ "FROM foo\n"
|
||||||
|
+ "GROUP BY m2,m1 LIMIT 10\n"
|
||||||
|
+ ")\n"
|
||||||
|
+ "select ranking, trend_score from t ORDER BY trend_score";
|
||||||
|
ImmutableList<Object[]> expectedResults = ImmutableList.of(
|
||||||
|
new Object[] {1L, 1L},
|
||||||
|
new Object[] {1L, 1L},
|
||||||
|
new Object[] {1L, 1L},
|
||||||
|
new Object[] {1L, 1L},
|
||||||
|
new Object[] {1L, 1L},
|
||||||
|
new Object[] {1L, 1L}
|
||||||
|
);
|
||||||
|
|
||||||
|
testBuilder()
|
||||||
|
.sql(sql)
|
||||||
|
.queryContext(ImmutableMap.of(PlannerContext.CTX_ENABLE_WINDOW_FNS, true))
|
||||||
|
.expectedQuery(
|
||||||
|
WindowOperatorQueryBuilder.builder()
|
||||||
|
.setDataSource(
|
||||||
|
Druids.newScanQueryBuilder()
|
||||||
|
.dataSource(
|
||||||
|
new WindowOperatorQueryBuilder()
|
||||||
|
.setDataSource(
|
||||||
|
GroupByQuery.builder()
|
||||||
|
.setDataSource(CalciteTests.DATASOURCE1)
|
||||||
.setInterval(querySegmentSpec(Filtration.eternity()))
|
.setInterval(querySegmentSpec(Filtration.eternity()))
|
||||||
.setGranularity(Granularities.ALL)
|
.setGranularity(Granularities.ALL)
|
||||||
.setDimensions(
|
.setDimensions(
|
||||||
new DefaultDimensionSpec("d0", "_d0", ColumnType.DOUBLE)
|
dimensions(
|
||||||
|
new DefaultDimensionSpec("m2", "d0", ColumnType.DOUBLE),
|
||||||
|
new DefaultDimensionSpec("m1", "d1", ColumnType.FLOAT)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setAggregatorSpecs(
|
||||||
|
aggregators(
|
||||||
|
useDefault
|
||||||
|
? new CountAggregatorFactory("a0")
|
||||||
|
: new FilteredAggregatorFactory(
|
||||||
|
new CountAggregatorFactory("a0"),
|
||||||
|
notNull("m1")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.setDimFilter(
|
|
||||||
useDefault ?
|
|
||||||
bound("d0", "2", null, true, false, null, StringComparators.NUMERIC) :
|
|
||||||
new RangeFilter("d0", ColumnType.LONG, 2L, null, true, false, null)
|
|
||||||
)
|
)
|
||||||
.setAggregatorSpecs(aggregators(
|
|
||||||
new LongMaxAggregatorFactory("_a0", "a0")
|
|
||||||
))
|
|
||||||
.setLimitSpec(
|
|
||||||
DefaultLimitSpec
|
|
||||||
.builder()
|
|
||||||
.orderBy(new OrderByColumnSpec("_a0", Direction.DESCENDING, StringComparators.NUMERIC))
|
|
||||||
.limit(2)
|
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setContext(OUTER_LIMIT_CONTEXT)
|
.setOperators(
|
||||||
.build()
|
OperatorFactoryBuilders.naivePartitionOperator("d0"),
|
||||||
),
|
OperatorFactoryBuilders.windowOperators(
|
||||||
ImmutableList.of(
|
OperatorFactoryBuilders.rankProcessor("w0", "d0")
|
||||||
new Object[]{3.0D, 1L},
|
|
||||||
new Object[]{4.0D, 1L}
|
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
|
.setSignature(
|
||||||
|
RowSignature.builder()
|
||||||
|
.add("w0", ColumnType.LONG)
|
||||||
|
.add("a0", ColumnType.LONG)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.intervals(querySegmentSpec(Filtration.eternity()))
|
||||||
|
.columns("a0", "w0")
|
||||||
|
.context(QUERY_CONTEXT_DEFAULT)
|
||||||
|
.resultFormat(ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
|
||||||
|
.legacy(false)
|
||||||
|
.limit(10)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.setSignature(
|
||||||
|
RowSignature.builder()
|
||||||
|
.add("w0", ColumnType.LONG)
|
||||||
|
.add("a0", ColumnType.LONG)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.setOperators(
|
||||||
|
OperatorFactoryBuilders.naiveSortOperator("a0", ColumnWithDirection.Direction.ASC)
|
||||||
|
)
|
||||||
|
.setLeafOperators(
|
||||||
|
OperatorFactoryBuilders.scanOperatorFactoryBuilder()
|
||||||
|
.setOffsetLimit(0, Long.MAX_VALUE)
|
||||||
|
.setProjectedColumns("a0", "w0")
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.expectedResults(expectedResults)
|
||||||
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,7 @@ public class CalciteWindowQueryTest extends BaseCalciteQueryTest
|
||||||
Assert.assertEquals(1, results.recordedQueries.size());
|
Assert.assertEquals(1, results.recordedQueries.size());
|
||||||
|
|
||||||
maybeDumpActualResults(results.results);
|
maybeDumpActualResults(results.results);
|
||||||
|
if (input.expectedOperators != null) {
|
||||||
final WindowOperatorQuery query = getWindowOperatorQuery(results.recordedQueries);
|
final WindowOperatorQuery query = getWindowOperatorQuery(results.recordedQueries);
|
||||||
for (int i = 0; i < input.expectedOperators.size(); ++i) {
|
for (int i = 0; i < input.expectedOperators.size(); ++i) {
|
||||||
final OperatorFactory expectedOperator = input.expectedOperators.get(i);
|
final OperatorFactory expectedOperator = input.expectedOperators.get(i);
|
||||||
|
@ -139,7 +140,9 @@ public class CalciteWindowQueryTest extends BaseCalciteQueryTest
|
||||||
fail("validateEquivalent failed; but textual comparision of operators didn't reported the mismatch!");
|
fail("validateEquivalent failed; but textual comparision of operators didn't reported the mismatch!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final RowSignature outputSignature = query.getRowSignature();
|
}
|
||||||
|
|
||||||
|
final RowSignature outputSignature = results.signature;
|
||||||
ColumnType[] types = new ColumnType[outputSignature.size()];
|
ColumnType[] types = new ColumnType[outputSignature.size()];
|
||||||
for (int i = 0; i < outputSignature.size(); ++i) {
|
for (int i = 0; i < outputSignature.size(); ++i) {
|
||||||
types[i] = outputSignature.getColumnType(i).get();
|
types[i] = outputSignature.getColumnType(i).get();
|
||||||
|
|
|
@ -383,7 +383,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
|
|
||||||
private boolean isOrdered(QueryResults queryResults)
|
private boolean isOrdered(QueryResults queryResults)
|
||||||
{
|
{
|
||||||
SqlNode sqlNode = ((PlannerCaptureHook) queryResults.capture).getSqlNode();
|
SqlNode sqlNode = queryResults.capture.getSqlNode();
|
||||||
return SqlToRelConverter.isOrdered(sqlNode);
|
return SqlToRelConverter.isOrdered(sqlNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4364,6 +4364,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotYetSupported(Modes.CANNOT_APPLY_VIRTUAL_COL)
|
||||||
@DrillTest("nestedAggs/multiWin_5")
|
@DrillTest("nestedAggs/multiWin_5")
|
||||||
@Test
|
@Test
|
||||||
public void test_nestedAggs_multiWin_5()
|
public void test_nestedAggs_multiWin_5()
|
||||||
|
@ -4477,7 +4478,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
|
||||||
@DrillTest("aggregates/aggOWnFn_3")
|
@DrillTest("aggregates/aggOWnFn_3")
|
||||||
@Test
|
@Test
|
||||||
public void test_aggregates_aggOWnFn_3()
|
public void test_aggregates_aggOWnFn_3()
|
||||||
|
@ -4485,7 +4485,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
|
||||||
@DrillTest("aggregates/aggOWnFn_4")
|
@DrillTest("aggregates/aggOWnFn_4")
|
||||||
@Test
|
@Test
|
||||||
public void test_aggregates_aggOWnFn_4()
|
public void test_aggregates_aggOWnFn_4()
|
||||||
|
@ -4493,7 +4492,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
|
||||||
@DrillTest("first_val/firstValFn_29")
|
@DrillTest("first_val/firstValFn_29")
|
||||||
@Test
|
@Test
|
||||||
public void test_first_val_firstValFn_29()
|
public void test_first_val_firstValFn_29()
|
||||||
|
@ -4501,7 +4499,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
|
||||||
@DrillTest("first_val/firstValFn_32")
|
@DrillTest("first_val/firstValFn_32")
|
||||||
@Test
|
@Test
|
||||||
public void test_first_val_firstValFn_32()
|
public void test_first_val_firstValFn_32()
|
||||||
|
@ -4509,7 +4506,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("first_val/firstValFn_33")
|
@DrillTest("first_val/firstValFn_33")
|
||||||
@Test
|
@Test
|
||||||
public void test_first_val_firstValFn_33()
|
public void test_first_val_firstValFn_33()
|
||||||
|
@ -4525,7 +4522,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
|
||||||
@DrillTest("lag_func/lag_Fn_9")
|
@DrillTest("lag_func/lag_Fn_9")
|
||||||
@Test
|
@Test
|
||||||
public void test_lag_func_lag_Fn_9()
|
public void test_lag_func_lag_Fn_9()
|
||||||
|
@ -4533,7 +4529,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
|
||||||
@DrillTest("last_val/lastValFn_29")
|
@DrillTest("last_val/lastValFn_29")
|
||||||
@Test
|
@Test
|
||||||
public void test_last_val_lastValFn_29()
|
public void test_last_val_lastValFn_29()
|
||||||
|
@ -4541,7 +4536,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("last_val/lastValFn_34")
|
@DrillTest("last_val/lastValFn_34")
|
||||||
@Test
|
@Test
|
||||||
public void test_last_val_lastValFn_34()
|
public void test_last_val_lastValFn_34()
|
||||||
|
@ -4549,7 +4544,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("last_val/lastValFn_35")
|
@DrillTest("last_val/lastValFn_35")
|
||||||
@Test
|
@Test
|
||||||
public void test_last_val_lastValFn_35()
|
public void test_last_val_lastValFn_35()
|
||||||
|
@ -4557,7 +4552,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("last_val/lastValFn_38")
|
@DrillTest("last_val/lastValFn_38")
|
||||||
@Test
|
@Test
|
||||||
public void test_last_val_lastValFn_38()
|
public void test_last_val_lastValFn_38()
|
||||||
|
@ -4565,7 +4560,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("last_val/lastValFn_39")
|
@DrillTest("last_val/lastValFn_39")
|
||||||
@Test
|
@Test
|
||||||
public void test_last_val_lastValFn_39()
|
public void test_last_val_lastValFn_39()
|
||||||
|
@ -4581,7 +4576,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
|
||||||
@DrillTest("ntile_func/ntileFn_33")
|
@DrillTest("ntile_func/ntileFn_33")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_33()
|
public void test_ntile_func_ntileFn_33()
|
||||||
|
@ -4589,7 +4583,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
|
||||||
@DrillTest("ntile_func/ntileFn_34")
|
@DrillTest("ntile_func/ntileFn_34")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_34()
|
public void test_ntile_func_ntileFn_34()
|
||||||
|
@ -4597,7 +4590,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_COUNT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_47")
|
@DrillTest("ntile_func/ntileFn_47")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_47()
|
public void test_ntile_func_ntileFn_47()
|
||||||
|
@ -4605,7 +4598,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_COUNT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_48")
|
@DrillTest("ntile_func/ntileFn_48")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_48()
|
public void test_ntile_func_ntileFn_48()
|
||||||
|
@ -4613,7 +4606,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_COUNT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_49")
|
@DrillTest("ntile_func/ntileFn_49")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_49()
|
public void test_ntile_func_ntileFn_49()
|
||||||
|
@ -4621,7 +4614,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_COUNT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_50")
|
@DrillTest("ntile_func/ntileFn_50")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_50()
|
public void test_ntile_func_ntileFn_50()
|
||||||
|
@ -4629,7 +4622,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_COUNT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_51")
|
@DrillTest("ntile_func/ntileFn_51")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_51()
|
public void test_ntile_func_ntileFn_51()
|
||||||
|
@ -4637,7 +4630,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_52")
|
@DrillTest("ntile_func/ntileFn_52")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_52()
|
public void test_ntile_func_ntileFn_52()
|
||||||
|
@ -4645,7 +4638,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_53")
|
@DrillTest("ntile_func/ntileFn_53")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_53()
|
public void test_ntile_func_ntileFn_53()
|
||||||
|
@ -4653,7 +4646,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_54")
|
@DrillTest("ntile_func/ntileFn_54")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_54()
|
public void test_ntile_func_ntileFn_54()
|
||||||
|
@ -4661,7 +4654,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_55")
|
@DrillTest("ntile_func/ntileFn_55")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_55()
|
public void test_ntile_func_ntileFn_55()
|
||||||
|
@ -4669,7 +4662,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_56")
|
@DrillTest("ntile_func/ntileFn_56")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_56()
|
public void test_ntile_func_ntileFn_56()
|
||||||
|
@ -4677,7 +4670,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_57")
|
@DrillTest("ntile_func/ntileFn_57")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_57()
|
public void test_ntile_func_ntileFn_57()
|
||||||
|
@ -4685,7 +4678,7 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.NOT_ENOUGH_RULES)
|
@NotYetSupported(Modes.RESULT_MISMATCH)
|
||||||
@DrillTest("ntile_func/ntileFn_58")
|
@DrillTest("ntile_func/ntileFn_58")
|
||||||
@Test
|
@Test
|
||||||
public void test_ntile_func_ntileFn_58()
|
public void test_ntile_func_ntileFn_58()
|
||||||
|
@ -6697,7 +6690,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/defaultFrame/RBUPACR_chr_3")
|
@DrillTest("frameclause/defaultFrame/RBUPACR_chr_3")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_defaultFrame_RBUPACR_chr_3()
|
public void test_frameclause_defaultFrame_RBUPACR_chr_3()
|
||||||
|
@ -6822,7 +6814,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/defaultFrame/RBUPACR_vchr_3")
|
@DrillTest("frameclause/defaultFrame/RBUPACR_vchr_3")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_defaultFrame_RBUPACR_vchr_3()
|
public void test_frameclause_defaultFrame_RBUPACR_vchr_3()
|
||||||
|
@ -6846,7 +6837,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/multipl_wnwds/count_mulwds")
|
@DrillTest("frameclause/multipl_wnwds/count_mulwds")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_multipl_wnwds_count_mulwds()
|
public void test_frameclause_multipl_wnwds_count_mulwds()
|
||||||
|
@ -6910,7 +6900,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/RBCRACR/RBCRACR_char_3")
|
@DrillTest("frameclause/RBCRACR/RBCRACR_char_3")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_RBCRACR_RBCRACR_char_3()
|
public void test_frameclause_RBCRACR_RBCRACR_char_3()
|
||||||
|
@ -7012,7 +7001,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/RBCRACR/RBCRACR_vchar_3")
|
@DrillTest("frameclause/RBCRACR/RBCRACR_vchar_3")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_RBCRACR_RBCRACR_vchar_3()
|
public void test_frameclause_RBCRACR_RBCRACR_vchar_3()
|
||||||
|
@ -7083,7 +7071,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/RBUPACR/RBUPACR_chr_3")
|
@DrillTest("frameclause/RBUPACR/RBUPACR_chr_3")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_RBUPACR_RBUPACR_chr_3()
|
public void test_frameclause_RBUPACR_RBUPACR_chr_3()
|
||||||
|
@ -7161,7 +7148,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/RBUPACR/RBUPACR_vchr_3")
|
@DrillTest("frameclause/RBUPACR/RBUPACR_vchr_3")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_RBUPACR_RBUPACR_vchr_3()
|
public void test_frameclause_RBUPACR_RBUPACR_vchr_3()
|
||||||
|
@ -7192,7 +7178,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/RBUPAUF/RBUPAUF_char_3")
|
@DrillTest("frameclause/RBUPAUF/RBUPAUF_char_3")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_RBUPAUF_RBUPAUF_char_3()
|
public void test_frameclause_RBUPAUF_RBUPAUF_char_3()
|
||||||
|
@ -7249,7 +7234,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/RBUPAUF/RBUPAUF_vchar_3")
|
@DrillTest("frameclause/RBUPAUF/RBUPAUF_vchar_3")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_RBUPAUF_RBUPAUF_vchar_3()
|
public void test_frameclause_RBUPAUF_RBUPAUF_vchar_3()
|
||||||
|
@ -7257,7 +7241,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/subQueries/frmInSubQry_53")
|
@DrillTest("frameclause/subQueries/frmInSubQry_53")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_subQueries_frmInSubQry_53()
|
public void test_frameclause_subQueries_frmInSubQry_53()
|
||||||
|
@ -7265,7 +7248,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/subQueries/frmInSubQry_54")
|
@DrillTest("frameclause/subQueries/frmInSubQry_54")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_subQueries_frmInSubQry_54()
|
public void test_frameclause_subQueries_frmInSubQry_54()
|
||||||
|
@ -7273,7 +7255,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("frameclause/subQueries/frmInSubQry_55")
|
@DrillTest("frameclause/subQueries/frmInSubQry_55")
|
||||||
@Test
|
@Test
|
||||||
public void test_frameclause_subQueries_frmInSubQry_55()
|
public void test_frameclause_subQueries_frmInSubQry_55()
|
||||||
|
@ -7623,7 +7604,6 @@ public class DrillWindowQueryTest extends BaseCalciteQueryTest
|
||||||
windowQueryTest();
|
windowQueryTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotYetSupported(Modes.RESULT_MISMATCH)
|
|
||||||
@DrillTest("nestedAggs/emtyOvrCls_13")
|
@DrillTest("nestedAggs/emtyOvrCls_13")
|
||||||
@Test
|
@Test
|
||||||
public void test_nestedAggs_emtyOvrCls_13()
|
public void test_nestedAggs_emtyOvrCls_13()
|
||||||
|
|
|
@ -89,7 +89,8 @@ public @interface NotYetSupported
|
||||||
// at least c7 is represented oddly in the parquet file
|
// at least c7 is represented oddly in the parquet file
|
||||||
T_ALLTYPES_ISSUES(AssertionError.class, "(t_alltype|allTypsUniq|fewRowsAllData).parquet.*Verifier.verify"),
|
T_ALLTYPES_ISSUES(AssertionError.class, "(t_alltype|allTypsUniq|fewRowsAllData).parquet.*Verifier.verify"),
|
||||||
RESULT_MISMATCH(AssertionError.class, "assertResultsEquals"),
|
RESULT_MISMATCH(AssertionError.class, "assertResultsEquals"),
|
||||||
UNSUPPORTED_NULL_ORDERING(DruidException.class, "(A|DE)SCENDING ordering with NULLS (LAST|FIRST)");
|
UNSUPPORTED_NULL_ORDERING(DruidException.class, "(A|DE)SCENDING ordering with NULLS (LAST|FIRST)"),
|
||||||
|
CANNOT_TRANSLATE(DruidException.class, "Cannot translate reference");
|
||||||
|
|
||||||
public Class<? extends Throwable> throwableClass;
|
public Class<? extends Throwable> throwableClass;
|
||||||
public String regex;
|
public String regex;
|
||||||
|
|
|
@ -1391,7 +1391,7 @@ public class SqlResourceTest extends CalciteTestBase
|
||||||
DruidException.Persona.ADMIN,
|
DruidException.Persona.ADMIN,
|
||||||
DruidException.Category.INVALID_INPUT,
|
DruidException.Category.INVALID_INPUT,
|
||||||
"Query could not be planned. A possible reason is "
|
"Query could not be planned. A possible reason is "
|
||||||
+ "[SQL query requires order by non-time column [[dim1 ASC]], which is not supported.]"
|
+ "[SQL query requires ordering a table by non-time column [[dim1]], which is not supported.]"
|
||||||
);
|
);
|
||||||
checkSqlRequestLog(false);
|
checkSqlRequestLog(false);
|
||||||
Assert.assertTrue(lifecycleManager.getAll("id").isEmpty());
|
Assert.assertTrue(lifecycleManager.getAll("id").isEmpty());
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
type: "operatorValidation"
|
||||||
|
|
||||||
|
sql: |
|
||||||
|
SELECT
|
||||||
|
RANK() OVER (PARTITION BY m1 ORDER BY m2 ASC) AS ranking,
|
||||||
|
m1,m2,dim1,dim2
|
||||||
|
FROM foo
|
||||||
|
|
||||||
|
|
||||||
|
expectedOperators:
|
||||||
|
- type: "naiveSort"
|
||||||
|
columns:
|
||||||
|
- column: "m1"
|
||||||
|
direction: "ASC"
|
||||||
|
- column: "m2"
|
||||||
|
direction: "ASC"
|
||||||
|
- { type: "naivePartition", partitionColumns: [ m1 ] }
|
||||||
|
- type: "window"
|
||||||
|
processor:
|
||||||
|
type: "rank"
|
||||||
|
group: [ m2 ]
|
||||||
|
outputColumn: w0
|
||||||
|
asPercent: false
|
||||||
|
|
||||||
|
expectedResults:
|
||||||
|
- [1,1.0,1.0,"","a"]
|
||||||
|
- [1,2.0,2.0,"10.1",null]
|
||||||
|
- [1,3.0,3.0,"2",""]
|
||||||
|
- [1,4.0,4.0,"1","a"]
|
||||||
|
- [1,5.0,5.0,"def","abc"]
|
||||||
|
- [1,6.0,6.0,"abc",null]
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue