diff --git a/.github/workflows/MainDistributionPipeline.yml b/.github/workflows/MainDistributionPipeline.yml index e424756b..1da69c6c 100644 --- a/.github/workflows/MainDistributionPipeline.yml +++ b/.github/workflows/MainDistributionPipeline.yml @@ -24,17 +24,20 @@ concurrency: jobs: duckdb-latest-build: name: Build extension binaries - uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@v1.1.0 + uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@main with: duckdb_version: main extension_name: spatial + ci_tools_version: main + vcpkg_commit: 5e5d0e1cd7785623065e77eff011afdeec1a3574 duckdb-latest-deploy: name: Deploy extension binaries needs: duckdb-latest-build - uses: duckdb/extension-ci-tools/.github/workflows/_extension_deploy.yml@v1.1.0 + uses: duckdb/extension-ci-tools/.github/workflows/_extension_deploy.yml@main secrets: inherit with: duckdb_version: main + ci_tools_version: main extension_name: spatial deploy_latest: ${{ startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' }} diff --git a/.github/workflows/StableDistributionPipeline.yml b/.github/workflows/StableDistributionPipeline.yml index a6908a70..3923ad42 100644 --- a/.github/workflows/StableDistributionPipeline.yml +++ b/.github/workflows/StableDistributionPipeline.yml @@ -5,13 +5,13 @@ name: Stable Extension Distribution Pipeline on: pull_request: branches: - - v1.1.0 + - v1.1.3 paths-ignore: - '**/README.md' - 'doc/**' push: branches: - - v1.1.0 + - v1.1.3 paths-ignore: - '**/README.md' - 'doc/**' @@ -24,17 +24,21 @@ concurrency: jobs: duckdb-stable-build: name: Build extension binaries - uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@v1.1.0 + uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@v1.1.3 with: - duckdb_version: v1.1.0 + duckdb_version: v1.1.3 extension_name: spatial + ci_tools_version: v1.1.3 + vcpkg_commit: 5e5d0e1cd7785623065e77eff011afdeec1a3574 + duckdb-stable-deploy: name: Deploy extension binaries needs: duckdb-stable-build - uses: duckdb/extension-ci-tools/.github/workflows/_extension_deploy.yml@v1.1.0 + uses: duckdb/extension-ci-tools/.github/workflows/_extension_deploy.yml@v1.1.3 secrets: inherit with: - duckdb_version: v1.1.0 + duckdb_version: v1.1.3 + ci_tools_version: v1.1.3 extension_name: spatial - deploy_latest: ${{ startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/v1.1.0' }} + deploy_latest: ${{ startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/v1.1.3' }} diff --git a/.gitmodules b/.gitmodules index 7114de7a..45589912 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "duckdb"] path = duckdb url = https://github.com/duckdb/duckdb.git +[submodule "extension-ci-tools"] + path = extension-ci-tools + url = https://github.com/duckdb/extension-ci-tools.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 95792382..2f3fa491 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,9 @@ add_definitions(-DDUCKDB_PATCH_VERSION=${DUCKDB_PATCH_VERSION}) # Enable network functionality (OpenSSL and GDAL's CURL based fs/drivers) option(SPATIAL_USE_NETWORK "Enable network functionality" ON) -if (EMSCRIPTEN OR IOS OR ANDROID) +if(EMSCRIPTEN + OR IOS + OR ANDROID) set(SPATIAL_USE_NETWORK OFF) endif() @@ -32,7 +34,6 @@ include_directories(spatial/third_party/protozero/include) include_directories(spatial/third_party/shapelib) add_subdirectory(spatial/third_party/shapelib) - add_library(${EXTENSION_NAME} STATIC ${EXTENSION_SOURCES}) # Build dependencies TODO: in the future we should allow users to dynamically @@ -44,10 +45,8 @@ if(NOT EXISTS ${CMAKE_BINARY_DIR}/deps) execute_process( # Generate project COMMAND - ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR} - -DDUCKDB_ENABLE_DEPRECATED_API=1 - -DWASM_LOADABLE_EXTENSIONS=1 - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR} -DDUCKDB_ENABLE_DEPRECATED_API=1 + -DWASM_LOADABLE_EXTENSIONS=1 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DOSX_BUILD_ARCH=${OSX_BUILD_ARCH} -DSPATIAL_USE_NETWORK=${SPATIAL_USE_NETWORK} -DOPENSSL_ROOT_DIR=$ENV{OPENSSL_ROOT_DIR} @@ -55,7 +54,8 @@ if(NOT EXISTS ${CMAKE_BINARY_DIR}/deps) -DVCPKG_INSTALLED_DIR='${CMAKE_BINARY_DIR}/vcpkg_installed' -DCMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}' -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' - -S ${CMAKE_CURRENT_SOURCE_DIR}/deps -B ${CMAKE_BINARY_DIR}/deps + -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE='${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}' -S + ${CMAKE_CURRENT_SOURCE_DIR}/deps -B ${CMAKE_BINARY_DIR}/deps RESULT_VARIABLE DEPENDENCIES_GENERATE_RESULT) if(NOT DEPENDENCIES_GENERATE_RESULT EQUAL 0) message(FATAL_ERROR "Could not generate dependencies project") @@ -82,7 +82,7 @@ message(STATUS "Find libraries path: '${CMAKE_PREFIX_PATH}'") set(ZLIB_USE_STATIC_LIBS ON) set(OPENSSL_USE_STATIC_LIBS ON) -if (EMSCRIPTEN) +if(EMSCRIPTEN) set(OPENSSL_USE_STATIC_LIBS OFF) endif() @@ -96,16 +96,15 @@ find_package(EXPAT REQUIRED) find_package(GeographicLib REQUIRED) # Important: The link order matters, its the reverse order of dependency -set(EXTENSION_DEPENDENCIES - GDAL::GDAL - GEOS::geos_c - PROJ::proj - EXPAT::EXPAT - SQLite::SQLite3 - ZLIB::ZLIB - ${SQLITE3_MEMVFS} - ${GeographicLib_LIBRARIES} -) +set(EXTENSION_DEPENDENCIES + GDAL::GDAL + GEOS::geos_c + PROJ::proj + EXPAT::EXPAT + SQLite::SQLite3 + ZLIB::ZLIB + ${SQLITE3_MEMVFS} + ${GeographicLib_LIBRARIES}) if(SPATIAL_USE_NETWORK) message(STATUS "Building with network functionality") @@ -124,7 +123,7 @@ if((NOT EMSCRIPTEN) AND (NOT IOS)) find_library(CoreFoundation_Library CoreFoundation) find_library(SystemConfiguration_Library SystemConfiguration) list(APPEND EXTENSION_DEPENDENCIES ${CoreFoundation_Library} - ${SystemConfiguration_Library}) + ${SystemConfiguration_Library}) endif() endif() @@ -138,7 +137,8 @@ target_link_libraries(${EXTENSION_NAME} PUBLIC ${EXTENSION_DEPENDENCIES}) set(PARAMETERS "-warnings") build_loadable_extension(${TARGET_NAME} ${PARAMETERS} ${EXTENSION_SOURCES}) -target_link_libraries(${TARGET_NAME}_loadable_extension ${EXTENSION_DEPENDENCIES}) +target_link_libraries(${TARGET_NAME}_loadable_extension + ${EXTENSION_DEPENDENCIES}) install( TARGETS ${EXTENSION_NAME} diff --git a/Makefile b/Makefile index 830e5a45..a8ea67db 100644 --- a/Makefile +++ b/Makefile @@ -1,180 +1,8 @@ -.PHONY: all clean format debug release duckdb_debug duckdb_release pull update +PROJ_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -all: release +# Configuration of extension +EXT_NAME=excel +EXT_CONFIG=${PROJ_DIR}extension_config.cmake -DUCKDB_SRCDIR ?= "./duckdb/" - -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -PROJ_DIR := $(dir $(MKFILE_PATH)) - -TEST_PATH="/test/unittest" -DUCKDB_PATH="/duckdb" - -# For non-MinGW windows the path is slightly different -ifeq ($(OS),Windows_NT) -ifneq ($(CXX),g++) - TEST_PATH="/test/Release/unittest.exe" - DUCKDB_PATH="/Release/duckdb.exe" -endif -endif - -#### OSX config -OSX_BUILD_FLAG= -ifneq (${OSX_BUILD_ARCH}, "") - OSX_BUILD_FLAG=-DOSX_BUILD_ARCH=${OSX_BUILD_ARCH} -endif - -#### VCPKG config -VCPKG_TOOLCHAIN_PATH?= -ifneq ("${VCPKG_TOOLCHAIN_PATH}", "") - TOOLCHAIN_FLAGS:=${TOOLCHAIN_FLAGS} -DVCPKG_MANIFEST_DIR='${PROJ_DIR}' -DVCPKG_BUILD=1 -DCMAKE_TOOLCHAIN_FILE='${VCPKG_TOOLCHAIN_PATH}' -endif -ifneq ("${VCPKG_TARGET_TRIPLET}", "") - TOOLCHAIN_FLAGS:=${TOOLCHAIN_FLAGS} -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' -endif -ifeq (${USE_MERGED_VCPKG_MANIFEST}, 1) - TOOLCHAIN_FLAGS:=${TOOLCHAIN_FLAGS} -DVCPKG_MANIFEST_DIR='${PROJ_DIR}build/extension_configuration' -else - TOOLCHAIN_FLAGS:=${TOOLCHAIN_FLAGS} -DVCPKG_MANIFEST_DIR='${PROJ_DIR}' -endif - -#### Enable Ninja as generator -ifeq ($(GEN),ninja) - GENERATOR=-G "Ninja" -DFORCE_COLORED_OUTPUT=1 -endif - -EXT_NAME=spatial - -#### Configuration for this extension -EXTENSION_NAME=SPATIAL -EXTENSION_FLAGS=\ --DENABLE_SANITIZER=OFF \ --DDUCKDB_EXTENSION_NAMES="spatial" \ --DDUCKDB_EXTENSION_${EXTENSION_NAME}_PATH="$(PROJ_DIR)" \ --DDUCKDB_EXTENSION_${EXTENSION_NAME}_SHOULD_LINK=1 \ --DDUCKDB_EXTENSION_${EXTENSION_NAME}_LOAD_TESTS=1 \ --DDUCKDB_EXTENSION_${EXTENSION_NAME}_INCLUDE_PATH="$(PROJ_DIR)spatial/include" \ --DDUCKDB_EXTENSION_${EXTENSION_NAME}_TEST_PATH="$(PROJ_DIR)test" \ --DDUCKDB_EXTENSION_${EXTENSION_NAME}_LINKED_LIBS="../../deps/local/lib/*.a" - -#### Add more of the DuckDB in-tree extensions here that you need (also feel free to remove them when not needed) -EXTRA_EXTENSIONS_FLAG=-DBUILD_EXTENSIONS="parquet;json" - -BUILD_FLAGS=-DEXTENSION_STATIC_BUILD=1 $(EXTENSION_FLAGS) ${EXTRA_EXTENSIONS_FLAG} $(OSX_BUILD_FLAG) $(TOOLCHAIN_FLAGS) -DDUCKDB_EXPLICIT_PLATFORM='${DUCKDB_PLATFORM}' -ifeq (${BUILD_SHELL}, 0) - BUILD_FLAGS += -DBUILD_SHELL=0 -else - ifeq ($(OS),Windows_NT) - BUILD_FLAGS += -DBUILD_SHELL=0 - endif -endif - -ifeq (${BUILD_BENCHMARK}, 1) - BUILD_FLAGS += -DBUILD_BENCHMARKS=1 -endif - -CLIENT_FLAGS:= - -#### Main build -# For regular CLI build, we link the spatial extension directly into the DuckDB executable -CLIENT_FLAGS=-DDUCKDB_EXTENSION_${EXTENSION_NAME}_SHOULD_LINK=1 - -debug: - mkdir -p build/debug && \ - cmake $(GENERATOR) $(BUILD_FLAGS) $(CLIENT_FLAGS) -DCMAKE_BUILD_TYPE=Debug -S ./duckdb/ -B build/debug && \ - cmake --build build/debug --config Debug - -release: - mkdir -p build/release && \ - cmake $(GENERATOR) $(BUILD_FLAGS) $(CLIENT_FLAGS) -DCMAKE_BUILD_TYPE=Release -S ./duckdb/ -B build/release && \ - cmake --build build/release --config Release - -reldebug: - mkdir -p build/reldebug && \ - cmake $(GENERATOR) $(BUILD_FLAGS) $(CLIENT_FLAGS) -DCMAKE_BUILD_TYPE=RelWithDebInfo -S ./duckdb/ -B build/reldebug && \ - cmake --build build/reldebug --config RelWithDebInfo - -##### Client build -JS_BUILD_FLAGS=-DBUILD_NODE=1 -DDUCKDB_EXTENSION_${EXTENSION_NAME}_SHOULD_LINK=0 -PY_BUILD_FLAGS=-DBUILD_PYTHON=1 -DDUCKDB_EXTENSION_${EXTENSION_NAME}_SHOULD_LINK=0 - -debug_js: CLIENT_FLAGS=$(JS_BUILD_FLAGS) -debug_js: debug -debug_python: CLIENT_FLAGS=$(PY_BUILD_FLAGS) -debug_python: debug -release_js: CLIENT_FLAGS=$(JS_BUILD_FLAGS) -release_js: release -release_python: CLIENT_FLAGS=$(PY_BUILD_FLAGS) -release_python: release - -# Main tests -test: test_release - -test_release: release - ./build/release/$(TEST_PATH) "$(PROJ_DIR)test/*" - -test_debug: debug - ./build/debug/$(TEST_PATH) "$(PROJ_DIR)test/*" - -#### Client tests -DEBUG_EXT_PATH='$(PROJ_DIR)build/debug/extension/spatial/spatial.duckdb_extension' -RELEASE_EXT_PATH='$(PROJ_DIR)build/release/extension/spatial/spatial.duckdb_extension' - -test_js: test_debug_js - -test_debug_js: debug_js - cd duckdb/tools/nodejs && ${EXTENSION_NAME}_EXTENSION_BINARY_PATH=$(DEBUG_EXT_PATH) npm run test-path -- "../../../test/nodejs/**/*.js" - -test_release_js: release_js - cd duckdb/tools/nodejs && ${EXTENSION_NAME}_EXTENSION_BINARY_PATH=$(RELEASE_EXT_PATH) npm run test-path -- "../../../test/nodejs/**/*.js" - -test_python: test_debug_python - -test_debug_python: debug_python - cd test/python && ${EXTENSION_NAME}_EXTENSION_BINARY_PATH=$(DEBUG_EXT_PATH) python3 -m pytest - -test_release_python: release_python - cd test/python && ${EXTENSION_NAME}_EXTENSION_BINARY_PATH=$(RELEASE_EXT_PATH) python3 -m pytest - -#### Misc -format: - find spatial/src/ -iname *.hpp -o -iname *.cpp | xargs clang-format --sort-includes=0 -style=file -i - find spatial/include -iname *.hpp -o -iname *.cpp | xargs clang-format --sort-includes=0 -style=file -i - cmake-format -i spatial/src/CMakeLists.txt - -update: - git submodule update --remote --merge - -pull: - git submodule init - git submodule update --recursive --remote - -clean: - rm -rf build - rm -rf testext -#cd duckdb && make clean -#cd duckdb && make clean-python - -# WASM config -VCPKG_EMSDK_FLAGS=-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=$(EMSDK)/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -WASM_COMPILE_TIME_COMMON_FLAGS=-DWASM_LOADABLE_EXTENSIONS=1 -DBUILD_EXTENSIONS_ONLY=1 -DSKIP_EXTENSIONS="parquet;json" $(VCPKG_EMSDK_FLAGS) -WASM_CXX_MVP_FLAGS= -WASM_CXX_EH_FLAGS=$(WASM_CXX_MVP_FLAGS) -fwasm-exceptions -DWEBDB_FAST_EXCEPTIONS=1 -WASM_CXX_THREADS_FLAGS=$(WASM_COMPILE_TIME_EH_FLAGS) -DWITH_WASM_THREADS=1 -DWITH_WASM_SIMD=1 -DWITH_WASM_BULK_MEMORY=1 -pthread -WASM_LINK_TIME_FLAGS=-O3 -sSIDE_MODULE=2 -sEXPORTED_FUNCTIONS="_${EXT_NAME}_version,_${EXT_NAME}_init" - -# WASM targets -wasm_mvp: - mkdir -p build/wasm_mvp - emcmake cmake $(GENERATOR) $(EXTENSION_FLAGS) $(WASM_COMPILE_TIME_COMMON_FLAGS) -Bbuild/wasm_mvp -DCMAKE_CXX_FLAGS="$(WASM_CXX_MVP_FLAGS)" -S $(DUCKDB_SRCDIR) -DDUCKDB_EXPLICIT_PLATFORM=wasm_mvp -DDUCKDB_CUSTOM_PLATFORM=wasm_mvp - emmake make -j8 -Cbuild/wasm_mvp - -wasm_eh: - mkdir -p build/wasm_eh - emcmake cmake $(GENERATOR) $(EXTENSION_FLAGS) $(WASM_COMPILE_TIME_COMMON_FLAGS) -Bbuild/wasm_eh -DCMAKE_CXX_FLAGS="$(WASM_CXX_EH_FLAGS)" -S $(DUCKDB_SRCDIR) -DDUCKDB_EXPLICIT_PLATFORM=wasm_eh -DDUCKDB_CUSTOM_PLATFORM=wasm_eh - emmake make -j8 -Cbuild/wasm_eh - -wasm_threads: - mkdir -p ./build/wasm_threads - emcmake cmake $(GENERATOR) $(EXTENSION_FLAGS) $(WASM_COMPILE_TIME_COMMON_FLAGS) -Bbuild/wasm_threads -DCMAKE_CXX_FLAGS="$(WASM_CXX_THREADS_FLAGS)" -S $(DUCKDB_SRCDIR) -DDUCKDB_EXPLICIT_PLATFORM=wasm_threads -DDUCKDB_CUSTOM_PLATFORM=wasm_threads - emmake make -j8 -Cbuild/wasm_threads +# Include the Makefile from extension-ci-tools +include extension-ci-tools/makefiles/duckdb_extension.Makefile diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index f26869ff..d6bb4b98 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -11,6 +11,10 @@ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24.0") cmake_policy(SET CMP0135 NEW) endif() +if(${VCPKG_TARGET_TRIPLET} STREQUAL "wasm32-emscripten") + set(EMSCRIPTEN ON) +endif() + if (NOT EMSCRIPTEN) if (OSX_BUILD_ARCH) message(STATUS "building for OSX architecture: ${OSX_BUILD_ARCH}") @@ -31,42 +35,20 @@ set(PATCH_NAME_ENDING ) if (EMSCRIPTEN) set(CMAKE_FLAGS_POINTER_SIZE -DCMAKE_SIZEOF_VOID_P=4 -DCMAKE_SIZEOF_VOIDP=4) set(CMAKE_PROJ_FLAGS -DCMAKE_MODULE_PATH=${LOCAL_INSTALL_DIR}/lib/cmake -DSQLITE3_INCLUDE_DIR=${LOCAL_INSTALL_DIR}/include -DSQLITE3_LIBRARY=${LOCAL_INSTALL_DIR}/lib/libsqlite3.a) - set(CMAKE_GDAL_FLAGS -DACCEPT_MISSING_LINUX_FS_HEADER=ON -DSIZEOF_INT=4 -DSIZEOF_UNSIGNED_LONG=4 -DSIZEOF_OFF_T=4 -DGEOS_DIR=${LOCAL_INSTALL_DIR}/lib/cmake/geos -DGeographicLib_DIR=${LOCAL_INSTALL_DIR}/lib/cmake/GeographicLib -DSQLITE3_LIBRARY=${LOCAL_INSTALL_DIR}/lib/libsqlite3.a) + set(CMAKE_GDAL_FLAGS -DACCEPT_MISSING_LINUX_FS_HEADER=ON -DSIZEOF_INT=4 -DSIZEOF_UNSIGNED_LONG=4 -DSIZEOF_OFF_T=4 -DSQLITE3_LIBRARY=${LOCAL_INSTALL_DIR}/lib/libsqlite3.a) set(PATCH_NAME_ENDING _wasm) set(OGR_ENABLE_DRIVER_OPENFILEGDB OFF) endif() -# ZLIB -ExternalProject_Add( - ZLIB - URL ${CMAKE_CURRENT_SOURCE_DIR}/vendor/zlib1213.zip - CONFIGURE_HANDLED_BY_BUILD TRUE - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX:PATH=${LOCAL_INSTALL_DIR} - -DCMAKE_PREFIX_PATH=${LOCAL_INSTALL_DIR} - -DCMAKE_MODULE_PATH=${LOCAL_INSTALL_DIR}/lib/cmake - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES_PACKED} - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DBUILD_SHARED_LIBS=OFF - ${CMAKE_FLAGS_POINTER_SIZE} - # vcpkg options - -DVCPKG_MANIFEST_DIR='${VCPKG_MANIFEST_DIR}' - -DVCPKG_INSTALLED_DIR='${VCPKG_INSTALLED_DIR}' - -DCMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}' - -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' -) - # Use the system sqlite binary on Emscripten, iOS and Android if (EMSCRIPTEN OR IOS OR ANDROID) find_program(EXE_SQLITE3 sqlite3) endif() -set(GDAL_DEPENDENCIES ${GDAL_DEPENDENCIES} ZLIB) +set(GDAL_DEPENDENCIES ${GDAL_DEPENDENCIES}) # SQLite3 ExternalProject_Add( SQLITE3 - DEPENDS ZLIB URL ${CMAKE_CURRENT_SOURCE_DIR}/vendor/sqlite3 CONFIGURE_HANDLED_BY_BUILD TRUE CMAKE_ARGS @@ -80,6 +62,7 @@ ExternalProject_Add( -DVCPKG_INSTALLED_DIR='${VCPKG_INSTALLED_DIR}' -DCMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}' -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' + -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE='${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}' ) set(GDAL_DEPENDENCIES ${GDAL_DEPENDENCIES} SQLITE3) @@ -87,7 +70,6 @@ if(SPATIAL_USE_NETWORK) # CURL ExternalProject_Add( CURL - DEPENDS ZLIB URL ${CMAKE_CURRENT_SOURCE_DIR}/vendor/curl-7.87.0.zip CONFIGURE_HANDLED_BY_BUILD TRUE CMAKE_ARGS @@ -102,6 +84,7 @@ ExternalProject_Add( -DVCPKG_INSTALLED_DIR='${VCPKG_INSTALLED_DIR}' -DCMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}' -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' + -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE='${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}' -DBUILD_SHARED_LIBS=OFF -DHTTP_ONLY=ON # Disable some defaults for now @@ -118,7 +101,7 @@ endif() # PROJ ExternalProject_Add( PROJ - DEPENDS SQLITE3 ZLIB + DEPENDS SQLITE3 URL ${CMAKE_CURRENT_SOURCE_DIR}/vendor/proj-9.1.1.zip CONFIGURE_HANDLED_BY_BUILD TRUE PATCH_COMMAND patch -p1 < "${CMAKE_CURRENT_LIST_DIR}/patches/proj${PATCH_NAME_ENDING}.patch" @@ -136,6 +119,7 @@ ExternalProject_Add( -DVCPKG_INSTALLED_DIR='${VCPKG_INSTALLED_DIR}' -DCMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}' -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' + -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE='${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}' # PROJ options -DBUILD_SHARED_LIBS=OFF -DBUILD_APPS=OFF @@ -164,6 +148,7 @@ ExternalProject_Add( -DVCPKG_INSTALLED_DIR='${VCPKG_INSTALLED_DIR}' -DCMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}' -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' + -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE='${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}' # EXPAT options -DEXPAT_SHARED_LIBS=OFF -DEXPAT_BUILD_TESTS=OFF @@ -173,57 +158,7 @@ ExternalProject_Add( ) set(GDAL_DEPENDENCIES ${GDAL_DEPENDENCIES} EXPAT) - -# GEOS -ExternalProject_Add( - GEOS - URL ${CMAKE_CURRENT_SOURCE_DIR}/vendor/geos-3.13.0.tar.bz2 - CONFIGURE_HANDLED_BY_BUILD TRUE - CMAKE_ARGS - # CMake options - -DCMAKE_INSTALL_PREFIX:PATH=${LOCAL_INSTALL_DIR} - -DCMAKE_PREFIX_PATH=${LOCAL_INSTALL_DIR} - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES_PACKED} - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - ${CMAKE_FLAGS_POINTER_SIZE} - # vcpkg options - -DVCPKG_MANIFEST_DIR='${VCPKG_MANIFEST_DIR}' - -DVCPKG_INSTALLED_DIR='${VCPKG_INSTALLED_DIR}' - -DCMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}' - -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' - # GEOS options - -DBUILD_SHARED_LIBS=OFF - -DBUILD_TESTING=OFF - -DBUILD_DOCUMENTATION=OFF - -DBUILD_ASTYLE=OFF - -DBUILD_GEOSOP=OFF -) -set(GDAL_DEPENDENCIES ${GDAL_DEPENDENCIES} GEOS) - -# GeographicLib -ExternalProject_Add( - GEOGRAPHICLIB - URL ${CMAKE_CURRENT_SOURCE_DIR}/vendor/GeographicLib-2.2.zip - CONFIGURE_HANDLED_BY_BUILD TRUE - PATCH_COMMAND patch -p1 < "${CMAKE_CURRENT_LIST_DIR}/patches/geographiclib${PATCH_NAME_ENDING}.patch" - CMAKE_ARGS - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DCMAKE_INSTALL_PREFIX:PATH=${LOCAL_INSTALL_DIR} - -DCMAKE_PREFIX_PATH=${LOCAL_INSTALL_DIR} - -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES_PACKED} - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - ${CMAKE_FLAGS_POINTER_SIZE} - # vcpkg options - -DVCPKG_MANIFEST_DIR='${VCPKG_MANIFEST_DIR}' - -DVCPKG_INSTALLED_DIR='${VCPKG_INSTALLED_DIR}' - -DCMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}' - -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' - # GeographicLib options - -DBUILD_SHARED_LIBS=OFF - -DGEOGRAPHICLIB_DATA=${LOCAL_INSTALL_DIR}/share/GeographicLib - -DBUILD_DOCUMENTATION=OFF -) +set(GDAL_DEPENDENCIES ${GDAL_DEPENDENCIES}) # GDAL ExternalProject_Add( @@ -247,6 +182,7 @@ ExternalProject_Add( -DVCPKG_INSTALLED_DIR='${VCPKG_INSTALLED_DIR}' -DCMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}' -DVCPKG_TARGET_TRIPLET='${VCPKG_TARGET_TRIPLET}' + -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE='${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}' # GDAL Options -DGDAL_OBJECT_LIBRARIES_POSITION_INDEPENDENT_CODE=ON # this is needed for GDAL to build with -fPIC -DBUILD_TESTING=OFF diff --git a/deps/vendor/GeographicLib-2.2.zip b/deps/vendor/GeographicLib-2.2.zip deleted file mode 100644 index 11d4fd72..00000000 Binary files a/deps/vendor/GeographicLib-2.2.zip and /dev/null differ diff --git a/deps/vendor/apache-arrow-10.0.1.zip b/deps/vendor/apache-arrow-10.0.1.zip deleted file mode 100644 index 8fca4a85..00000000 Binary files a/deps/vendor/apache-arrow-10.0.1.zip and /dev/null differ diff --git a/deps/vendor/geos-3.13.0.tar.bz2 b/deps/vendor/geos-3.13.0.tar.bz2 deleted file mode 100644 index 6027d42a..00000000 Binary files a/deps/vendor/geos-3.13.0.tar.bz2 and /dev/null differ diff --git a/deps/vendor/openssl-openssl-3.0.7.zip b/deps/vendor/openssl-openssl-3.0.7.zip deleted file mode 100644 index fa0483cc..00000000 Binary files a/deps/vendor/openssl-openssl-3.0.7.zip and /dev/null differ diff --git a/deps/vendor/zlib1213.zip b/deps/vendor/zlib1213.zip deleted file mode 100644 index f0bcb4e1..00000000 Binary files a/deps/vendor/zlib1213.zip and /dev/null differ diff --git a/docs/functions.md b/docs/functions.md index e1245ed9..80e4cc1b 100644 --- a/docs/functions.md +++ b/docs/functions.md @@ -47,7 +47,7 @@ | [`ST_GeomFromHEXWKB`](#st_geomfromhexwkb) | Creates a GEOMETRY from a HEXWKB string | | [`ST_GeomFromText`](#st_geomfromtext) | Deserializes a GEOMETRY from a WKT string, optionally ignoring invalid geometries | | [`ST_GeomFromWKB`](#st_geomfromwkb) | Deserializes a GEOMETRY from a WKB encoded blob | -| [`ST_GeometryType`](#st_geometrytype) | Returns a 'GEOMETRY_TYPE' enum identifying the input geometry type. | +| [`ST_GeometryType`](#st_geometrytype) | Returns a 'GEOMETRY_TYPE' enum identifying the input geometry type. Possible enum return types are: `POINT`, `LINESTRING`, `POLYGON`, `MULTIPOINT`, `MULTILINESTRING`, `MULTIPOLYGON`, and `GEOMETRYCOLLECTION`. | | [`ST_HasM`](#st_hasm) | Check if the input geometry has M values. | | [`ST_HasZ`](#st_hasz) | Check if the input geometry has Z values. | | [`ST_Hilbert`](#st_hilbert) | Encodes the X and Y values as the hilbert curve index for a curve covering the given bounding box. | @@ -496,8 +496,8 @@ select st_collectionextract('MULTIPOINT(1 2,3 4)'::geometry, 1); #### Signatures ```sql -BOOLEAN ST_Contains (col0 POLYGON_2D, col1 POINT_2D) -BOOLEAN ST_Contains (col0 GEOMETRY, col1 GEOMETRY) +BOOLEAN ST_Contains (geom1 POLYGON_2D, geom2 POINT_2D) +BOOLEAN ST_Contains (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description @@ -520,7 +520,7 @@ true #### Signature ```sql -BOOLEAN ST_ContainsProperly (col0 GEOMETRY, col1 GEOMETRY) +BOOLEAN ST_ContainsProperly (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description @@ -550,7 +550,7 @@ Returns the convex hull enclosing the geometry #### Signature ```sql -BOOLEAN ST_CoveredBy (col0 GEOMETRY, col1 GEOMETRY) +BOOLEAN ST_CoveredBy (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description @@ -565,7 +565,7 @@ Returns true if geom1 is "covered" by geom2 #### Signature ```sql -BOOLEAN ST_Covers (col0 GEOMETRY, col1 GEOMETRY) +BOOLEAN ST_Covers (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description @@ -580,7 +580,7 @@ Returns if geom1 "covers" geom2 #### Signature ```sql -BOOLEAN ST_Crosses (col0 GEOMETRY, col1 GEOMETRY) +BOOLEAN ST_Crosses (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description @@ -610,14 +610,14 @@ Returns if two geometries are within a target distance of each-other #### Signature ```sql -DOUBLE ST_DWithin_Spheroid (col0 POINT_2D, col1 POINT_2D, col2 DOUBLE) +BOOLEAN ST_DWithin_Spheroid (col0 POINT_2D, col1 POINT_2D, col2 DOUBLE) ``` #### Description Returns if two POINT_2D's are within a target distance in meters, using an ellipsoidal model of the earths surface -The input geometry is assumed to be in the [EPSG:4326](https://en.wikipedia.org/wiki/World_Geodetic_System) coordinate system (WGS84), with [latitude, longitude] axis order and the distance is returned in meters. This function uses the [GeographicLib](https://geographiclib.sourceforge.io/) library to solve the [inverse geodesic problem](https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid#Solution_of_the_direct_and_inverse_problems), calculating the distance between two points using an ellipsoidal model of the earth. This is a highly accurate method for calculating the distance between two arbitrary points taking the curvature of the earths surface into account, but is also the slowest. + The input geometry is assumed to be in the [EPSG:4326](https://en.wikipedia.org/wiki/World_Geodetic_System) coordinate system (WGS84), with [latitude, longitude] axis order and the distance is returned in meters. This function uses the [GeographicLib](https://geographiclib.sourceforge.io/) library to solve the [inverse geodesic problem](https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid#Solution_of_the_direct_and_inverse_problems), calculating the distance between two points using an ellipsoidal model of the earth. This is a highly accurate method for calculating the distance between two arbitrary points taking the curvature of the earths surface into account, but is also the slowest. ---- @@ -1059,7 +1059,15 @@ ANY ST_GeometryType (col0 WKB_BLOB) #### Description -Returns a 'GEOMETRY_TYPE' enum identifying the input geometry type. +Returns a 'GEOMETRY_TYPE' enum identifying the input geometry type. Possible enum return types are: `POINT`, `LINESTRING`, `POLYGON`, `MULTIPOINT`, `MULTILINESTRING`, `MULTIPOLYGON`, and `GEOMETRYCOLLECTION`. + +#### Example + +```sql +SELECT DISTINCT ST_GeometryType(ST_GeomFromText('POINT(1 1)')); +---- +POINT +``` ---- @@ -1171,7 +1179,7 @@ For the BOX_2D and BOX_2DF variants, the center of the box is used as the point #### Signature ```sql -GEOMETRY ST_Intersection (col0 GEOMETRY, col1 GEOMETRY) +GEOMETRY ST_Intersection (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description @@ -1391,7 +1399,7 @@ Returns the minimum M value of a geometry #### Signature ```sql -GEOMETRY ST_MakeEnvelope (col0 DOUBLE, col1 DOUBLE, col2 DOUBLE, col3 DOUBLE) +GEOMETRY ST_MakeEnvelope (min_x DOUBLE, min_y DOUBLE, max_x DOUBLE, max_y DOUBLE) ``` #### Description @@ -1600,7 +1608,7 @@ Returns the number of vertices within a geometry #### Signature ```sql -BOOLEAN ST_Overlaps (col0 GEOMETRY, col1 GEOMETRY) +BOOLEAN ST_Overlaps (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description @@ -1652,7 +1660,7 @@ Returns `0.0` for any geometry that is not a `POLYGON`, `MULTIPOLYGON` or `GEOME #### Signature ```sql -GEOMETRY ST_Point (col0 DOUBLE, col1 DOUBLE) +GEOMETRY ST_Point (x DOUBLE, y DOUBLE) ``` #### Description @@ -1667,7 +1675,7 @@ Creates a GEOMETRY point #### Signature ```sql -POINT_2D ST_Point2D (col0 DOUBLE, col1 DOUBLE) +POINT_2D ST_Point2D (x DOUBLE, y DOUBLE) ``` #### Description @@ -1682,7 +1690,7 @@ Creates a POINT_2D #### Signature ```sql -POINT_3D ST_Point3D (col0 DOUBLE, col1 DOUBLE, col2 DOUBLE) +POINT_3D ST_Point3D (x DOUBLE, y DOUBLE, z DOUBLE) ``` #### Description @@ -1697,7 +1705,7 @@ Creates a POINT_3D #### Signature ```sql -POINT_4D ST_Point4D (col0 DOUBLE, col1 DOUBLE, col2 DOUBLE, col3 DOUBLE) +POINT_4D ST_Point4D (x DOUBLE, y DOUBLE, z DOUBLE, m DOUBLE) ``` #### Description @@ -1770,8 +1778,8 @@ MULTIPOINT Z EMPTY #### Signatures ```sql -VARCHAR ST_QuadKey (col0 DOUBLE, col1 DOUBLE, col2 INTEGER) -VARCHAR ST_QuadKey (col0 GEOMETRY, col1 INTEGER) +VARCHAR ST_QuadKey (lon DOUBLE, lat DOUBLE, level INTEGER) +VARCHAR ST_QuadKey (point GEOMETRY, level INTEGER) ``` #### Description @@ -1849,7 +1857,7 @@ Returns a new version of the input geometry with the order of its vertices rever #### Signature ```sql -GEOMETRY ST_ShortestLine (col0 GEOMETRY, col1 GEOMETRY) +GEOMETRY ST_ShortestLine (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description @@ -1917,7 +1925,7 @@ select ST_StartPoint('LINESTRING(0 0, 1 1)'::geometry); #### Signature ```sql -BOOLEAN ST_Touches (col0 GEOMETRY, col1 GEOMETRY) +BOOLEAN ST_Touches (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description @@ -2024,8 +2032,8 @@ MULTIPOINT (1 2, 3 4) #### Signatures ```sql -BOOLEAN ST_Within (col0 POINT_2D, col1 POLYGON_2D) -BOOLEAN ST_Within (col0 GEOMETRY, col1 GEOMETRY) +BOOLEAN ST_Within (geom1 POINT_2D, geom2 POLYGON_2D) +BOOLEAN ST_Within (geom1 GEOMETRY, geom2 GEOMETRY) ``` #### Description diff --git a/duckdb b/duckdb index c3ca3607..fc4b8d47 160000 --- a/duckdb +++ b/duckdb @@ -1 +1 @@ -Subproject commit c3ca3607c221d315f38227b8bf58e68746c59083 +Subproject commit fc4b8d4794d0dfe62764ae5d03270d34264c005f diff --git a/extension-ci-tools b/extension-ci-tools new file mode 160000 index 00000000..916d4ef4 --- /dev/null +++ b/extension-ci-tools @@ -0,0 +1 @@ +Subproject commit 916d4ef4371068ca98a007378b52582c3e46b4e5 diff --git a/extension_config.cmake b/extension_config.cmake new file mode 100644 index 00000000..5f026a73 --- /dev/null +++ b/extension_config.cmake @@ -0,0 +1,17 @@ +# This file is included by DuckDB's build system. It specifies which extension to load + +# Extension from this repo + +# Disable tests on MinGW for 1.1.3, will be fixed in 1.1.4 +if (MINGW) + set(DO_TESTS "") +else () + set(DO_TESTS "LOAD_TESTS") +endif() + +duckdb_extension_load(spatial + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR} + INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/spatial/include + ${DO_TESTS} + LINKED_LIBS "../../deps/local/lib/*.a" +) \ No newline at end of file diff --git a/generate_function_reference.py b/generate_function_reference.py index a349b77a..f227aa23 100644 --- a/generate_function_reference.py +++ b/generate_function_reference.py @@ -1,6 +1,7 @@ import os import json +# We just take the first non-empty description and example for now get_spatial_functions_sql = """ SELECT json({ @@ -16,15 +17,17 @@ function_name, list({ return: return_type, - params: list_zip(parameters, parameter_types)::STRUCT(name VARCHAR, type VARCHAR)[] + params: list_zip(parameters, parameter_types)::STRUCT(name VARCHAR, type VARCHAR)[], + description: description, + examples: examples }) as signatures, + list_filter(signatures, x -> x.description IS NOT NULL)[1].description as description, + list_filter(signatures, x -> len(x.examples) != 0)[1].examples[1] as example, any_value(tags) AS func_tags, - any_value(description) AS description, - any_value(example) AS example FROM duckdb_functions() as funcs WHERE function_type = '$FUNCTION_TYPE$' GROUP BY function_name, function_type - HAVING func_tags['ext'] = ['spatial'] + HAVING func_tags['ext'] = 'spatial' ORDER BY function_name ); """ @@ -40,7 +43,7 @@ def write_table_of_contents(f, functions): f.write('| --- | --- |\n') for function in functions: # Summary is the first line of the description - summary = function['description'].split('\n')[0] + summary = function['description'].split('\n')[0] if function['description'] else "" f.write(f"| [`{function['name']}`](#{to_kebab_case(function['name'])}) | {summary} |\n") @@ -87,6 +90,8 @@ def main(): f.write(f"{signature['return']} {function['name']} ({param_list})\n") f.write("```\n\n") + + if function['description']: f.write("#### Description\n\n") f.write(function['description']) diff --git a/spatial/include/spatial/core/function_builder.hpp b/spatial/include/spatial/core/function_builder.hpp new file mode 100644 index 00000000..6bb2d4e8 --- /dev/null +++ b/spatial/include/spatial/core/function_builder.hpp @@ -0,0 +1,146 @@ +#pragma once + +#include "duckdb.hpp" + +#include "spatial/common.hpp" +#include "duckdb/function/function_set.hpp" +#include "duckdb/function/scalar_function.hpp" +#include "duckdb/parser/parsed_data/create_function_info.hpp" + +namespace spatial { + +namespace core { +//------------------------------------------------------------------------------ +// Scalar Function Variant Builder +//------------------------------------------------------------------------------ + +class ScalarFunctionVariantBuilder { + friend class ScalarFunctionBuilder; + +public: + void AddParameter(const char *name, const LogicalType &type); + void SetReturnType(LogicalType type); + void SetFunction(scalar_function_t fn); + void SetInit(init_local_state_t init); + void SetBind(bind_scalar_function_t bind); + void SetDescription(const string &desc); + void SetExample(const string &ex); + +private: + explicit ScalarFunctionVariantBuilder() : function({}, LogicalTypeId::INVALID, nullptr) { + } + + ScalarFunction function; + FunctionDescription description = {}; +}; + +inline void ScalarFunctionVariantBuilder::AddParameter(const char *name, const LogicalType &type) { + function.arguments.emplace_back(type); + description.parameter_names.emplace_back(name); + description.parameter_types.emplace_back(type); +} + +inline void ScalarFunctionVariantBuilder::SetReturnType(LogicalType type) { + function.return_type = std::move(type); +} + +inline void ScalarFunctionVariantBuilder::SetFunction(scalar_function_t fn) { + function.function = fn; +} + +inline void ScalarFunctionVariantBuilder::SetInit(init_local_state_t init) { + function.init_local_state = init; +} + +inline void ScalarFunctionVariantBuilder::SetBind(bind_scalar_function_t bind) { + function.bind = bind; +} + +inline void ScalarFunctionVariantBuilder::SetDescription(const string &desc) { + description.description = desc; +} + +inline void ScalarFunctionVariantBuilder::SetExample(const string &ex) { + description.examples.emplace_back(ex); +} + +//------------------------------------------------------------------------------ +// Scalar Function Builder +//------------------------------------------------------------------------------ + +class ScalarFunctionBuilder { + friend class FunctionBuilder; + +public: + template + void AddVariant(CALLBACK &&callback); + void SetTag(const string &key, const string &value); + void SetDescription(const string &desc); + +private: + explicit ScalarFunctionBuilder(const char *name) : set(name) { + } + + ScalarFunctionSet set; + vector descriptions = {}; + unordered_map tags = {}; + + // If not set by a variant + string default_description; +}; + +inline void ScalarFunctionBuilder::SetDescription(const string &desc) { + default_description = desc; +} + +inline void ScalarFunctionBuilder::SetTag(const string &key, const string &value) { + tags[key] = value; +} + +template +void ScalarFunctionBuilder::AddVariant(CALLBACK &&callback) { + ScalarFunctionVariantBuilder builder; + + callback(builder); + + // A return type is required + if (builder.function.return_type.id() == LogicalTypeId::INVALID) { + throw InternalException("Return type not set in ScalarFunctionBuilder::AddVariant"); + } + + // Add the new variant to the set + set.AddFunction(std::move(builder.function)); + + // Add the default description if not set by the variant + if (builder.description.description.empty()) { + builder.description.description = default_description; + } + + // Add the description + descriptions.emplace_back(std::move(builder.description)); +} + +//------------------------------------------------------------------------------ +// Function Builder +//------------------------------------------------------------------------------ + +class FunctionBuilder { +public: + template + static void RegisterScalar(DatabaseInstance &db, const char *name, CALLBACK &&callback); + +private: + static void Register(DatabaseInstance &db, const char *name, ScalarFunctionBuilder &builder); +}; + +template +void FunctionBuilder::RegisterScalar(DatabaseInstance &db, const char *name, CALLBACK &&callback) { + ScalarFunctionBuilder builder(name); + callback(builder); + + Register(db, name, builder); +} + +} // namespace core + +} // namespace spatial \ No newline at end of file diff --git a/spatial/include/spatial/doc_util.hpp b/spatial/include/spatial/doc_util.hpp index 6262c18a..86fca3eb 100644 --- a/spatial/include/spatial/doc_util.hpp +++ b/spatial/include/spatial/doc_util.hpp @@ -11,22 +11,20 @@ struct DocTag { struct DocUtil { static void AddDocumentation(duckdb::DatabaseInstance &db, const char *function_name, const char *description, - const char *example, - const duckdb::unordered_map &tags); + const char *example, const duckdb::unordered_map &tags, + duckdb::vector parameter_names = {}); // Abuse adding tags as a comment template static void AddDocumentation(duckdb::DatabaseInstance &db, const char *function_name, const char *description, - const char *example, const DocTag (&tags)[N]) { + const char *example, const DocTag (&tags)[N], + duckdb::vector parameter_names = {}) { duckdb::unordered_map tag_map; for (size_t i = 0; i < N; i++) { tag_map[tags[i].key] = tags[i].value; } - AddDocumentation(db, function_name, description, example, tag_map); + AddDocumentation(db, function_name, description, example, tag_map, parameter_names); } - - static void AddFunctionParameterNames(duckdb::DatabaseInstance &db, const char *function_name, - duckdb::vector names); }; -} // namespace spatial \ No newline at end of file +} // namespace spatial diff --git a/spatial/src/spatial/core/CMakeLists.txt b/spatial/src/spatial/core/CMakeLists.txt index db2a6e34..3eb9b789 100644 --- a/spatial/src/spatial/core/CMakeLists.txt +++ b/spatial/src/spatial/core/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(util) set(EXTENSION_SOURCES ${EXTENSION_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/function_builder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/module.cpp ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp ${CMAKE_CURRENT_SOURCE_DIR}/optimizer_rules.cpp diff --git a/spatial/src/spatial/core/function_builder.cpp b/spatial/src/spatial/core/function_builder.cpp new file mode 100644 index 00000000..7367287b --- /dev/null +++ b/spatial/src/spatial/core/function_builder.cpp @@ -0,0 +1,78 @@ +#include "spatial/core/function_builder.hpp" +#include "duckdb/catalog/catalog_entry/function_entry.hpp" +#include "duckdb/main/extension_util.hpp" + +namespace spatial { + +namespace core { + +static string RemoveIndentAndTrailingWhitespace(const char *text) { + string result; + // Skip any empty first newlines if present + while (*text == '\n') { + text++; + } + + // Track indent length + auto indent_start = text; + while (isspace(*text) && *text != '\n') { + text++; + } + auto indent_len = text - indent_start; + while (*text) { + result += *text; + if (*text++ == '\n') { + // Remove all indentation, but only if it matches the first line's indentation + bool matched_indent = true; + for (auto i = 0; i < indent_len; i++) { + if (*text != indent_start[i]) { + matched_indent = false; + break; + } + } + if (matched_indent) { + text += indent_len; + } + } + } + + // Also remove any trailing whitespace + result.erase(result.find_last_not_of(" \n\r\t") + 1); + return result; +} + +void FunctionBuilder::Register(DatabaseInstance &db, const char *name, ScalarFunctionBuilder &builder) { + // Register the function + ExtensionUtil::RegisterFunction(db, std::move(builder.set)); + + // Also add the parameter names. We need to access the catalog entry for this. + auto &catalog = Catalog::GetSystemCatalog(db); + auto transaction = CatalogTransaction::GetSystemTransaction(db); + auto &schema = catalog.GetSchema(transaction, DEFAULT_SCHEMA); + auto catalog_entry = schema.GetEntry(transaction, CatalogType::SCALAR_FUNCTION_ENTRY, name); + if (!catalog_entry) { + // This should not happen, we just registered the function + throw InternalException("Function with name \"%s\" not found in FunctionBuilder::AddScalar", name); + } + + auto &func_entry = catalog_entry->Cast(); + + // Insert all descriptions + for (auto &desc : builder.descriptions) { + + desc.description = RemoveIndentAndTrailingWhitespace(desc.description.c_str()); + for (auto &ex : desc.examples) { + ex = RemoveIndentAndTrailingWhitespace(ex.c_str()); + } + + func_entry.descriptions.push_back(desc); + } + + if (!builder.tags.empty()) { + func_entry.tags = std::move(builder.tags); + } +} + +} // namespace core + +} // namespace spatial \ No newline at end of file diff --git a/spatial/src/spatial/core/functions/scalar/st_collectionextract.cpp b/spatial/src/spatial/core/functions/scalar/st_collectionextract.cpp index 78c3f7d9..82ad4598 100644 --- a/spatial/src/spatial/core/functions/scalar/st_collectionextract.cpp +++ b/spatial/src/spatial/core/functions/scalar/st_collectionextract.cpp @@ -196,10 +196,9 @@ void CoreScalarFunctions::RegisterStCollectionExtract(DatabaseInstance &db) { GeometryFunctionLocalState::Init)); ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_CollectionExtract", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); - DocUtil::AddFunctionParameterNames(db, "ST_CollectionExtract", {"geom", "type"}); + DocUtil::AddDocumentation(db, "ST_CollectionExtract", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS, {"geom", "type"}); } } // namespace core -} // namespace spatial \ No newline at end of file +} // namespace spatial diff --git a/spatial/src/spatial/core/functions/scalar/st_contains.cpp b/spatial/src/spatial/core/functions/scalar/st_contains.cpp index ef7af82e..1978e85e 100644 --- a/spatial/src/spatial/core/functions/scalar/st_contains.cpp +++ b/spatial/src/spatial/core/functions/scalar/st_contains.cpp @@ -1,8 +1,8 @@ #include "spatial/common.hpp" -#include "spatial/core/types.hpp" #include "spatial/core/functions/scalar.hpp" +#include "spatial/core/types.hpp" +#include "spatial/core/function_builder.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" namespace spatial { namespace core { @@ -148,18 +148,24 @@ static void PointWithinPolygonFunction(DataChunk &args, ExpressionState &state, //------------------------------------------------------------------------------ void CoreScalarFunctions::RegisterStContains(DatabaseInstance &db) { - // ST_Within is the inverse of ST_Contains - ScalarFunctionSet contains_function_set("ST_Contains"); - ScalarFunctionSet within_function_set("ST_Within"); + FunctionBuilder::RegisterScalar(db, "ST_Contains", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::POLYGON_2D()); + variant.AddParameter("geom2", GeoTypes::POINT_2D()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(PolygonContainsPointFunction); + }); + }); - // POLYGON_2D - POINT_2D - contains_function_set.AddFunction(ScalarFunction({GeoTypes::POLYGON_2D(), GeoTypes::POINT_2D()}, - LogicalType::BOOLEAN, PolygonContainsPointFunction)); - within_function_set.AddFunction(ScalarFunction({GeoTypes::POINT_2D(), GeoTypes::POLYGON_2D()}, LogicalType::BOOLEAN, - PointWithinPolygonFunction)); - - ExtensionUtil::RegisterFunction(db, contains_function_set); - ExtensionUtil::RegisterFunction(db, within_function_set); + // ST_Within is the inverse of ST_Contains + FunctionBuilder::RegisterScalar(db, "ST_Within", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::POINT_2D()); + variant.AddParameter("geom2", GeoTypes::POLYGON_2D()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(PointWithinPolygonFunction); + }); + }); } } // namespace core diff --git a/spatial/src/spatial/core/functions/scalar/st_geometrytype.cpp b/spatial/src/spatial/core/functions/scalar/st_geometrytype.cpp index 9b7c0b5c..2acfe200 100644 --- a/spatial/src/spatial/core/functions/scalar/st_geometrytype.cpp +++ b/spatial/src/spatial/core/functions/scalar/st_geometrytype.cpp @@ -84,10 +84,14 @@ static void WKBTypeFunction(DataChunk &args, ExpressionState &state, Vector &res // Documentation //------------------------------------------------------------------------------ static constexpr const char *DOC_DESCRIPTION = R"( - Returns a 'GEOMETRY_TYPE' enum identifying the input geometry type. + Returns a 'GEOMETRY_TYPE' enum identifying the input geometry type. Possible enum return types are: `POINT`, `LINESTRING`, `POLYGON`, `MULTIPOINT`, `MULTILINESTRING`, `MULTIPOLYGON`, and `GEOMETRYCOLLECTION`. )"; -static constexpr const char *DOC_EXAMPLE = R"()"; +static constexpr const char *DOC_EXAMPLE = R"( +SELECT DISTINCT ST_GeometryType(ST_GeomFromText('POINT(1 1)')); +---- +POINT +)"; static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "property"}}; //------------------------------------------------------------------------------ diff --git a/spatial/src/spatial/core/functions/scalar/st_makeenvelope.cpp b/spatial/src/spatial/core/functions/scalar/st_makeenvelope.cpp index 2b3acf1f..48e9c04e 100644 --- a/spatial/src/spatial/core/functions/scalar/st_makeenvelope.cpp +++ b/spatial/src/spatial/core/functions/scalar/st_makeenvelope.cpp @@ -3,8 +3,8 @@ #include "spatial/core/functions/scalar.hpp" #include "spatial/core/functions/common.hpp" #include "spatial/core/geometry/geometry.hpp" +#include "spatial/core/function_builder.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "duckdb/common/vector_operations/generic_executor.hpp" namespace spatial { @@ -41,21 +41,27 @@ static constexpr const char *DOC_DESCRIPTION = R"( static constexpr const char *DOC_EXAMPLE = R"( )"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "construction"}}; //------------------------------------------------------------------------------ // Register Functions //------------------------------------------------------------------------------ void CoreScalarFunctions::RegisterStMakeEnvelope(DatabaseInstance &db) { - - ScalarFunctionSet set("ST_MakeEnvelope"); - - set.AddFunction(ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE}, - GeoTypes::GEOMETRY(), MakeEnvelopeFunction, nullptr, nullptr, nullptr, - GeometryFunctionLocalState::Init)); - - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_MakeEnvelope", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_MakeEnvelope", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("min_x", LogicalType::DOUBLE); + variant.AddParameter("min_y", LogicalType::DOUBLE); + variant.AddParameter("max_x", LogicalType::DOUBLE); + variant.AddParameter("max_y", LogicalType::DOUBLE); + variant.SetReturnType(GeoTypes::GEOMETRY()); + variant.SetFunction(MakeEnvelopeFunction); + variant.SetInit(GeometryFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "construction"); + }); } } // namespace core diff --git a/spatial/src/spatial/core/functions/scalar/st_point.cpp b/spatial/src/spatial/core/functions/scalar/st_point.cpp index d6c79e74..10d00a3d 100644 --- a/spatial/src/spatial/core/functions/scalar/st_point.cpp +++ b/spatial/src/spatial/core/functions/scalar/st_point.cpp @@ -4,6 +4,7 @@ #include "spatial/core/functions/common.hpp" #include "spatial/core/geometry/geometry.hpp" #include "spatial/core/types.hpp" +#include "spatial/core/function_builder.hpp" namespace spatial { @@ -114,37 +115,67 @@ static void PointFunction(DataChunk &args, ExpressionState &state, Vector &resul //------------------------------------------------------------------------------ // Register functions //------------------------------------------------------------------------------ -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "construction"}}; - void CoreScalarFunctions::RegisterStPoint(DatabaseInstance &db) { - ScalarFunction st_point("ST_Point", {LogicalType::DOUBLE, LogicalType::DOUBLE}, GeoTypes::GEOMETRY(), PointFunction, - nullptr, nullptr, nullptr, GeometryFunctionLocalState::Init); - - ExtensionUtil::RegisterFunction(db, st_point); - auto POINT_DOC_DESCRIPTION = "Creates a GEOMETRY point"; - DocUtil::AddDocumentation(db, "ST_Point", POINT_DOC_DESCRIPTION, nullptr, DOC_TAGS); - - // Non-standard - ScalarFunction st_point2d("ST_Point2D", {LogicalType::DOUBLE, LogicalType::DOUBLE}, GeoTypes::POINT_2D(), - Point2DFunction); - ExtensionUtil::RegisterFunction(db, st_point2d); - auto POINT2D_DOC_DESCRIPTION = "Creates a POINT_2D"; - DocUtil::AddDocumentation(db, "ST_Point2D", POINT2D_DOC_DESCRIPTION, nullptr, DOC_TAGS); - - ScalarFunction st_point_3d("ST_Point3D", {LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE}, - GeoTypes::POINT_3D(), Point3DFunction); - ExtensionUtil::RegisterFunction(db, st_point_3d); - auto POINT3D_DOC_DESCRIPTION = "Creates a POINT_3D"; - DocUtil::AddDocumentation(db, "ST_Point3D", POINT3D_DOC_DESCRIPTION, nullptr, DOC_TAGS); - - ScalarFunction st_point_4d("ST_Point4D", - {LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE}, - GeoTypes::POINT_4D(), Point4DFunction); - - ExtensionUtil::RegisterFunction(db, st_point_4d); - auto POINT4D_DOC_DESCRIPTION = "Creates a POINT_4D"; - DocUtil::AddDocumentation(db, "ST_Point4D", POINT4D_DOC_DESCRIPTION, nullptr, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_Point", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("x", LogicalType::DOUBLE); + variant.AddParameter("y", LogicalType::DOUBLE); + variant.SetReturnType(GeoTypes::GEOMETRY()); + variant.SetFunction(PointFunction); + variant.SetInit(GeometryFunctionLocalState::Init); + + variant.SetDescription("Creates a GEOMETRY point"); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "construction"); + }); + + FunctionBuilder::RegisterScalar(db, "ST_Point2D", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("x", LogicalType::DOUBLE); + variant.AddParameter("y", LogicalType::DOUBLE); + variant.SetReturnType(GeoTypes::POINT_2D()); + variant.SetFunction(Point2DFunction); + + variant.SetDescription("Creates a POINT_2D"); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "construction"); + }); + + FunctionBuilder::RegisterScalar(db, "ST_Point3D", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("x", LogicalType::DOUBLE); + variant.AddParameter("y", LogicalType::DOUBLE); + variant.AddParameter("z", LogicalType::DOUBLE); + variant.SetReturnType(GeoTypes::POINT_3D()); + variant.SetFunction(Point3DFunction); + + variant.SetDescription("Creates a POINT_3D"); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "construction"); + }); + + FunctionBuilder::RegisterScalar(db, "ST_Point4D", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("x", LogicalType::DOUBLE); + variant.AddParameter("y", LogicalType::DOUBLE); + variant.AddParameter("z", LogicalType::DOUBLE); + variant.AddParameter("m", LogicalType::DOUBLE); + variant.SetReturnType(GeoTypes::POINT_4D()); + variant.SetFunction(Point4DFunction); + + variant.SetDescription("Creates a POINT_4D"); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "construction"); + }); } } // namespace core diff --git a/spatial/src/spatial/core/functions/scalar/st_quadkey.cpp b/spatial/src/spatial/core/functions/scalar/st_quadkey.cpp index 0add5283..59b33722 100644 --- a/spatial/src/spatial/core/functions/scalar/st_quadkey.cpp +++ b/spatial/src/spatial/core/functions/scalar/st_quadkey.cpp @@ -6,6 +6,7 @@ #include "spatial/core/functions/common.hpp" #include "spatial/core/geometry/geometry.hpp" #include "spatial/core/types.hpp" +#include "spatial/core/function_builder.hpp" #include @@ -106,23 +107,37 @@ SELECT ST_QuadKey(st_point(11.08, 49.45), 10); ---- 1333203202 )"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "property"}}; //------------------------------------------------------------------------------ // Register functions //------------------------------------------------------------------------------ void CoreScalarFunctions::RegisterStQuadKey(DatabaseInstance &db) { - ScalarFunctionSet set("ST_QuadKey"); - - set.AddFunction(ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::INTEGER}, - LogicalType::VARCHAR, CoordinateQuadKeyFunction)); - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), LogicalType::INTEGER}, LogicalType::VARCHAR, - GeometryQuadKeyFunction, nullptr, nullptr, nullptr, - GeometryFunctionLocalState::Init)); - - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_QuadKey", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_QuadKey", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("longitude", LogicalType::DOUBLE); + variant.AddParameter("latitude", LogicalType::DOUBLE); + variant.AddParameter("level", LogicalType::INTEGER); + variant.SetReturnType(LogicalType::VARCHAR); + variant.SetFunction(CoordinateQuadKeyFunction); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("point", GeoTypes::GEOMETRY()); + variant.AddParameter("level", LogicalType::INTEGER); + variant.SetReturnType(LogicalType::VARCHAR); + variant.SetFunction(GeometryQuadKeyFunction); + variant.SetInit(GeometryFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "property"); + }); } } // namespace core diff --git a/spatial/src/spatial/core/functions/table/st_generatepoints.cpp b/spatial/src/spatial/core/functions/table/st_generatepoints.cpp index 007d386d..8754619a 100644 --- a/spatial/src/spatial/core/functions/table/st_generatepoints.cpp +++ b/spatial/src/spatial/core/functions/table/st_generatepoints.cpp @@ -79,8 +79,8 @@ static void Execute(ClientContext &context, TableFunctionInput &data_p, DataChun const auto chunk_size = MinValue(STANDARD_VECTOR_SIZE, bind_data.count - state.current_idx); for (idx_t i = 0; i < chunk_size; i++) { - x_data[i] = state.rng.NextRandom(bind_data.bbox.min.x, bind_data.bbox.max.x); - y_data[i] = state.rng.NextRandom(bind_data.bbox.min.y, bind_data.bbox.max.y); + x_data[i] = state.rng.NextRandom32(bind_data.bbox.min.x, bind_data.bbox.max.x); + y_data[i] = state.rng.NextRandom32(bind_data.bbox.min.y, bind_data.bbox.max.y); state.current_idx++; } diff --git a/spatial/src/spatial/core/index/rtree/rtree_index_plan_scan.cpp b/spatial/src/spatial/core/index/rtree/rtree_index_plan_scan.cpp index 65f5c189..23ddb2d6 100644 --- a/spatial/src/spatial/core/index/rtree/rtree_index_plan_scan.cpp +++ b/spatial/src/spatial/core/index/rtree/rtree_index_plan_scan.cpp @@ -46,7 +46,7 @@ class RTreeIndexScanOptimizer : public OptimizerExtension { column_t referenced_column = column_ids[bound_colref.binding.column_index]; // search for the referenced column in the set of column_ids for (idx_t i = 0; i < get_column_ids.size(); i++) { - if (get_column_ids[i] == referenced_column) { + if (get_column_ids[i].GetPrimaryIndex() == referenced_column) { bound_colref.binding.column_index = i; return; } @@ -213,7 +213,7 @@ class RTreeIndexScanOptimizer : public OptimizerExtension { auto &type = get.returned_types[column_id]; bool found = false; for (idx_t i = 0; i < column_ids.size(); i++) { - if (column_ids[i] == column_id) { + if (column_ids[i].GetPrimaryIndex() == column_id) { column_id = i; found = true; break; diff --git a/spatial/src/spatial/core/index/rtree/rtree_index_scan.cpp b/spatial/src/spatial/core/index/rtree/rtree_index_scan.cpp index 01f2966a..101ac45d 100644 --- a/spatial/src/spatial/core/index/rtree/rtree_index_scan.cpp +++ b/spatial/src/spatial/core/index/rtree/rtree_index_scan.cpp @@ -31,7 +31,7 @@ BindInfo RTreeIndexScanBindInfo(const optional_ptr bind_data_p) { struct RTreeIndexScanGlobalState : public GlobalTableFunctionState { ColumnFetchState fetch_state; TableScanState local_storage_state; - vector column_ids; + vector column_ids; // Index scan state unique_ptr index_state; @@ -54,7 +54,7 @@ static unique_ptr RTreeIndexScanInitGlobal(ClientConte if (id != DConstants::INVALID_INDEX) { col_id = bind_data.table.GetColumn(LogicalIndex(id)).StorageOid(); } - result->column_ids.push_back(col_id); + result->column_ids.emplace_back(col_id); } // Initialize the storage scan state @@ -128,9 +128,13 @@ unique_ptr RTreeIndexScanCardinality(ClientContext &context, con //------------------------------------------------------------------------- // ToString //------------------------------------------------------------------------- -static string RTreeIndexScanToString(const FunctionData *bind_data_p) { - auto &bind_data = bind_data_p->Cast(); - return bind_data.table.name + " (RTREE INDEX SCAN : " + bind_data.index.GetIndexName() + ")"; +static InsertionOrderPreservingMap RTreeIndexScanToString(TableFunctionToStringInput &input) { + D_ASSERT(input.bind_data); + InsertionOrderPreservingMap result; + auto &bind_data = input.bind_data->Cast(); + result["Table"] = bind_data.table.name; + result["Index"] = bind_data.index.GetIndexName(); + return result; } //------------------------------------------------------------------------- @@ -205,7 +209,6 @@ TableFunction RTreeIndexScanFunction::GetFunction() { func.pushdown_complex_filter = nullptr; func.to_string = RTreeIndexScanToString; func.table_scan_progress = nullptr; - func.get_batch_index = nullptr; func.projection_pushdown = true; func.filter_pushdown = false; func.get_bind_info = RTreeIndexScanBindInfo; diff --git a/spatial/src/spatial/core/io/osm/st_read_osm.cpp b/spatial/src/spatial/core/io/osm/st_read_osm.cpp index 465cb872..5aa49ddb 100644 --- a/spatial/src/spatial/core/io/osm/st_read_osm.cpp +++ b/spatial/src/spatial/core/io/osm/st_read_osm.cpp @@ -836,10 +836,12 @@ static double Progress(ClientContext &context, const FunctionData *bind_data, return state.GetProgress(); } -static idx_t GetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, - LocalTableFunctionState *local_state, GlobalTableFunctionState *global_state) { - auto &state = (LocalState &)*local_state; - return state.block->block_idx; +static OperatorPartitionData GetPartitionData(ClientContext &context, TableFunctionGetPartitionInput &input) { + if (input.partition_info.RequiresPartitionColumns()) { + throw InternalException("ST_ReadOSM::GetPartitionData: partition columns not supported"); + } + auto &state = input.local_state->Cast(); + return OperatorPartitionData(state.block->block_idx); } static unique_ptr ReadOsmPBFReplacementScan(ClientContext &context, ReplacementScanInput &input, @@ -898,7 +900,7 @@ static constexpr const char *DOC_EXAMPLE = R"( void CoreTableFunctions::RegisterOsmTableFunction(DatabaseInstance &db) { TableFunction read("ST_ReadOSM", {LogicalType::VARCHAR}, Execute, Bind, InitGlobal, InitLocal); - read.get_batch_index = GetBatchIndex; + read.get_partition_data = GetPartitionData; read.table_scan_progress = Progress; ExtensionUtil::RegisterFunction(db, read); diff --git a/spatial/src/spatial/gdal/functions/st_read.cpp b/spatial/src/spatial/gdal/functions/st_read.cpp index 9bd92e80..600fad8c 100644 --- a/spatial/src/spatial/gdal/functions/st_read.cpp +++ b/spatial/src/spatial/gdal/functions/st_read.cpp @@ -675,7 +675,7 @@ void GdalTableFunction::Register(DatabaseInstance &db) { GdalTableFunction::InitGlobal, GdalTableFunction::InitLocal); scan.cardinality = GdalTableFunction::Cardinality; - scan.get_batch_index = ArrowTableFunction::ArrowGetBatchIndex; + scan.get_partition_data = ArrowTableFunction::ArrowGetPartitionData; scan.projection_pushdown = true; scan.filter_pushdown = true; diff --git a/spatial/src/spatial/geos/functions/aggregate.cpp b/spatial/src/spatial/geos/functions/aggregate.cpp index aacc6682..d4aec18b 100644 --- a/spatial/src/spatial/geos/functions/aggregate.cpp +++ b/spatial/src/spatial/geos/functions/aggregate.cpp @@ -197,8 +197,9 @@ void GeosAggregateFunctions::Register(DatabaseInstance &db) { AggregateFunctionSet st_intersection_agg("ST_Intersection_Agg"); st_intersection_agg.AddFunction( - AggregateFunction::UnaryAggregateDestructor( - core::GeoTypes::GEOMETRY(), core::GeoTypes::GEOMETRY())); + AggregateFunction::UnaryAggregateDestructor(core::GeoTypes::GEOMETRY(), + core::GeoTypes::GEOMETRY())); ExtensionUtil::RegisterFunction(db, st_intersection_agg); DocUtil::AddDocumentation(db, "ST_Intersection_Agg", INTERSECTION_DOC_DESCRIPTION, INTERSECTION_DOC_EXAMPLE, @@ -206,8 +207,9 @@ void GeosAggregateFunctions::Register(DatabaseInstance &db) { AggregateFunctionSet st_union_agg("ST_Union_Agg"); st_union_agg.AddFunction( - AggregateFunction::UnaryAggregateDestructor( - core::GeoTypes::GEOMETRY(), core::GeoTypes::GEOMETRY())); + AggregateFunction::UnaryAggregateDestructor(core::GeoTypes::GEOMETRY(), + core::GeoTypes::GEOMETRY())); ExtensionUtil::RegisterFunction(db, st_union_agg); DocUtil::AddDocumentation(db, "ST_Union_Agg", UNION_DOC_DESCRIPTION, UNION_DOC_EXAMPLE, DOC_TAGS); diff --git a/spatial/src/spatial/geos/functions/scalar/st_buffer.cpp b/spatial/src/spatial/geos/functions/scalar/st_buffer.cpp index 9d5730db..05833550 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_buffer.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_buffer.cpp @@ -130,9 +130,8 @@ void GEOSScalarFunctions::RegisterStBuffer(DatabaseInstance &db) { GEOSFunctionLocalState::Init)); ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_Buffer", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); - DocUtil::AddFunctionParameterNames(db, "ST_Buffer", - {"geom", "distance", "num_triangles", "join_style", "cap_style", "mitre_limit"}); + DocUtil::AddDocumentation(db, "ST_Buffer", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS, + {"geom", "distance", "num_triangles", "join_style", "cap_style", "mitre_limit"}); } } // namespace geos diff --git a/spatial/src/spatial/geos/functions/scalar/st_contains.cpp b/spatial/src/spatial/geos/functions/scalar/st_contains.cpp index 984efb83..92d81bd5 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_contains.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_contains.cpp @@ -9,6 +9,8 @@ #include "duckdb/common/vector_operations/unary_executor.hpp" #include "duckdb/common/vector_operations/binary_executor.hpp" +#include "spatial/core/function_builder.hpp" + namespace spatial { namespace geos { @@ -37,18 +39,28 @@ select st_contains('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'::geometry, 'POINT(0.5 0. true )"; -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "relation"}}; //------------------------------------------------------------------------------ // Register functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStContains(DatabaseInstance &db) { - ScalarFunctionSet set("ST_Contains"); - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, LogicalType::BOOLEAN, ContainsFunction, - nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); + FunctionBuilder::RegisterScalar(db, "ST_Contains", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(ContainsFunction); + variant.SetInit(GEOSFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetDescription(DOC_DESCRIPTION); - ExtensionUtil::AddFunctionOverload(db, set); - DocUtil::AddDocumentation(db, "ST_Contains", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + func.SetTag("ext", "spatial"); + func.SetTag("category", "relation"); + }); } } // namespace geos diff --git a/spatial/src/spatial/geos/functions/scalar/st_containsproperly.cpp b/spatial/src/spatial/geos/functions/scalar/st_containsproperly.cpp index 9ab116bf..d913579e 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_containsproperly.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_containsproperly.cpp @@ -1,13 +1,14 @@ +#include "duckdb/common/vector_operations/binary_executor.hpp" +#include "duckdb/common/vector_operations/unary_executor.hpp" +#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "spatial/common.hpp" #include "spatial/core/types.hpp" -#include "spatial/geos/functions/scalar.hpp" #include "spatial/geos/functions/common.hpp" -#include "spatial/geos/geos_wrappers.hpp" +#include "spatial/geos/functions/scalar.hpp" #include "spatial/geos/geos_executor.hpp" +#include "spatial/geos/geos_wrappers.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/common/vector_operations/binary_executor.hpp" +#include "spatial/core/function_builder.hpp" namespace spatial { @@ -62,30 +63,28 @@ static constexpr const char *DOC_DESCRIPTION = R"( static constexpr const char *DOC_EXAMPLE = R"( )"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "relation"}}; //------------------------------------------------------------------------------ // Register functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStContainsProperly(DatabaseInstance &db) { - ScalarFunctionSet set("ST_ContainsProperly"); + FunctionBuilder::RegisterScalar(db, "ST_ContainsProperly", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(ContainsProperlyFunction); + variant.SetInit(GEOSFunctionLocalState::Init); - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, LogicalType::BOOLEAN, - ContainsProperlyFunction, nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_ContainsProperly", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + func.SetTag("ext", "spatial"); + func.SetTag("category", "relation"); + }); } } // namespace geos } // namespace spatial - -/* - -ST_Within( -ST_GeomFromText('POLYGON((339 346, 459 346, 399 311, 340 277, 399 173, 280 242, 339 415, 280 381, 460 207, 339 346))'), -ST_GeomFromText('POLYGON((339 207, 280 311, 460 138, 399 242, 459 277, 459 415, 399 381, 519 311, 520 242, 519 173, 399 -450, 339 207))')); -*/ \ No newline at end of file diff --git a/spatial/src/spatial/geos/functions/scalar/st_covered_by.cpp b/spatial/src/spatial/geos/functions/scalar/st_covered_by.cpp index 24887ab1..19373527 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_covered_by.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_covered_by.cpp @@ -4,6 +4,7 @@ #include "spatial/geos/functions/common.hpp" #include "spatial/geos/geos_wrappers.hpp" #include "spatial/geos/geos_executor.hpp" +#include "spatial/core/function_builder.hpp" #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" @@ -31,23 +32,27 @@ static constexpr const char *DOC_DESCRIPTION = R"( Returns true if geom1 is "covered" by geom2 )"; -static constexpr const char *DOC_EXAMPLE = R"( - -)"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "relation"}}; +static constexpr const char *DOC_EXAMPLE = R"()"; //------------------------------------------------------------------------------ // Register functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStCoveredBy(DatabaseInstance &db) { - ScalarFunctionSet set("ST_CoveredBy"); - - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, LogicalType::BOOLEAN, - CoveredByFunction, nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); - - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_CoveredBy", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_CoveredBy", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(CoveredByFunction); + variant.SetInit(GEOSFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "relation"); + }); } } // namespace geos diff --git a/spatial/src/spatial/geos/functions/scalar/st_covers.cpp b/spatial/src/spatial/geos/functions/scalar/st_covers.cpp index 532621a6..61dd0e47 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_covers.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_covers.cpp @@ -4,6 +4,7 @@ #include "spatial/geos/functions/common.hpp" #include "spatial/geos/geos_wrappers.hpp" #include "spatial/geos/geos_executor.hpp" +#include "spatial/core/function_builder.hpp" #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" @@ -32,20 +33,26 @@ static constexpr const char *DOC_DESCRIPTION = R"( )"; static constexpr const char *DOC_EXAMPLE = R"()"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "relation"}}; //------------------------------------------------------------------------------ // Register functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStCovers(DatabaseInstance &db) { - ScalarFunctionSet set("ST_Covers"); - - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, LogicalType::BOOLEAN, CoversFunction, - nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); - - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_Covers", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_Covers", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(CoversFunction); + variant.SetInit(GEOSFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "relation"); + }); } } // namespace geos diff --git a/spatial/src/spatial/geos/functions/scalar/st_crosses.cpp b/spatial/src/spatial/geos/functions/scalar/st_crosses.cpp index aca1c98a..de78bb4e 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_crosses.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_crosses.cpp @@ -4,6 +4,7 @@ #include "spatial/geos/functions/common.hpp" #include "spatial/geos/geos_wrappers.hpp" #include "spatial/geos/geos_executor.hpp" +#include "spatial/core/function_builder.hpp" #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" @@ -31,23 +32,27 @@ static constexpr const char *DOC_DESCRIPTION = R"( Returns true if geom1 "crosses" geom2 )"; -static constexpr const char *DOC_EXAMPLE = R"( - -)"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "relation"}}; +static constexpr const char *DOC_EXAMPLE = R"()"; //------------------------------------------------------------------------------ // Register functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStCrosses(DatabaseInstance &db) { - ScalarFunctionSet set("ST_Crosses"); - - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, LogicalType::BOOLEAN, CrossesFunction, - nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); - - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_Crosses", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_Crosses", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(CrossesFunction); + variant.SetInit(GEOSFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "relation"); + }); } } // namespace geos diff --git a/spatial/src/spatial/geos/functions/scalar/st_intersection.cpp b/spatial/src/spatial/geos/functions/scalar/st_intersection.cpp index ea080f39..e833a178 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_intersection.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_intersection.cpp @@ -1,12 +1,12 @@ +#include "duckdb/common/vector_operations/binary_executor.hpp" +#include "duckdb/common/vector_operations/unary_executor.hpp" +#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "spatial/common.hpp" #include "spatial/core/types.hpp" -#include "spatial/geos/functions/scalar.hpp" #include "spatial/geos/functions/common.hpp" +#include "spatial/geos/functions/scalar.hpp" #include "spatial/geos/geos_wrappers.hpp" - -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/common/vector_operations/binary_executor.hpp" +#include "spatial/core/function_builder.hpp" namespace spatial { @@ -34,23 +34,27 @@ static constexpr const char *DOC_DESCRIPTION = R"( Returns the "intersection" of geom1 and geom2 )"; -static constexpr const char *DOC_EXAMPLE = R"( - -)"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "relation"}}; +static constexpr const char *DOC_EXAMPLE = R"()"; //------------------------------------------------------------------------------ // Register Functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStIntersection(DatabaseInstance &db) { - ScalarFunctionSet set("ST_Intersection"); - - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, GeoTypes::GEOMETRY(), - IntersectionFunction, nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); - - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_Intersection", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_Intersection", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(GeoTypes::GEOMETRY()); + variant.SetFunction(IntersectionFunction); + variant.SetInit(GEOSFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "relation"); + }); } } // namespace geos diff --git a/spatial/src/spatial/geos/functions/scalar/st_overlaps.cpp b/spatial/src/spatial/geos/functions/scalar/st_overlaps.cpp index acc408ce..9e46e31c 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_overlaps.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_overlaps.cpp @@ -4,10 +4,7 @@ #include "spatial/geos/functions/common.hpp" #include "spatial/geos/geos_wrappers.hpp" #include "spatial/geos/geos_executor.hpp" - -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/common/vector_operations/binary_executor.hpp" +#include "spatial/core/function_builder.hpp" namespace spatial { @@ -31,24 +28,27 @@ static constexpr const char *DOC_DESCRIPTION = R"( Returns true if geom1 "overlaps" geom2 )"; -static constexpr const char *DOC_EXAMPLE = R"( - -)"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "relation"}}; +static constexpr const char *DOC_EXAMPLE = R"()"; //------------------------------------------------------------------------------ // Register Functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStOverlaps(DatabaseInstance &db) { - - ScalarFunctionSet set("ST_Overlaps"); - - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, LogicalType::BOOLEAN, OverlapsFunction, - nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); - - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_Overlaps", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_Overlaps", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(OverlapsFunction); + variant.SetInit(GEOSFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "relation"); + }); } } // namespace geos diff --git a/spatial/src/spatial/geos/functions/scalar/st_shortestline.cpp b/spatial/src/spatial/geos/functions/scalar/st_shortestline.cpp index e6deedfc..2b329204 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_shortestline.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_shortestline.cpp @@ -1,10 +1,10 @@ #include "spatial/common.hpp" #include "spatial/core/types.hpp" +#include "spatial/core/function_builder.hpp" #include "spatial/geos/functions/scalar.hpp" #include "spatial/geos/functions/common.hpp" #include "spatial/geos/geos_wrappers.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "duckdb/common/vector_operations/binary_executor.hpp" namespace spatial { @@ -38,20 +38,26 @@ static constexpr const char *DOC_DESCRIPTION = R"( static constexpr const char *DOC_EXAMPLE = R"( )"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "construction"}}; //------------------------------------------------------------------------------ // Register Functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStShortestLine(DatabaseInstance &db) { - ScalarFunctionSet set("ST_ShortestLine"); - - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, GeoTypes::GEOMETRY(), - ShortestLineFunction, nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); - - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_ShortestLine", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_ShortestLine", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(GeoTypes::GEOMETRY()); + variant.SetFunction(ShortestLineFunction); + variant.SetInit(GEOSFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "construction"); + }); } } // namespace geos diff --git a/spatial/src/spatial/geos/functions/scalar/st_touches.cpp b/spatial/src/spatial/geos/functions/scalar/st_touches.cpp index 178efa63..6dc79e15 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_touches.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_touches.cpp @@ -1,14 +1,12 @@ #include "spatial/common.hpp" #include "spatial/core/types.hpp" +#include "spatial/core/function_builder.hpp" + #include "spatial/geos/functions/scalar.hpp" #include "spatial/geos/functions/common.hpp" #include "spatial/geos/geos_wrappers.hpp" #include "spatial/geos/geos_executor.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/common/vector_operations/binary_executor.hpp" - namespace spatial { namespace geos { @@ -32,21 +30,25 @@ Returns true if geom1 "touches" geom2 )"; static constexpr const char *DOC_EXAMPLE = R"()"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "relation"}}; -; //------------------------------------------------------------------------------ // Register Functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStTouches(DatabaseInstance &db) { - - ScalarFunctionSet set("ST_Touches"); - - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, LogicalType::BOOLEAN, TouchesFunction, - nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); - - ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_Touches", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_Touches", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(TouchesFunction); + variant.SetInit(GEOSFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "relation"); + }); } } // namespace geos diff --git a/spatial/src/spatial/geos/functions/scalar/st_within.cpp b/spatial/src/spatial/geos/functions/scalar/st_within.cpp index 93386d45..69e1d2e6 100644 --- a/spatial/src/spatial/geos/functions/scalar/st_within.cpp +++ b/spatial/src/spatial/geos/functions/scalar/st_within.cpp @@ -1,14 +1,11 @@ #include "spatial/common.hpp" #include "spatial/core/types.hpp" +#include "spatial/core/function_builder.hpp" #include "spatial/geos/functions/scalar.hpp" #include "spatial/geos/functions/common.hpp" #include "spatial/geos/geos_wrappers.hpp" #include "spatial/geos/geos_executor.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/common/vector_operations/binary_executor.hpp" - namespace spatial { namespace geos { @@ -32,19 +29,25 @@ static constexpr const char *DOC_DESCRIPTION = R"( )"; static constexpr const char *DOC_EXAMPLE = R"()"; - -static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "relation"}}; //------------------------------------------------------------------------------ // Register Functions //------------------------------------------------------------------------------ void GEOSScalarFunctions::RegisterStWithin(DatabaseInstance &db) { - ScalarFunctionSet set("ST_Within"); - - set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), GeoTypes::GEOMETRY()}, LogicalType::BOOLEAN, WithinFunction, - nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); - - ExtensionUtil::AddFunctionOverload(db, set); - DocUtil::AddDocumentation(db, "ST_Within", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); + FunctionBuilder::RegisterScalar(db, "ST_Within", [](ScalarFunctionBuilder &func) { + func.AddVariant([](ScalarFunctionVariantBuilder &variant) { + variant.AddParameter("geom1", GeoTypes::GEOMETRY()); + variant.AddParameter("geom2", GeoTypes::GEOMETRY()); + variant.SetReturnType(LogicalType::BOOLEAN); + variant.SetFunction(WithinFunction); + variant.SetInit(GEOSFunctionLocalState::Init); + + variant.SetExample(DOC_EXAMPLE); + variant.SetDescription(DOC_DESCRIPTION); + }); + + func.SetTag("ext", "spatial"); + func.SetTag("category", "relation"); + }); } } // namespace geos diff --git a/spatial/src/spatial/proj/functions.cpp b/spatial/src/spatial/proj/functions.cpp index 7baf0e4a..9a7b962c 100644 --- a/spatial/src/spatial/proj/functions.cpp +++ b/spatial/src/spatial/proj/functions.cpp @@ -510,12 +510,11 @@ void ProjFunctions::Register(DatabaseInstance &db) { GeometryTransformFunction, TransformBind, nullptr, nullptr, ProjFunctionLocalState::Init)); ExtensionUtil::RegisterFunction(db, set); - DocUtil::AddDocumentation(db, "ST_Transform", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS); - DocUtil::AddFunctionParameterNames(db, "ST_Transform", {"geom", "source_crs", "target_crs", "always_xy"}); - + DocUtil::AddDocumentation(db, "ST_Transform", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS, + {"geom", "source_crs", "target_crs", "always_xy"}); GenerateSpatialRefSysTable::Register(db); } } // namespace proj -} // namespace spatial \ No newline at end of file +} // namespace spatial diff --git a/spatial/src/spatial_extension.cpp b/spatial/src/spatial_extension.cpp index d07319f1..f5839843 100644 --- a/spatial/src/spatial_extension.cpp +++ b/spatial/src/spatial_extension.cpp @@ -53,7 +53,8 @@ static string RemoveIndentAndTrailingWhitespace(const char *text) { void spatial::DocUtil::AddDocumentation(duckdb::DatabaseInstance &db, const char *function_name, const char *description, const char *example, - const duckdb::unordered_map &tags) { + const duckdb::unordered_map &tags, + duckdb::vector parameter_names) { auto &system_catalog = Catalog::GetSystemCatalog(db); auto data = CatalogTransaction::GetSystemTransaction(db); @@ -73,40 +74,22 @@ void spatial::DocUtil::AddDocumentation(duckdb::DatabaseInstance &db, const char } auto &func_entry = catalog_entry->Cast(); + FunctionDescription func_description; if (description != nullptr) { - func_entry.description = RemoveIndentAndTrailingWhitespace(description); + func_description.description = RemoveIndentAndTrailingWhitespace(description); } if (example != nullptr) { - func_entry.example = RemoveIndentAndTrailingWhitespace(example); + func_description.examples.push_back(RemoveIndentAndTrailingWhitespace(example)); } + if (!parameter_names.empty()) { + func_description.parameter_names = std::move(parameter_names); + } + func_entry.descriptions.push_back(std::move(func_description)); if (!tags.empty()) { func_entry.tags = tags; } } -void spatial::DocUtil::AddFunctionParameterNames(duckdb::DatabaseInstance &db, const char *function_name, - duckdb::vector names) { - auto &system_catalog = Catalog::GetSystemCatalog(db); - auto data = CatalogTransaction::GetSystemTransaction(db); - auto &schema = system_catalog.GetSchema(data, DEFAULT_SCHEMA); - auto catalog_entry = schema.GetEntry(data, CatalogType::SCALAR_FUNCTION_ENTRY, function_name); - if (!catalog_entry) { - // Try get a aggregate function - catalog_entry = schema.GetEntry(data, CatalogType::AGGREGATE_FUNCTION_ENTRY, function_name); - if (!catalog_entry) { - // Try get a table function - catalog_entry = schema.GetEntry(data, CatalogType::TABLE_FUNCTION_ENTRY, function_name); - if (!catalog_entry) { - throw duckdb::InvalidInputException("Function with name \"%s\" not found in DocUtil::AddDocumentation", - function_name); - } - } - } - - auto &func_entry = catalog_entry->Cast(); - func_entry.parameter_names = std::move(names); -} - namespace duckdb { static void LoadInternal(DatabaseInstance &instance) { diff --git a/vcpkg.json b/vcpkg.json index 0fa0cf26..282efc0f 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,5 +1,8 @@ { - "dependencies": [ - "openssl" - ] + "dependencies": [ + "openssl", + "zlib", + "geographiclib", + "geos" + ] }