Skip to content

Commit 491f897

Browse files
pramodsatyamohsakasoumiiow
authored
test: Add custom function tests (#25480)
## Description Adds e2e tests for Presto C++ custom functions. Testcases borrowed from [AbstractTestQueries](https://github.com/prestodb/presto/blob/master/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java) in `presto-tests`. ``` == NO RELEASE NOTE == ``` Co-authored-by: mohsaka <[email protected]> Co-authored-by: soumiiow <[email protected]>
1 parent 2c63235 commit 491f897

File tree

10 files changed

+517
-2
lines changed

10 files changed

+517
-2
lines changed

.github/workflows/prestocpp-linux-build-and-unit-test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ jobs:
7979
github.event_name == 'schedule' || needs.changes.outputs.codechange == 'true'
8080
run: |
8181
source /opt/rh/gcc-toolset-12/enable
82+
cp -r presto-native-tests/presto_cpp/tests presto-native-execution/presto_cpp/main/functions/dynamic_registry
83+
echo "add_subdirectory(tests)" >> presto-native-execution/presto_cpp/main/functions/dynamic_registry/CMakeLists.txt
8284
cd presto-native-execution
8385
cmake \
8486
-B _build/release \
@@ -126,6 +128,7 @@ jobs:
126128
path: |
127129
presto-native-execution/_build/release/presto_cpp/main/presto_server
128130
presto-native-execution/_build/release/velox/velox/functions/remote/server/velox_functions_remote_server_main
131+
presto-native-execution/_build/release/presto_cpp/main/functions/dynamic_registry/tests/
129132
130133
prestocpp-linux-presto-e2e-tests:
131134
needs: [changes, prestocpp-linux-build-for-test]

presto-native-execution/src/test/java/com/facebook/presto/nativeworker/PrestoNativeQueryRunnerUtils.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ public static class HiveQueryRunnerBuilder
120120
private Map<String, String> extraCoordinatorProperties = new HashMap<>();
121121
private Map<String, String> hiveProperties = new HashMap<>();
122122
private Map<String, String> tpcdsProperties = new HashMap<>();
123+
private Optional<String> pluginDirectory = Optional.empty();
123124
private String security;
124125
private boolean addStorageFormatToPath;
125126
private boolean coordinatorSidecarEnabled;
@@ -171,6 +172,12 @@ public HiveQueryRunnerBuilder setRemoteFunctionServerUds(Optional<String> remote
171172
return this;
172173
}
173174

175+
public HiveQueryRunnerBuilder setPluginDirectory(Optional<String> pluginDirectory)
176+
{
177+
this.pluginDirectory = pluginDirectory;
178+
return this;
179+
}
180+
174181
public HiveQueryRunnerBuilder setFailOnNestedLoopJoin(boolean failOnNestedLoopJoin)
175182
{
176183
this.failOnNestedLoopJoin = failOnNestedLoopJoin;
@@ -281,7 +288,7 @@ public QueryRunner build()
281288
Optional<BiFunction<Integer, URI, Process>> externalWorkerLauncher = Optional.empty();
282289
if (this.useExternalWorkerLauncher) {
283290
externalWorkerLauncher = getExternalWorkerLauncher("hive", serverBinary, cacheMaxSize, remoteFunctionServerUds,
284-
failOnNestedLoopJoin, coordinatorSidecarEnabled, builtInWorkerFunctionsEnabled, enableRuntimeMetricsCollection, enableSsdCache, implicitCastCharNToVarchar);
291+
pluginDirectory, failOnNestedLoopJoin, coordinatorSidecarEnabled, builtInWorkerFunctionsEnabled, enableRuntimeMetricsCollection, enableSsdCache, implicitCastCharNToVarchar);
285292
}
286293
return HiveQueryRunner.createQueryRunner(
287294
ImmutableList.of(),
@@ -370,7 +377,7 @@ public QueryRunner build()
370377
Optional<BiFunction<Integer, URI, Process>> externalWorkerLauncher = Optional.empty();
371378
if (this.useExternalWorkerLauncher) {
372379
externalWorkerLauncher = getExternalWorkerLauncher("iceberg", serverBinary, cacheMaxSize, remoteFunctionServerUds,
373-
false, false, false, false, false, false);
380+
Optional.empty(), false, false, false, false, false, false);
374381
}
375382
return IcebergQueryRunner.builder()
376383
.setExtraProperties(extraProperties)
@@ -464,6 +471,7 @@ public static Optional<BiFunction<Integer, URI, Process>> getExternalWorkerLaunc
464471
String prestoServerPath,
465472
int cacheMaxSize,
466473
Optional<String> remoteFunctionServerUds,
474+
Optional<String> pluginDirectory,
467475
Boolean failOnNestedLoopJoin,
468476
boolean isCoordinatorSidecarEnabled,
469477
boolean isBuiltInWorkerFunctionsEnabled,
@@ -517,6 +525,10 @@ else if (isBuiltInWorkerFunctionsEnabled) {
517525
"remote-function-server.signature.files.directory.path=%s%n", configProperties, REMOTE_FUNCTION_CATALOG_NAME, remoteFunctionServerUds.get(), jsonSignaturesPath);
518526
}
519527

