Skip to content

Commit

Permalink
Add comparison operators to row type
Browse files Browse the repository at this point in the history
Row types now have the capability of comparing. This includes operstors
'>', '>=', '<', and '<='. The comparison starts with the first element of
the row to the last one. All elements in a row should be orderable in
order to compare.
  • Loading branch information
highker committed Mar 9, 2017
1 parent 013d914 commit 56ecfd1
Show file tree
Hide file tree
Showing 10 changed files with 417 additions and 31 deletions.
Expand Up @@ -232,7 +232,11 @@
import static com.facebook.presto.operator.scalar.Re2JCastToRegexpFunction.castVarcharToRe2JRegexp;
import static com.facebook.presto.operator.scalar.RowDistinctFromOperator.ROW_DISTINCT_FROM;
import static com.facebook.presto.operator.scalar.RowEqualOperator.ROW_EQUAL;
import static com.facebook.presto.operator.scalar.RowGreaterThanOperator.ROW_GREATER_THAN;
import static com.facebook.presto.operator.scalar.RowGreaterThanOrEqualOperator.ROW_GREATER_THAN_OR_EQUAL;
import static com.facebook.presto.operator.scalar.RowHashCodeOperator.ROW_HASH_CODE;
import static com.facebook.presto.operator.scalar.RowLessThanOperator.ROW_LESS_THAN;
import static com.facebook.presto.operator.scalar.RowLessThanOrEqualOperator.ROW_LESS_THAN_OR_EQUAL;
import static com.facebook.presto.operator.scalar.RowNotEqualOperator.ROW_NOT_EQUAL;
import static com.facebook.presto.operator.scalar.RowToJsonCast.ROW_TO_JSON;
import static com.facebook.presto.operator.scalar.RowToRowCast.ROW_TO_ROW_CAST;
Expand Down Expand Up @@ -545,7 +549,7 @@ public WindowFunctionSupplier load(SpecializedFunctionKey key)
.functions(MAX_BY, MIN_BY, MAX_BY_N_AGGREGATION, MIN_BY_N_AGGREGATION)
.functions(MAX_AGGREGATION, MIN_AGGREGATION, MAX_N_AGGREGATION, MIN_N_AGGREGATION)
.function(COUNT_COLUMN)
.functions(ROW_HASH_CODE, ROW_TO_JSON, ROW_DISTINCT_FROM, ROW_EQUAL, ROW_NOT_EQUAL, ROW_TO_ROW_CAST)
.functions(ROW_HASH_CODE, ROW_TO_JSON, ROW_DISTINCT_FROM, ROW_EQUAL, ROW_GREATER_THAN, ROW_GREATER_THAN_OR_EQUAL, ROW_LESS_THAN, ROW_LESS_THAN_OR_EQUAL, ROW_NOT_EQUAL, ROW_TO_ROW_CAST)
.function(CONCAT)
.function(DECIMAL_TO_DECIMAL_CAST)
.function(castVarcharToRe2JRegexp(featuresConfig.getRe2JDfaStatesLimit(), featuresConfig.getRe2JDfaRetries()))
Expand Down
Expand Up @@ -215,6 +215,11 @@ public static TypeVariableConstraint comparableTypeParameter(String name)
return new TypeVariableConstraint(name, true, false, null);
}

public static TypeVariableConstraint orderableWithVariadicBound(String name, String variadicBound)
{
return new TypeVariableConstraint(name, false, true, variadicBound);
}

