com.hazelcast.org.apache.calcite.rel.core.AggregateCall Maven / Gradle / Ivy
/*
* 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 com.hazelcast.com.liance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.com.hazelcast.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 com.hazelcast.org.apache.calcite.rel.core;
import com.hazelcast.org.apache.calcite.rel.RelCollation;
import com.hazelcast.org.apache.calcite.rel.RelCollations;
import com.hazelcast.org.apache.calcite.rel.RelNode;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeFactory;
import com.hazelcast.org.apache.calcite.sql.SqlAggFunction;
import com.hazelcast.org.apache.calcite.sql.type.SqlTypeUtil;
import com.hazelcast.org.apache.calcite.util.Optionality;
import com.hazelcast.org.apache.calcite.util.mapping.Mapping;
import com.hazelcast.org.apache.calcite.util.mapping.Mappings;
import com.hazelcast.com.google.com.hazelcast.com.on.base.Preconditions;
import com.hazelcast.com.google.com.hazelcast.com.on.collect.ImmutableList;
import java.util.List;
import java.util.Objects;
/**
* Call to an aggregate function within an
* {@link com.hazelcast.org.apache.calcite.rel.core.Aggregate}.
*/
public class AggregateCall {
//~ Instance fields --------------------------------------------------------
private final SqlAggFunction aggFunction;
private final boolean distinct;
private final boolean approximate;
private final boolean ignoreNulls;
public final RelDataType type;
public final String name;
// We considered using ImmutableIntList but we would not save much memory:
// since all values are small, ImmutableList uses cached Integer values.
private final ImmutableList argList;
public final int filterArg;
public final RelCollation collation;
//~ Constructors -----------------------------------------------------------
/**
* Creates an AggregateCall.
*
* @param aggFunction Aggregate function
* @param distinct Whether distinct
* @param argList List of ordinals of arguments
* @param type Result type
* @param name Name (may be null)
*/
@Deprecated // to be removed before 2.0
public AggregateCall(
SqlAggFunction aggFunction,
boolean distinct,
List argList,
RelDataType type,
String name) {
this(aggFunction, distinct, false, false,
argList, -1, RelCollations.EMPTY, type, name);
}
/**
* Creates an AggregateCall.
*
* @param aggFunction Aggregate function
* @param distinct Whether distinct
* @param approximate Whether approximate
* @param argList List of ordinals of arguments
* @param filterArg Ordinal of filter argument (the
* {@code FILTER (WHERE ...)} clause in SQL), or -1
* @param collation How to sort values before aggregation (the
* {@code WITHIN GROUP} clause in SQL)
* @param type Result type
* @param name Name (may be null)
*/
private AggregateCall(SqlAggFunction aggFunction, boolean distinct,
boolean approximate, boolean ignoreNulls, List argList,
int filterArg, RelCollation collation, RelDataType type, String name) {
this.type = Objects.requireNonNull(type);
this.name = name;
this.aggFunction = Objects.requireNonNull(aggFunction);
this.argList = ImmutableList.copyOf(argList);
this.filterArg = filterArg;
this.collation = Objects.requireNonNull(collation);
this.distinct = distinct;
this.approximate = approximate;
this.ignoreNulls = ignoreNulls;
Preconditions.checkArgument(
aggFunction.getDistinctOptionality() != Optionality.IGNORED || !distinct,
"DISTINCT has no effect for this aggregate function, so must be false");
Preconditions.checkArgument(filterArg < 0 || aggFunction.allowsFilter());
}
//~ Methods ----------------------------------------------------------------
@Deprecated // to be removed before 2.0
public static AggregateCall create(SqlAggFunction aggFunction,
boolean distinct, List argList, int groupCount, RelNode input,
RelDataType type, String name) {
return create(aggFunction, distinct, false, false, argList, -1,
RelCollations.EMPTY, groupCount, input, type, name);
}
@Deprecated // to be removed before 2.0
public static AggregateCall create(SqlAggFunction aggFunction,
boolean distinct, List argList, int filterArg, int groupCount,
RelNode input, RelDataType type, String name) {
return create(aggFunction, distinct, false, false, argList, filterArg,
RelCollations.EMPTY, groupCount, input, type, name);
}
@Deprecated // to be removed before 2.0
public static AggregateCall create(SqlAggFunction aggFunction,
boolean distinct, boolean approximate, List argList,
int filterArg, int groupCount,
RelNode input, RelDataType type, String name) {
return create(aggFunction, distinct, approximate, false, argList,
filterArg, RelCollations.EMPTY, groupCount, input, type, name);
}
@Deprecated // to be removed before 2.0
public static AggregateCall create(SqlAggFunction aggFunction,
boolean distinct, boolean approximate, List argList,
int filterArg, RelCollation collation, int groupCount,
RelNode input, RelDataType type, String name) {
return create(aggFunction, distinct, approximate, false, argList, filterArg,
collation, groupCount, input, type, name);
}
/** Creates an AggregateCall, inferring its type if {@code type} is null. */
public static AggregateCall create(SqlAggFunction aggFunction,
boolean distinct, boolean approximate, boolean ignoreNulls,
List argList, int filterArg, RelCollation collation,
int groupCount,
RelNode input, RelDataType type, String name) {
if (type == null) {
final RelDataTypeFactory typeFactory =
input.getCluster().getTypeFactory();
final List types =
SqlTypeUtil.projectTypes(input.getRowType(), argList);
final Aggregate.AggCallBinding callBinding =
new Aggregate.AggCallBinding(typeFactory, aggFunction, types,
groupCount, filterArg >= 0);
type = aggFunction.inferReturnType(callBinding);
}
return create(aggFunction, distinct, approximate, ignoreNulls, argList,
filterArg, collation, type, name);
}
@Deprecated // to be removed before 2.0
public static AggregateCall create(SqlAggFunction aggFunction,
boolean distinct, List argList, int filterArg, RelDataType type,
String name) {
return create(aggFunction, distinct, false, false, argList, filterArg,
RelCollations.EMPTY, type, name);
}
@Deprecated // to be removed before 2.0
public static AggregateCall create(SqlAggFunction aggFunction,
boolean distinct, boolean approximate, List argList,
int filterArg, RelDataType type, String name) {
return create(aggFunction, distinct, approximate, false, argList, filterArg,
RelCollations.EMPTY, type, name);
}
@Deprecated // to be removed before 2.0
public static AggregateCall create(SqlAggFunction aggFunction,
boolean distinct, boolean approximate, List argList,
int filterArg, RelCollation collation, RelDataType type, String name) {
return create(aggFunction, distinct, approximate, false, argList, filterArg,
collation, type, name);
}
/** Creates an AggregateCall. */
public static AggregateCall create(SqlAggFunction aggFunction,
boolean distinct, boolean approximate, boolean ignoreNulls,
List argList, int filterArg, RelCollation collation,
RelDataType type, String name) {
final boolean distinct2 = distinct
&& (aggFunction.getDistinctOptionality() != Optionality.IGNORED);
return new AggregateCall(aggFunction, distinct2, approximate, ignoreNulls,
argList, filterArg, collation, type, name);
}
/**
* Returns whether this AggregateCall is distinct, as in
* COUNT(DISTINCT empno)
.
*
* @return whether distinct
*/
public final boolean isDistinct() {
return distinct;
}
/**
* Returns whether this AggregateCall is approximate, as in
* APPROX_COUNT_DISTINCT(empno)
.
*
* @return whether approximate
*/
public final boolean isApproximate() {
return approximate;
}
/**
* Returns whether this AggregateCall ignores nulls.
*
* @return whether ignore nulls
*/
public final boolean ignoreNulls() {
return ignoreNulls;
}
/**
* Returns the aggregate function.
*
* @return aggregate function
*/
public final SqlAggFunction getAggregation() {
return aggFunction;
}
/**
* Returns the aggregate ordering definition (the {@code WITHIN GROUP} clause
* in SQL), or the empty list if not specified.
*
* @return ordering definition
*/
public RelCollation getCollation() {
return collation;
}
/**
* Returns the ordinals of the arguments to this call.
*
* The list is immutable.
*
* @return list of argument ordinals
*/
public final List getArgList() {
return argList;
}
/**
* Returns the result type.
*
* @return result type
*/
public final RelDataType getType() {
return type;
}
/**
* Returns the name.
*
* @return name
*/
public String getName() {
return name;
}
/**
* Creates an equivalent AggregateCall that has a new name.
*
* @param name New name (may be null)
*/
public AggregateCall rename(String name) {
if (Objects.equals(this.name, name)) {
return this;
}
return new AggregateCall(aggFunction, distinct, approximate, ignoreNulls,
argList,
filterArg, RelCollations.EMPTY, type,
name);
}
public String toString() {
StringBuilder buf = new StringBuilder(aggFunction.toString());
buf.append("(");
if (approximate) {
buf.append("APPROXIMATE ");
}
if (distinct) {
buf.append((argList.size() == 0) ? "DISTINCT" : "DISTINCT ");
}
int i = -1;
for (Integer arg : argList) {
if (++i > 0) {
buf.append(", ");
}
buf.append("$");
buf.append(arg);
}
buf.append(")");
if (!collation.equals(RelCollations.EMPTY)) {
buf.append(" WITHIN GROUP (");
buf.append(collation);
buf.append(")");
}
if (hasFilter()) {
buf.append(" FILTER $");
buf.append(filterArg);
}
return buf.toString();
}
/** Returns whether this AggregateCall has a filter argument. */
public boolean hasFilter() {
return filterArg >= 0;
}
@Override public boolean equals(Object o) {
if (!(o instanceof AggregateCall)) {
return false;
}
AggregateCall other = (AggregateCall) o;
return aggFunction.equals(other.aggFunction)
&& (distinct == other.distinct)
&& (approximate == other.approximate)
&& (ignoreNulls == other.ignoreNulls)
&& argList.equals(other.argList)
&& filterArg == other.filterArg
&& Objects.equals(collation, other.collation);
}
@Override public int hashCode() {
return Objects.hash(aggFunction,
distinct,
approximate,
ignoreNulls,
argList,
filterArg,
collation);
}
/**
* Creates a binding of this call in the context of an
* {@link com.hazelcast.org.apache.calcite.rel.logical.LogicalAggregate},
* which can then be used to infer the return type.
*/
public Aggregate.AggCallBinding createBinding(
Aggregate aggregateRelBase) {
final RelDataType rowType = aggregateRelBase.getInput().getRowType();
return new Aggregate.AggCallBinding(
aggregateRelBase.getCluster().getTypeFactory(), aggFunction,
SqlTypeUtil.projectTypes(rowType, argList),
aggregateRelBase.getGroupCount(), hasFilter());
}
/**
* Creates an equivalent AggregateCall with new argument ordinals.
*
* @see #transform(Mappings.TargetMapping)
*
* @param args Arguments
* @return AggregateCall that suits new inputs and GROUP BY columns
*/
public AggregateCall copy(List args, int filterArg,
RelCollation collation) {
return new AggregateCall(aggFunction, distinct, approximate, ignoreNulls,
args, filterArg, collation, type, name);
}
@Deprecated // to be removed before 2.0
public AggregateCall copy(List args, int filterArg) {
// ignoring collation is error-prone
return copy(args, filterArg, collation);
}
@Deprecated // to be removed before 2.0
public AggregateCall copy(List args) {
// ignoring filterArg and collation is error-prone
return copy(args, filterArg, collation);
}
/**
* Creates an equivalent AggregateCall that is adapted to a new input types
* and/or number of columns in GROUP BY.
*
* @param input Relation that will be input of Aggregate
* @param argList Argument indices of the new call in the input
* @param filterArg Index of the filter, or -1
* @param oldGroupKeyCount number of columns in GROUP BY of old aggregate
* @param newGroupKeyCount number of columns in GROUP BY of new aggregate
* @return AggregateCall that suits new inputs and GROUP BY columns
*/
public AggregateCall adaptTo(RelNode input, List argList,
int filterArg, int oldGroupKeyCount, int newGroupKeyCount) {
// The return type of aggregate call need to be recomputed.
// Since it might depend on the number of columns in GROUP BY.
final RelDataType newType =
oldGroupKeyCount == newGroupKeyCount
&& argList.equals(this.argList)
&& filterArg == this.filterArg
? type
: null;
return create(aggFunction, distinct, approximate, ignoreNulls, argList,
filterArg, collation, newGroupKeyCount, input, newType, getName());
}
/** Creates a copy of this aggregate call, applying a mapping to its
* arguments. */
public AggregateCall transform(Mappings.TargetMapping mapping) {
return copy(Mappings.apply2((Mapping) mapping, argList),
hasFilter() ? Mappings.apply(mapping, filterArg) : -1,
RelCollations.permute(collation, mapping));
}
}