Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions presto-docs/src/main/sphinx/functions/array.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ The ``||`` operator is used to concatenate an array with an array or an element
Array Functions
---------------

.. function:: all_match(array(T), function(T,boolean)) -> boolean
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after T, before boolean => T, boolean


Returns whether all elements of an array match the given predicate. Returns ``true`` if all the elements
match the predicate (a special case is when the array is empty); ``false`` if one or more elements don't
match; ``NULL`` if the predicate function returns ``NULL`` for one or more elements and ``true`` for all
other elements.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about empty array? Every predicate would return true? Is that worth documenting?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rongrong : It's already discussed:

(a special case is when the array is empty)


.. function:: any_match(array(T), function(T,boolean)) -> boolean
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above


Returns whether any elements of an array match the given predicate. Returns ``true`` if one or more
elements match the predicate; ``false`` if none of the elements matches (a special case is when the
array is empty); ``NULL`` if the predicate function returns ``NULL`` for one or more elements and ``false``
for all other elements.

.. function:: array_distinct(x) -> array

Remove duplicate values from the array ``x``.
Expand Down Expand Up @@ -139,6 +153,12 @@ Array Functions
SELECT ngrams(ARRAY['foo', 'bar', 'baz', 'foo'], 5); -- [['foo', 'bar', 'baz', 'foo']]
SELECT ngrams(ARRAY[1, 2, 3, 4], 2); -- [[1, 2], [2, 3], [3, 4]]