528+
if (pluginDirectory.isPresent()) {
529+
configProperties = format("%s%n" + "plugin.dir=%s%n", configProperties, pluginDirectory.get());
530+
}
531+
520532
if (failOnNestedLoopJoin) {
521533
configProperties = format("%s%n" + "velox-plan-validator-fail-on-nested-loop-join=true%n", configProperties);
522534
}

presto-native-tests/CMakeLists.txt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
cmake_minimum_required(VERSION 3.10)
13+
14+
# set the project name
15+
project(PrestoCpp)
16+
17+
set(CMAKE_CXX_STANDARD 17)
18+
set(CMAKE_CXX_STANDARD_REQUIRED True)
19+
message("Appending CMAKE_CXX_FLAGS with ${SCRIPT_CXX_FLAGS}")
20+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SCRIPT_CXX_FLAGS}")
21+
22+
# Known warnings that are benign can be disabled.
23+
set(DISABLED_WARNINGS
24+
"-Wno-nullability-completeness -Wno-deprecated-declarations")
25+
26+
# Important warnings that must be explicitly enabled.
27+
set(ENABLE_WARNINGS "-Wreorder")
28+
29+
set(CMAKE_CXX_FLAGS
30+
"${CMAKE_CXX_FLAGS} ${DISABLED_WARNINGS} ${ENABLE_WARNINGS}")
31+
32+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
33+
34+
if(DEFINED ENV{INSTALL_PREFIX})
35+
message(STATUS "Dependency install directory set to: $ENV{INSTALL_PREFIX}")
36+
list(APPEND CMAKE_PREFIX_PATH "$ENV{INSTALL_PREFIX}")
37+
endif()
38+
39+
find_package(gflags REQUIRED)
40+
41+
find_library(GLOG glog)
42+
43+
find_package(fmt REQUIRED)
44+
45+
if(NOT TARGET gflags::gflags)
46+
# This is a bit convoluted, but we want to be able to use gflags::gflags as a
47+
# target even when velox is built as a subproject which uses
48+
# `find_package(gflags)` which does not create a globally imported target that
49+
# we can ALIAS.
50+
add_library(gflags_gflags INTERFACE)
51+
target_link_libraries(gflags_gflags INTERFACE gflags)
52+
add_library(gflags::gflags ALIAS gflags_gflags)
53+
endif()
54+
include_directories(.)
55+
56+
include_directories(${CMAKE_BINARY_DIR})
57+
58+
# Adding this down here prevents warnings in dependencies from stopping the
59+
# build.
60+
if("${TREAT_WARNINGS_AS_ERRORS}")
61+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
62+
endif()
63+
64+
if(DEFINED ENV{INSTALL_PREFIX})
65+
# Allow installed package headers to be picked up before brew/system package
66+
# headers. We set this after Velox since Velox handles INSTALL_PREFIX its own
67+
# way.
68+
include_directories(BEFORE "$ENV{INSTALL_PREFIX}/include")
69+
endif()
70+
71+
add_subdirectory(presto_cpp)