public static TypeVariableConstraint orderableTypeParameter(String name)
{
return new TypeVariableConstraint(name, false, true, null);
Expand Down
@@ -0,0 +1,88 @@
package com.facebook.presto.operator.scalar;
/*
* Licensed 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.
*/

import com.facebook.presto.metadata.FunctionRegistry;
import com.facebook.presto.metadata.Signature;
import com.facebook.presto.metadata.SqlOperator;
import com.facebook.presto.spi.PrestoException;
import com.facebook.presto.spi.block.Block;
import com.facebook.presto.spi.function.OperatorType;
import com.facebook.presto.spi.type.StandardTypes;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.type.RowType;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;

import java.lang.invoke.MethodHandle;
import java.util.List;

import static com.facebook.presto.metadata.Signature.orderableWithVariadicBound;
import static com.facebook.presto.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR;
import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
import static com.facebook.presto.spi.type.TypeUtils.readNativeValue;
import static com.facebook.presto.type.TypeUtils.checkElementNotNull;

public abstract class RowComparisonOperator
extends SqlOperator
{
protected RowComparisonOperator(OperatorType operatorType)
{
super(operatorType,
ImmutableList.of(orderableWithVariadicBound("T", StandardTypes.ROW)),
ImmutableList.of(),
parseTypeSignature(StandardTypes.BOOLEAN),
ImmutableList.of(parseTypeSignature("T"), parseTypeSignature("T")));
}

protected List<MethodHandle> getMethodHandles(RowType type, FunctionRegistry functionRegistry, OperatorType operatorType)
{
ImmutableList.Builder<MethodHandle> argumentMethods = ImmutableList.builder();
for (Type parameterType : type.getTypeParameters()) {
Signature signature = functionRegistry.resolveOperator(operatorType, ImmutableList.of(parameterType, parameterType));
argumentMethods.add(functionRegistry.getScalarFunctionImplementation(signature).getMethodHandle());
}
return argumentMethods.build();
}

protected static int compare(
RowType rowType,
List<MethodHandle> comparisonFunctions,
Block leftRow,
Block rightRow)
{
for (int i = 0; i < leftRow.getPositionCount(); i++) {
checkElementNotNull(leftRow.isNull(i), "null value at position " + i);
checkElementNotNull(rightRow.isNull(i), "null value at position " + i);
Type type = rowType.getTypeParameters().get(i);
Object leftElement = readNativeValue(type, leftRow, i);
Object rightElement = readNativeValue(type, rightRow, i);
try {
if ((boolean) comparisonFunctions.get(i).invoke(leftElement, rightElement)) {
return 1;
}
if ((boolean) comparisonFunctions.get(i).invoke(rightElement, leftElement)) {
return -1;
}
}
catch (Throwable t) {
Throwables.propagateIfInstanceOf(t, Error.class);
Throwables.propagateIfInstanceOf(t, PrestoException.class);

throw new PrestoException(GENERIC_INTERNAL_ERROR, t);
}
}
return 0;
}
}
@@ -0,0 +1,60 @@
package com.facebook.presto.operator.scalar;
/*
* Licensed 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.
*/

import com.facebook.presto.metadata.BoundVariables;
import com.facebook.presto.metadata.FunctionRegistry;
import com.facebook.presto.spi.block.Block;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.type.RowType;
import com.google.common.collect.ImmutableList;

import java.lang.invoke.MethodHandle;
import java.util.List;

import static com.facebook.presto.spi.function.OperatorType.GREATER_THAN;
import static com.facebook.presto.util.Reflection.methodHandle;

public final class RowGreaterThanOperator
extends RowComparisonOperator
{
public static final RowGreaterThanOperator ROW_GREATER_THAN = new RowGreaterThanOperator();
private static final MethodHandle METHOD_HANDLE = methodHandle(RowGreaterThanOperator.class, "greater", RowType.class, List.class, Block.class, Block.class);

private RowGreaterThanOperator()
{
super(GREATER_THAN);
}

@Override
public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry)
{
Type type = boundVariables.getTypeVariable("T");
return new ScalarFunctionImplementation(
false,
ImmutableList.of(false, false),
METHOD_HANDLE.bindTo(type).bindTo(getMethodHandles((RowType) type, functionRegistry, GREATER_THAN)),
isDeterministic());
}

public static boolean greater(
RowType rowType,
List<MethodHandle> lessThanFunctions,
Block leftRow, Block rightRow)
{
int compareResult = compare(rowType, lessThanFunctions, leftRow, rightRow);
return compareResult > 0;
}
}
@@ -0,0 +1,61 @@
package com.facebook.presto.operator.scalar;
/*
* Licensed 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.
*/

import com.facebook.presto.metadata.BoundVariables;
import com.facebook.presto.metadata.FunctionRegistry;
import com.facebook.presto.spi.block.Block;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.type.RowType;
import com.google.common.collect.ImmutableList;

import java.lang.invoke.MethodHandle;
import java.util.List;

import static com.facebook.presto.spi.function.OperatorType.GREATER_THAN;
import static com.facebook.presto.spi.function.OperatorType.GREATER_THAN_OR_EQUAL;
import static com.facebook.presto.util.Reflection.methodHandle;