.. function:: none_match(array(T), function(T,boolean)) -> boolean
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seem that the functions are actually listed in alphabetical order so it probably makes more sense to keep these three functions together.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rongrong : Looks to me the functions are listed in alphabetical order? Maybe some functions are not following the ordering strictly (although I didn't see it with skim 😄 ) and we should fix them?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's the array_intersect/union/except that's wrong then. Can you add a follow up PR to fix that? Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also add space here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rongrong

Maybe it's the array_intersect/union/except that's wrong then. Can you add a follow up PR to fix that? Thanks!

Yup: #13736 😃


Returns whether no elements of an array match the given predicate. Returns ``true`` if none of the elements
matches the predicate (a special case is when the array is empty); ``false`` if one or more elements match;
``NULL`` if the predicate function returns ``NULL`` for one or more elements and ``false`` for all other elements.

.. function:: reduce(array(T), initialState S, inputFunction(S,T,S), outputFunction(S,R)) -> R

Returns a single value reduced from ``array``. ``inputFunction`` will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
import com.facebook.presto.operator.aggregation.differentialentropy.DifferentialEntropyAggregation;
import com.facebook.presto.operator.aggregation.histogram.Histogram;
import com.facebook.presto.operator.aggregation.multimapagg.MultimapAggregationFunction;
import com.facebook.presto.operator.scalar.ArrayAllMatchFunction;
import com.facebook.presto.operator.scalar.ArrayAnyMatchFunction;
import com.facebook.presto.operator.scalar.ArrayCardinalityFunction;
import com.facebook.presto.operator.scalar.ArrayContains;
import com.facebook.presto.operator.scalar.ArrayDistinctFromOperator;
Expand All @@ -82,6 +84,7 @@
import com.facebook.presto.operator.scalar.ArrayMaxFunction;
import com.facebook.presto.operator.scalar.ArrayMinFunction;
import com.facebook.presto.operator.scalar.ArrayNgramsFunction;
import com.facebook.presto.operator.scalar.ArrayNoneMatchFunction;
import com.facebook.presto.operator.scalar.ArrayNotEqualOperator;
import com.facebook.presto.operator.scalar.ArrayPositionFunction;
import com.facebook.presto.operator.scalar.ArrayRemoveFunction;
Expand Down Expand Up @@ -585,6 +588,9 @@ public BuiltInFunctionNamespaceManager(
.scalar(ArraySliceFunction.class)
.scalar(ArrayIndeterminateOperator.class)
.scalar(ArrayNgramsFunction.class)
.scalar(ArrayAllMatchFunction.class)
.scalar(ArrayAnyMatchFunction.class)
.scalar(ArrayNoneMatchFunction.class)
.scalar(MapDistinctFromOperator.class)
.scalar(MapEqualOperator.class)
.scalar(MapEntriesFunction.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* 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.block.Block;
import com.facebook.presto.spi.function.Description;
import com.facebook.presto.spi.function.ScalarFunction;
import com.facebook.presto.spi.function.SqlNullable;
import com.facebook.presto.spi.function.SqlType;
import com.facebook.presto.spi.function.TypeParameter;
import com.facebook.presto.spi.function.TypeParameterSpecialization;
import com.facebook.presto.spi.type.StandardTypes;
import com.facebook.presto.spi.type.Type;
import io.airlift.slice.Slice;

import static java.lang.Boolean.FALSE;

@Description("Returns true if all elements of the array match the given predicate")
@ScalarFunction(value = "all_match")
public final class ArrayAllMatchFunction
{
private ArrayAllMatchFunction() {}

@TypeParameter("T")
@TypeParameterSpecialization(name = "T", nativeContainerType = Block.class)
@SqlType(StandardTypes.BOOLEAN)
@SqlNullable
public static Boolean allMatchBlock(
@TypeParameter("T") Type elementType,
@SqlType("array(T)") Block arrayBlock,
@SqlType("function(T, boolean)") BlockToBooleanFunction function)
{
boolean hasNullResult = false;
for (int i = 0; i < arrayBlock.getPositionCount(); i++) {
Block element = null;
if (!arrayBlock.isNull(i)) {
element = (Block) elementType.getObject(arrayBlock, i);
}
Boolean match = function.apply(element);
if (FALSE.equals(match)) {
return false;
}
if (match == null) {
hasNullResult = true;
}
}
if (hasNullResult) {
return null;
}
return true;
}

@TypeParameter("T")
@TypeParameterSpecialization(name = "T", nativeContainerType = Slice.class)
@SqlType(StandardTypes.BOOLEAN)
@SqlNullable
public static Boolean allMatchSlice(
@TypeParameter("T") Type elementType,
@SqlType("array(T)") Block arrayBlock,
@SqlType("function(T, boolean)") SliceToBooleanFunction function)
{
boolean hasNullResult = false;
int positionCount = arrayBlock.getPositionCount();
for (int i = 0; i < positionCount; i++) {
Slice element = null;
if (!arrayBlock.isNull(i)) {
element = elementType.getSlice(arrayBlock, i);
}
Boolean match = function.apply(element);
if (FALSE.equals(match)) {
return false;
}
if (match == null) {
hasNullResult = true;
}
}
if (hasNullResult) {
return null;
}
return true;
}

@TypeParameter("T")
@TypeParameterSpecialization(name = "T", nativeContainerType = long.class)
@SqlType(StandardTypes.BOOLEAN)
@SqlNullable
public static Boolean allMatchLong(
@TypeParameter("T") Type elementType,
@SqlType("array(T)") Block arrayBlock,
@SqlType("function(T, boolean)") LongToBooleanFunction function)
{
boolean hasNullResult = false;
int positionCount = arrayBlock.getPositionCount();
for (int i = 0; i < positionCount; i++) {
Long element = null;
if (!arrayBlock.isNull(i)) {
element = elementType.getLong(arrayBlock, i);
}
Boolean match = function.apply(element);
if (FALSE.equals(match)) {
return false;
}
if (match == null) {
hasNullResult = true;
}
}
if (hasNullResult) {
return null;
}
return true;
}

@TypeParameter("T")
@TypeParameterSpecialization(name = "T", nativeContainerType = double.class)
@SqlType(StandardTypes.BOOLEAN)
@SqlNullable
public static Boolean allMatchDouble(
@TypeParameter("T") Type elementType,
@SqlType("array(T)") Block arrayBlock,
@SqlType("function(T, boolean)") DoubleToBooleanFunction function)
{
boolean hasNullResult = false;
int positionCount = arrayBlock.getPositionCount();
for (int i = 0; i < positionCount; i++) {
Double element = null;
if (!arrayBlock.isNull(i)) {
element = elementType.getDouble(arrayBlock, i);
}
Boolean match = function.apply(element);
if (FALSE.equals(match)) {
return false;
}
if (match == null) {
hasNullResult = true;
}
}
if (hasNullResult) {
return null;
}
return true;
}

@TypeParameter("T")
@TypeParameterSpecialization(name = "T", nativeContainerType = boolean.class)
@SqlType(StandardTypes.BOOLEAN)
@SqlNullable
public static Boolean allMatchBoolean(
@TypeParameter("T") Type elementType,
@SqlType("array(T)") Block arrayBlock,
@SqlType("function(T, boolean)") BooleanToBooleanFunction function)
{
boolean hasNullResult = false;
int positionCount = arrayBlock.getPositionCount();
for (int i = 0; i < positionCount; i++) {
Boolean element = null;
if (!arrayBlock.isNull(i)) {
element = elementType.getBoolean(arrayBlock, i);
}
Boolean match = function.apply(element);
if (FALSE.equals(match)) {
return false;
}
if (match == null) {
hasNullResult = true;
}
}
if (hasNullResult) {
return null;
}
return true;
}
}
Loading