presto-native-tests/Makefile

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
.PHONY: build clean debug release submodules
13+
14+
BUILD_BASE_DIR=_build
15+
BUILD_DIR=release
16+
BUILD_TYPE=Release
17+
TREAT_WARNINGS_AS_ERRORS ?= 1
18+
ENABLE_WALL ?= 1
19+
NUM_THREADS ?= $(shell getconf _NPROCESSORS_CONF 2>/dev/null || echo 1)
20+
CMAKE_PREFIX_PATH ?= "/usr/local"
21+
22+
EXTRA_CMAKE_FLAGS ?= ""
23+
24+
CMAKE_FLAGS := -DTREAT_WARNINGS_AS_ERRORS=${TREAT_WARNINGS_AS_ERRORS}
25+
CMAKE_FLAGS += -DENABLE_ALL_WARNINGS=${ENABLE_WALL}
26+
CMAKE_FLAGS += -DCMAKE_PREFIX_PATH=$(CMAKE_PREFIX_PATH)
27+
CMAKE_FLAGS += -DCMAKE_BUILD_TYPE=$(BUILD_TYPE)
28+
29+
SHELL := /bin/bash
30+
31+
# Use Ninja if available. If Ninja is used, pass through parallelism control flags.
32+
USE_NINJA ?= 1
33+
ifeq ($(USE_NINJA), 1)
34+
ifneq ($(shell which ninja), )
35+
CMAKE_FLAGS += -GNinja -DMAX_LINK_JOBS=$(MAX_LINK_JOBS) -DMAX_HIGH_MEM_JOBS=$(MAX_HIGH_MEM_JOBS)
36+
endif
37+
endif
38+
39+
ifndef USE_CCACHE
40+
ifneq ($(shell which ccache), )
41+
CMAKE_FLAGS += -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
42+
endif
43+
endif
44+
45+
all: release #: Build the release version
46+
47+
clean: #: Delete all build artifacts
48+
rm -rf $(BUILD_BASE_DIR)
49+
50+
cmake: submodules #: Use CMake to create a Makefile build system
51+
cmake -B "$(BUILD_BASE_DIR)/$(BUILD_DIR)" $(FORCE_COLOR) $(CMAKE_FLAGS) $(EXTRA_CMAKE_FLAGS)
52+
53+
build: #: Build the software based in BUILD_DIR and BUILD_TYPE variables
54+
cmake --build $(BUILD_BASE_DIR)/$(BUILD_DIR) -j $(NUM_THREADS)
55+
56+
debug: #: Build with debugging symbols
57+
$(MAKE) cmake BUILD_DIR=debug BUILD_TYPE=Debug
58+
$(MAKE) build BUILD_DIR=debug
59+
60+
release: #: Build the release version
61+
$(MAKE) cmake BUILD_DIR=release BUILD_TYPE=Release && \
62+
$(MAKE) build BUILD_DIR=release
63+
64+
help: #: Show the help messages
65+
@cat $(firstword $(MAKEFILE_LIST)) | \
66+
awk '/^[-a-z]+:/' | \
67+
awk -F: '{ printf("%-20s %s\n", $$1, $$NF) }'
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
add_subdirectory(tests)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
add_subdirectory(custom_functions)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
set(PRESTO_AND_VELOX_INCLUDE_DIRS
13+
${CMAKE_SOURCE_DIR}/../presto-native-execution
14+
${CMAKE_SOURCE_DIR}/../presto-native-execution/velox
15+
)
16+
17+
add_library(presto_cpp_custom_functions_test SHARED CustomFunctions.cpp)
18+
19+
set(CMAKE_DYLIB_TEST_LINK_LIBRARIES fmt::fmt
20+
xsimd)
21+
22+
target_include_directories(presto_cpp_custom_functions_test
23+
PRIVATE
24+
${PRESTO_AND_VELOX_INCLUDE_DIRS}
25+
presto_dynamic_function_registrar
26+
)
27+
28+
target_link_libraries(presto_cpp_custom_functions_test
29+
PRIVATE
30+
${CMAKE_DYLIB_TEST_LINK_LIBRARIES})
31+
32+
if(APPLE)
33+
set(COMMON_LIBRARY_LINK_OPTIONS "-Wl,-undefined,dynamic_lookup")
34+
else()
35+
set(COMMON_LIBRARY_LINK_OPTIONS "-Wl,--exclude-libs,ALL")
36+
endif()
37+
38+
target_link_options(presto_cpp_custom_functions_test PRIVATE
39+
${COMMON_LIBRARY_LINK_OPTIONS})
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
#include <iostream>
16+
#include "presto_cpp/main/functions/dynamic_registry/DynamicFunctionRegistrar.h"
17+
#include "velox/expression/SimpleFunctionRegistry.h"
18+
// This file defines a function that will be dynamically linked and
19+
// registered. This function implements a custom function in the definition,
20+
// and this library (.so) needs to provide a `void registerExtensions()`
21+
// C function in the top-level namespace.
22+
//
23+
// (note the extern "C" directive to prevent the compiler from mangling the
24+
// symbol name).
25+
26+
namespace custom::functionRegistry {
27+
template <typename T>
28+
struct CustomAdd {
29+
VELOX_DEFINE_FUNCTION_TYPES(T);
30+
FOLLY_ALWAYS_INLINE bool call(
31+
out_type<int64_t>& result,
32+
const arg_type<int64_t>& x1,
33+
const arg_type<int64_t>& x2) {
34+
result = x1 + x2;
35+
return true;
36+
}
37+
};
38+
39+
template <typename T>
40+
struct SumArray {
41+
VELOX_DEFINE_FUNCTION_TYPES(T);
42+
FOLLY_ALWAYS_INLINE bool call(
43+
out_type<int64_t>& result,
44+
const arg_type<facebook::velox::Array<int64_t>>& arr) {
45+
int64_t sum = 0;
46+
for (auto val : arr) {
47+
if (val.has_value()) {
48+
sum += val.value();
49+
}
50+
}
51+
result = sum;
52+
return true;
53+
}
54+
};
55+
56+
template <typename T>
57+
struct MapSize {
58+
VELOX_DEFINE_FUNCTION_TYPES(T);
59+
FOLLY_ALWAYS_INLINE bool call(
60+
out_type<int64_t>& result,
61+
const arg_type<facebook::velox::Map<int64_t, int64_t>>& m) {
62+
result = m.size();
63+
return true;
64+
}
65+
};
66+
67+
template <typename T>
68+
struct SumNestedArrayElements {
69+
VELOX_DEFINE_FUNCTION_TYPES(T);
70+
FOLLY_ALWAYS_INLINE bool call(
71+
out_type<int64_t>& result,
72+
const arg_type<facebook::velox::Array<facebook::velox::Array<int64_t>>>& arr) {
73+
int64_t sum = 0;
74+
for (auto innerOpt : arr) {
75+
if (innerOpt.has_value()) {
76+
for (auto val : innerOpt.value()) {
77+
if (val.has_value()) {
78+
sum += val.value();
79+
}
80+
}
81+
}
82+
}
83+
result = sum;
84+
return true;
85+
}
86+
};
87+
} // namespace custom::functionRegistry
88+
89+
extern "C" {
90+
void registerExtensions() {
91+
facebook::presto::registerPrestoFunction<
92+
custom::functionRegistry::CustomAdd,
93+
int64_t,
94+
int64_t,
95+
int64_t>("dynamic_custom_add");
96+
97+
facebook::presto::registerPrestoFunction<
98+
custom::functionRegistry::SumArray,
99+
int64_t,
100+
facebook::velox::Array<int64_t>>("sum_array");
101+
102+
facebook::presto::registerPrestoFunction<
103+
custom::functionRegistry::MapSize,
104+
int64_t,
105+
facebook::velox::Map<int64_t, int64_t>>("map_size");
106+
107+
facebook::presto::registerPrestoFunction<
108+
custom::functionRegistry::SumNestedArrayElements,
109+
int64_t,
110+
facebook::velox::Array<facebook::velox::Array<int64_t>>>("sum_nested_array_elements");
111+
}
112+
}

0 commit comments

Comments
 (0)