public final class RowGreaterThanOrEqualOperator
extends RowComparisonOperator
{
public static final RowGreaterThanOrEqualOperator ROW_GREATER_THAN_OR_EQUAL = new RowGreaterThanOrEqualOperator();
private static final MethodHandle METHOD_HANDLE = methodHandle(RowGreaterThanOrEqualOperator.class, "greaterOrEqual", RowType.class, List.class, Block.class, Block.class);

private RowGreaterThanOrEqualOperator()
{
super(GREATER_THAN_OR_EQUAL);
}

@Override
public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry)
{
Type type = boundVariables.getTypeVariable("T");
return new ScalarFunctionImplementation(
false,
ImmutableList.of(false, false),
METHOD_HANDLE.bindTo(type).bindTo(getMethodHandles((RowType) type, functionRegistry, GREATER_THAN)),
isDeterministic());
}

public static boolean greaterOrEqual(
RowType rowType,
List<MethodHandle> lessThanFunctions,
Block leftRow, Block rightRow)
{
int compareResult = compare(rowType, lessThanFunctions, leftRow, rightRow);
return compareResult >= 0;
}
}
@@ -0,0 +1,60 @@
package com.facebook.presto.operator.scalar;
/*
* Licensed 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.
*/

import com.facebook.presto.metadata.BoundVariables;
import com.facebook.presto.metadata.FunctionRegistry;
import com.facebook.presto.spi.block.Block;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.type.RowType;
import com.google.common.collect.ImmutableList;

import java.lang.invoke.MethodHandle;
import java.util.List;

import static com.facebook.presto.spi.function.OperatorType.LESS_THAN;
import static com.facebook.presto.util.Reflection.methodHandle;

public final class RowLessThanOperator
extends RowComparisonOperator
{
public static final RowLessThanOperator ROW_LESS_THAN = new RowLessThanOperator();
private static final MethodHandle METHOD_HANDLE = methodHandle(RowLessThanOperator.class, "less", RowType.class, List.class, Block.class, Block.class);

private RowLessThanOperator()
{
super(LESS_THAN);
}

@Override
public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry)
{
Type type = boundVariables.getTypeVariable("T");
return new ScalarFunctionImplementation(
false,
ImmutableList.of(false, false),
METHOD_HANDLE.bindTo(type).bindTo(getMethodHandles((RowType) type, functionRegistry, LESS_THAN)),
isDeterministic());
}

public static boolean less(
RowType rowType,
List<MethodHandle> lessThanFunctions,
Block leftRow, Block rightRow)
{
int compareResult = compare(rowType, lessThanFunctions, leftRow, rightRow);
return compareResult > 0;
}
}
@@ -0,0 +1,61 @@
package com.facebook.presto.operator.scalar;
/*
* Licensed 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.
*/

import com.facebook.presto.metadata.BoundVariables;
import com.facebook.presto.metadata.FunctionRegistry;
import com.facebook.presto.spi.block.Block;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.type.RowType;
import com.google.common.collect.ImmutableList;

import java.lang.invoke.MethodHandle;
import java.util.List;

import static com.facebook.presto.spi.function.OperatorType.LESS_THAN;
import static com.facebook.presto.spi.function.OperatorType.LESS_THAN_OR_EQUAL;
import static com.facebook.presto.util.Reflection.methodHandle;

public final class RowLessThanOrEqualOperator
extends RowComparisonOperator
{
public static final RowLessThanOrEqualOperator ROW_LESS_THAN_OR_EQUAL = new RowLessThanOrEqualOperator();
private static final MethodHandle METHOD_HANDLE = methodHandle(RowLessThanOrEqualOperator.class, "lessOrEqual", RowType.class, List.class, Block.class, Block.class);

private RowLessThanOrEqualOperator()
{
super(LESS_THAN_OR_EQUAL);
}

@Override
public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry)
{
Type type = boundVariables.getTypeVariable("T");
return new ScalarFunctionImplementation(
false,
ImmutableList.of(false, false),
METHOD_HANDLE.bindTo(type).bindTo(getMethodHandles((RowType) type, functionRegistry, LESS_THAN)),
isDeterministic());
}

public static boolean lessOrEqual(
RowType rowType,
List<MethodHandle> lessThanFunctions,
Block leftRow, Block rightRow)
{
int compareResult = compare(rowType, lessThanFunctions, leftRow, rightRow);
return compareResult >= 0;
}
}

0 comments on commit 56ecfd1

Please sign in to comment.