/* * 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. */ package com.facebook.presto.operator.scalar; import com.facebook.presto.spi.PrestoException; import com.facebook.presto.spi.block.Block; import com.facebook.presto.spi.block.BlockBuilder; import com.facebook.presto.spi.block.BlockBuilderStatus; import com.facebook.presto.spi.function.Description; import com.facebook.presto.spi.function.OperatorDependency; import com.facebook.presto.spi.function.ScalarFunction; import com.facebook.presto.spi.function.SqlType; import com.facebook.presto.spi.function.TypeParameter; import com.facebook.presto.spi.type.StandardTypes; import com.facebook.presto.spi.type.Type; import com.google.common.base.Throwables; import java.lang.invoke.MethodHandle; import java.util.ArrayList; import java.util.List; import static com.facebook.presto.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR; import static com.facebook.presto.spi.function.OperatorType.EQUAL; import static com.facebook.presto.spi.type.TypeUtils.readNativeValue; @ScalarFunction("array_remove") @Description("Remove specified values from the given array") public final class ArrayRemoveFunction { private ArrayRemoveFunction() {} @TypeParameter("E") @SqlType("array(E)") public static Block remove( @OperatorDependency(operator = EQUAL, returnType = StandardTypes.BOOLEAN, argumentTypes = {"E", "E"}) MethodHandle equalsFunction, @TypeParameter("E") Type type, @SqlType("array(E)") Block array, @SqlType("E") long value) { return remove(equalsFunction, type, array, (Object) value); } @TypeParameter("E") @SqlType("array(E)") public static Block remove( @OperatorDependency(operator = EQUAL, returnType = StandardTypes.BOOLEAN, argumentTypes = {"E", "E"}) MethodHandle equalsFunction, @TypeParameter("E") Type type, @SqlType("array(E)") Block array, @SqlType("E") double value) { return remove(equalsFunction, type, array, (Object) value); } @TypeParameter("E") @SqlType("array(E)") public static Block remove( @OperatorDependency(operator = EQUAL, returnType = StandardTypes.BOOLEAN, argumentTypes = {"E", "E"}) MethodHandle equalsFunction, @TypeParameter("E") Type type, @SqlType("array(E)") Block array, @SqlType("E") boolean value) { return remove(equalsFunction, type, array, (Object) value); } @TypeParameter("E") @SqlType("array(E)") public static Block remove( @OperatorDependency(operator = EQUAL, returnType = StandardTypes.BOOLEAN, argumentTypes = {"E", "E"}) MethodHandle equalsFunction, @TypeParameter("E") Type type, @SqlType("array(E)") Block array, @SqlType("E") Object value) { int sizeAfterRemove = 0; List<Integer> positions = new ArrayList<>(); for (int i = 0; i < array.getPositionCount(); i++) { Object element = readNativeValue(type, array, i); try { if (element == null || !(boolean) equalsFunction.invoke(element, value)) { positions.add(i); sizeAfterRemove += array.getRegionSizeInBytes(i, 1); } } catch (Throwable t) { Throwables.propagateIfInstanceOf(t, Error.class); Throwables.propagateIfInstanceOf(t, PrestoException.class); throw new PrestoException(GENERIC_INTERNAL_ERROR, t); } } if (array.getPositionCount() == positions.size()) { return array; } int entrySize = 0; if (!positions.isEmpty()) { entrySize = (int) Math.ceil(sizeAfterRemove / (double) positions.size()); } BlockBuilder blockBuilder = type.createBlockBuilder(new BlockBuilderStatus(), positions.size(), entrySize); for (int position : positions) { type.appendTo(array, position, blockBuilder); } return blockBuilder.build(); } }