diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..ed0c3ce --- /dev/null +++ b/.clang-format @@ -0,0 +1,38 @@ +--- +BasedOnStyle: LLVM +TabWidth: 4 +IndentWidth: 4 +ColumnLimit: 120 +AllowShortFunctionsOnASingleLine: false +--- +UseTab: ForIndentation +DerivePointerAlignment: false +PointerAlignment: Right +AlignConsecutiveMacros: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AlwaysBreakAfterReturnType: AllDefinitions +AlignAfterOpenBracket: Align +BracedInitializerIndentWidth: 4 +IncludeBlocks: Preserve +IncludeCategories: # we want to ensure postgres.h appear first + - Regex: '^"postgres\.h"' + Priority: -2 + - Regex: '^"c\.h"' + Priority: -1 +IncludeIsMainRegex: '' +KeepEmptyLinesAtTheStartOfBlocks: true +SortIncludes: false +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +AllowShortLambdasOnASingleLine: Inline +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: Yes +Language: Cpp +AccessModifierOffset: -4 \ No newline at end of file diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..c154026 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,6 @@ +--- +Checks: '-*,clang-analyzer-core.*,clang-diagnostic-*' +WarningsAsErrors: 'clang-analyzer-unix.*,clang-analyzer-core.NullDereference' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff4f63 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.clangd +.depend + +.vscode +.ccls +compile_commands.json + +build/ + +*.a +*.so +*.o +*.bc +*.dylib + +results \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..aac2855 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "third_party/duckdb"] + path = third_party/duckdb + url = https://github.com/duckdb/duckdb.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a59a4ca --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,197 @@ +set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE) +cmake_minimum_required(VERSION 3.2 FATAL_ERROR) + +if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "In-source builds not allowed. + Please make a new directory and run CMake from there. + You may need to remove CMakeCache.txt." ) +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +# Build Type - set a default build type `Release` if none was specified +set(PROJECT_DEFAULT_BUILD_TYPE "Release") + +if (CMAKE_BUILD_TYPE AND + NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|Release|RelWithDebInfo|MinSizeRel)$") + message(FATAL_ERROR "Invalid value for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE} + valid values are Debug|Release|RelWithDebInfo|MinSizeRel") +endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${PROJECT_DEFAULT_BUILD_TYPE}' as none was specified.") + set(CMAKE_BUILD_TYPE "${PROJECT_DEFAULT_BUILD_TYPE}" CACHE + STRING "Choose the type of build." FORCE) +endif() + +message(STATUS "CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}") + +project(quack VERSION 0.0.1 LANGUAGES C CXX) + +string(TOLOWER "${PROJECT_NAME}" PROJECT_NAME_LOWER) + +set(PROJECT_LIB_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") +set(PROJECT_LIB_NAME "${PROJECT_NAME_LOWER}") + +string(TIMESTAMP COMPILATION_DATE "%Y/%m/%d" UTC) + +set(POSTGRESQL_MINIMUM_VERSION "16.0.0") +set(BOOST_MINIMUM_VERSION "1.81.0") + +message(STATUS "POSTGRESQL_MINIMUM_VERSION=${POSTGRESQL_MINIMUM_VERSION}") +message(STATUS "BOOST_MINIMUM_VERSION=${BOOST_MINIMUM_VERSION}") + +# PostgreSQL + +find_package(PostgreSQL) + +if(NOT PostgreSQL_FOUND OR NOT PostgreSQL_VERSION_STRING) + message(FATAL_ERROR "PostgreSQL not found - Please check your PostgreSQL installation.") +endif() + +# for XbetaY XalphaY XrcY -> X.Y +string(REGEX REPLACE "([0-9]+)[beta|alpha|rc|devel].*" "\\1.0" POSTGRESQL_VERSION_STRING ${PostgreSQL_VERSION_STRING}) +STRING(REGEX MATCH "([0-9]+)\.([0-9]+)" POSTGRESQL_VERSION "${PostgreSQL_VERSION_STRING}") + +#for X.Y.Z -> XY Y<10 +string(REGEX REPLACE "^([0-9]+)\\.([0-9]+).*" "\\1\\2" PGSQL_VERSION ${POSTGRESQL_VERSION}) + +if("${POSTGRESQL_VERSION}" VERSION_LESS "${POSTGRESQL_MINIMUM_VERSION}") + message(FATAL_ERROR " PostgreSQL ${POSTGRESQL_MINIMUM_VERSION} or greater is required.") +endif("${POSTGRESQL_VERSION}" VERSION_LESS "${POSTGRESQL_MINIMUM_VERSION}") + +include_directories(${PostgreSQL_SERVER_INCLUDE_DIRS}) + +# For Apple and Postgres 16 use .dylib instead of .so +if (APPLE AND POSTGRESQL_VERSION VERSION_GREATER_EQUAL "16") + set(CMAKE_SHARED_MODULE_SUFFIX ".dylib") +endif() + +# Boost + +find_package(Boost ${BOOST_MINIMUM_VERSION} REQUIRED) + +if (NOT Boost_VERSION_MACRO) + set(Boost_VERSION_MACRO ${Boost_VERSION}) +endif() + +set(BOOST_VERSION "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") + +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) + +add_definitions(-DBOOST_ALLOW_DEPRECATED_HEADERS) + +# Third party libs + +include(third_party/third_party.cmake) + +# Compiler + +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) +set(CMAKE_CXX_STANDARD 17) + +set(COMPILER_VERSION "${CMAKE_CXX_COMPILER_ID}-${CMAKE_CXX_COMPILER_VERSION}") + +#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# compiler directives +#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# https://www.postgresql.org/docs/10/xfunc-c.html + + +CHECK_C_COMPILER_FLAG("-fPIC" C_COMPILER_SUPPORTS_FPIC) +CHECK_CXX_COMPILER_FLAG("-fPIC" CXX_COMPILER_SUPPORTS_FPIC) + +if(C_COMPILER_SUPPORTS_FPIC) + set(CMAKE_C_FLAGS "-fPIC") +endif() +if(CXX_COMPILER_SUPPORTS_FPIC) + set(CMAKE_CXX_FLAGS "-fPIC") +endif() + +message(STATUS "COMPILER: ${CMAKE_CXX_COMPILER_ID}") + +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + # Append CFLAGS/CXXFLAGS and PostgreSQL CFLAGS/CXXFAGS + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PostgreSQL_CFLAGS} $ENV{CFLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-register ${PostgreSQL_CXXFLAGS} $ENV{CXXFLAGS}") + + # Debug compiler flags + if(CMAKE_BUILD_TYPE MATCHES "Debug") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") + endif() + # Release compiler flags + if(CMAKE_BUILD_TYPE MATCHES "Release") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") + endif() +endif() + +message(STATUS "CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") +message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") + +# Include directory + +include_directories(${PROJECT_SOURCE_DIR}/include) + +# Source directories + +add_subdirectory("src") + +# Library + +set(LIBRARY_OUTPUT_PATH lib) +add_library(${PROJECT_LIB_NAME} MODULE ${PROJECT_OBJECTS}) + +message(STATUS "PROJECT_LIB_NAME ${PROJECT_LIB_NAME}") + +set(LINK_FLAGS "${PostgreSQL_SHARED_LINK_OPTIONS}") + +foreach(_dir ${PostgreSQL_SERVER_LIBRARY_DIRS}) + set(LINK_FLAGS "${LINK_FLAGS} -L${_dir}") +endforeach() + +if(APPLE) + set(LINK_FLAGS "${LINK_FLAGS} -bundle_loader ${PG_BINARY} -undefined dynamic_lookup") +endif() + +foreach (_third_party_lib ${QUACK_THIRD_PARTY_LIBS}) + target_link_libraries(${PROJECT_LIB_NAME} PUBLIC ${_third_party_lib}) +endforeach () + +set_target_properties(${PROJECT_LIB_NAME} + PROPERTIES PREFIX "" + LINK_FLAGS "${LINK_FLAGS} $ENV{LDFLAGS}") + +# PostgreSQL extension control and installation sql files + +add_subdirectory(sql) + +# Installation + +install(TARGETS ${PROJECT_LIB_NAME} DESTINATION ${PostgreSQL_PACKAGE_LIBRARY_DIR}) +install(FILES ${PROJECT_FILES_TO_INSTALL} DESTINATION "${PostgreSQL_EXTENSION_DIR}") + +# Install third party libraries + +foreach (_third_party_lib ${QUACK_THIRD_PARTY_LIBS}) + install(TARGETS ${_third_party_lib} DESTINATION ${PostgreSQL_PACKAGE_LIBRARY_DIR}) +endforeach () + +# Add regress test + +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + include(CTest) +endif() + +add_subdirectory("regress") + +# Copy compile-commands.json to ROOT + +if (CMAKE_EXPORT_COMPILE_COMMANDS) + add_custom_target(copy-compile-commands ALL + ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_BINARY_DIR}/compile_commands.json + ${PROJECT_SOURCE_DIR}) +endif() diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..5d26e6c --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# pg_quack + +pg_quack is PostgreSQL with Embedded DuckDB :duck: + +## Installation + +### With pgxman + +1. [Install pgxman](https://pgxman.com/) +1. `pgxman install pg_quack` + +### From source + +1. `make install` +1. (Optional) Create quack directory and set permissions so PostgreSQL process can write to it. + Directory can be changed with `quack.data_dir` configuration parameter. By default, the + directory is `quack` in your Postgres data directory. + +``` +postgres=# show quack.data_dir ; + quack.data_dir +------------------------------------ + /opt/database/postgres/data/quack/ +(1 row) +``` + +## Usage + +``` +CREATE TABLE quack_test (...) USING quack; +``` + +## Limitations + +* PG 14 and PG 15 only (PG 16 is not yet supported) +* Only COPY, INSERT, and SELECT are supported. +* Only single connection can execute INSERT and SELECT against quack table +* Limited support for only basic data types +* You cannot query between `quack` tables and other storage methods (including Postgres `heap` tables). diff --git a/cmake/FindPostgreSQL.cmake b/cmake/FindPostgreSQL.cmake new file mode 100644 index 0000000..1a9af2d --- /dev/null +++ b/cmake/FindPostgreSQL.cmake @@ -0,0 +1,189 @@ +# Copyright 2020 Mats Kindahl +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# .rst: FindPostgreSQL +# -------------------- +# +# Find the PostgreSQL installation. +# +# This module defines the following variables +# +# :: +# +# PostgreSQL_LIBRARIES - the PostgreSQL libraries needed for linking +# +# PostgreSQL_INCLUDE_DIRS - include directories +# +# PostgreSQL_SERVER_INCLUDE_DIRS - include directories for server programming +# +# PostgreSQL_LIBRARY_DIRS - link directories for PostgreSQL libraries +# +# PostgreSQL_EXTENSION_DIR - the directory for extensions +# +# PostgreSQL_SHARED_LINK_OPTIONS - options for shared libraries +# +# PostgreSQL_LINK_OPTIONS - options for static libraries and executables +# +# PostgreSQL_VERSION_STRING - the version of PostgreSQL found (since CMake +# 2.8.8) +# +# ---------------------------------------------------------------------------- +# History: This module is derived from the existing FindPostgreSQL.cmake and try +# to use most of the existing output variables of that module, but uses +# `pg_config` to extract the necessary information instead and add a macro for +# creating extensions. The use of `pg_config` is aligned with how the PGXS code +# distributed with PostgreSQL itself works. + +# Define additional search paths for root directories. +set(PostgreSQL_ROOT_DIRECTORIES ENV PGROOT ENV PGPATH ${PostgreSQL_ROOT}) + +if (DEFINED ENV{PG_CONFIG}) + set(PG_CONFIG "$ENV{PG_CONFIG}") +else() + find_program( + PG_CONFIG pg_config + PATHS ${PostgreSQL_ROOT_DIRECTORIES} + PATH_SUFFIXES bin) +endif() + +if(NOT PG_CONFIG) + message(FATAL_ERROR "Could not find pg_config") +else() + set(PostgreSQL_FOUND TRUE) +endif() + +message(STATUS "Found pg_config as ${PG_CONFIG}") + +if(PostgreSQL_FOUND) + macro(PG_CONFIG VAR OPT) + execute_process( + COMMAND ${PG_CONFIG} ${OPT} + OUTPUT_VARIABLE ${VAR} + OUTPUT_STRIP_TRAILING_WHITESPACE) + endmacro() + + pg_config(_pg_bindir --bindir) + pg_config(_pg_includedir --includedir) + pg_config(_pg_pkgincludedir --pkgincludedir) + pg_config(_pg_sharedir --sharedir) + pg_config(_pg_includedir_server --includedir-server) + pg_config(_pg_libs --libs) + pg_config(_pg_ldflags --ldflags) + pg_config(_pg_ldflags_sl --ldflags_sl) + pg_config(_pg_ldflags_ex --ldflags_ex) + pg_config(_pg_pkglibdir --pkglibdir) + pg_config(_pg_libdir --libdir) + pg_config(_pg_version --version) + pg_config(_pg_compileflags --configure) + pg_config(_pg_cflags --cflags) + pg_config(_pg_cflags_sl --cflags_sl) + pg_config(_pg_cxxflags --cppflags) + + separate_arguments(_pg_ldflags) + separate_arguments(_pg_ldflags_sl) + separate_arguments(_pg_ldflags_ex) + + set(_server_lib_dirs ${_pg_libdir} ${_pg_pkglibdir}) + set(_server_inc_dirs ${_pg_includedir_server} ${_pg_pkgincludedir}) + string(REPLACE ";" " " _shared_link_options + "${_pg_ldflags};${_pg_ldflags_sl}") + + + set(_link_options ${_pg_ldflags}) + if(_pg_ldflags_ex) + list(APPEND _link_options ${_pg_ldflags_ex}) + endif() + + string(FIND ${_pg_compileflags} "--with-llvm" _pg_with_llvm_idx) + + if(${_pg_with_llvm_idx} EQUAL -1) + set(_pg_with_llvm FALSE) + else() + set(_pg_with_llvm TRUE) + endif() + + set(PostgreSQL_INCLUDE_DIRS + "${_pg_includedir}" + CACHE PATH + "Top-level directory containing the PostgreSQL include directories." + ) + set(PostgreSQL_EXTENSION_DIR + "${_pg_sharedir}/extension" + CACHE PATH "Directory containing extension SQL and control files") + set(PostgreSQL_SERVER_INCLUDE_DIRS + "${_server_inc_dirs}" + CACHE PATH "PostgreSQL include directories for server include files.") + set(PostgreSQL_LIBRARY_DIRS + "${_pg_libdir}" + CACHE PATH "library directory for PostgreSQL") + set(PostgreSQL_LIBRARIES + "${_pg_libs}" + CACHE PATH "Libraries for PostgreSQL") + set(PostgreSQL_SHARED_LINK_OPTIONS + "${_shared_link_options}" + CACHE STRING "PostgreSQL linker options for shared libraries.") + set(PostgreSQL_LINK_OPTIONS + "${_pg_ldflags},${_pg_ldflags_ex}" + CACHE STRING "PostgreSQL linker options for executables.") + set(PostgreSQL_SERVER_LIBRARY_DIRS + "${_server_lib_dirs}" + CACHE PATH "PostgreSQL server library directories.") + set(PostgreSQL_VERSION_STRING + "${_pg_version}" + CACHE STRING "PostgreSQL version string") + set(PostgreSQL_PACKAGE_LIBRARY_DIR + "${_pg_pkglibdir}" + CACHE STRING "PostgreSQL package library directory") + set(PostgreSQL_WITH_LLVM + "${_pg_with_llvm}" + CACHE BOOL "PostgreSQL -with-llvm flag.") + set(PostgreSQL_CFLAGS + "${_pg_cflags}" + CACHE STRING "PostgreSQL CFLAGS") + set(PostgreSQL_CFLAGS_SL + "${_pg_cflags_sl}" + CACHE STRING "PostgreSQL CFLAGS_SL") + set(PostgreSQL_CXXFLAGS + "${_pg_cxxflags}" + CACHE STRING "PostgreSQL CXXFLAGS") + + find_program( + PG_BINARY postgres + PATHS ${PostgreSQL_ROOT_DIRECTORIES} + HINTS ${_pg_bindir} + PATH_SUFFIXES bin) + + if(NOT PG_BINARY) + message(FATAL_ERROR "Could not find postgres binary") + endif() + + message(STATUS "Found postgres binary at ${PG_BINARY}") + + find_program(PG_REGRESS pg_regress HINT + ${PostgreSQL_PACKAGE_LIBRARY_DIR}/pgxs/src/test/regress) + if(NOT PG_REGRESS) + message(STATUS "Could not find pg_regress, tests not executed") + endif() + + message(STATUS "PostgreSQL version: ${PostgreSQL_VERSION_STRING} found") + message( + STATUS + "PostgreSQL package library directory: ${PostgreSQL_PACKAGE_LIBRARY_DIR}") + message(STATUS "PostgreSQL libraries: ${PostgreSQL_LIBRARIES}") + message(STATUS "PostgreSQL extension directory: ${PostgreSQL_EXTENSION_DIR}") + message(STATUS "PostgreSQL linker options: ${PostgreSQL_LINK_OPTIONS}") + message( + STATUS "PostgreSQL shared linker options: ${PostgreSQL_SHARED_LINK_OPTIONS}" + ) +endif() \ No newline at end of file diff --git a/include/quack/quack.h b/include/quack/quack.h new file mode 100644 index 0000000..8be0d64 --- /dev/null +++ b/include/quack/quack.h @@ -0,0 +1,6 @@ +#pragma once + +void _PG_init(void); + +// quack_internal.cpp +const char * quack_duckdb_version(); \ No newline at end of file diff --git a/regress/CMakeLists.txt b/regress/CMakeLists.txt new file mode 100644 index 0000000..82cfa5f --- /dev/null +++ b/regress/CMakeLists.txt @@ -0,0 +1,15 @@ +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose) + +if(PG_REGRESS) + +add_test( + NAME regress + COMMAND ${PG_REGRESS} + --temp-config=${PROJECT_SOURCE_DIR}/regress/regress.conf + --temp-instance=${CMAKE_BINARY_DIR}/tmp + --inputdir=${PROJECT_SOURCE_DIR}/regress + --schedule=${PROJECT_SOURCE_DIR}/regress/schedule.conf + --load-extension=quack +) + +endif() \ No newline at end of file diff --git a/regress/expected/basic.out b/regress/expected/basic.out new file mode 100644 index 0000000..3255711 --- /dev/null +++ b/regress/expected/basic.out @@ -0,0 +1,2 @@ +CREATE TABLE t(a INT); +DROP TABLE t; diff --git a/regress/regress.conf b/regress/regress.conf new file mode 100644 index 0000000..f327aca --- /dev/null +++ b/regress/regress.conf @@ -0,0 +1,3 @@ +# Configuration + +log_temp_files = -1 \ No newline at end of file diff --git a/regress/schedule.conf b/regress/schedule.conf new file mode 100644 index 0000000..43a5f3e --- /dev/null +++ b/regress/schedule.conf @@ -0,0 +1 @@ +test: basic \ No newline at end of file diff --git a/regress/sql/basic.sql b/regress/sql/basic.sql new file mode 100644 index 0000000..27fc35c --- /dev/null +++ b/regress/sql/basic.sql @@ -0,0 +1,2 @@ +CREATE TABLE t(a INT); +DROP TABLE t; \ No newline at end of file diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt new file mode 100644 index 0000000..627c87b --- /dev/null +++ b/sql/CMakeLists.txt @@ -0,0 +1,2 @@ +file(GLOB SQL_FILES "${PROJECT_NAME_LOWER}--*") +SET(PROJECT_FILES_TO_INSTALL ${SQL_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME_LOWER}.control PARENT_SCOPE) diff --git a/sql/quack--0.0.1.sql b/sql/quack--0.0.1.sql new file mode 100644 index 0000000..87dee75 --- /dev/null +++ b/sql/quack--0.0.1.sql @@ -0,0 +1 @@ +CREATE SCHEMA quack; \ No newline at end of file diff --git a/sql/quack.control b/sql/quack.control new file mode 100644 index 0000000..0c89e84 --- /dev/null +++ b/sql/quack.control @@ -0,0 +1,4 @@ +comment = 'DuckDB Embedded in Postgres' +default_version = '0.0.1' +module_pathname = '$libdir/quack' +relocatable = false diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..7d7c870 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,4 @@ +ADD_LIBRARY(extension OBJECT quack.c + quack_internal.cpp) + +set(PROJECT_OBJECTS ${PROJECT_OBJECTS} "$" PARENT_SCOPE) diff --git a/src/quack.c b/src/quack.c new file mode 100644 index 0000000..cacbcea --- /dev/null +++ b/src/quack.c @@ -0,0 +1,21 @@ +#include "postgres.h" + +#include "utils/guc.h" + +#include "quack/quack.h" + +PG_MODULE_MAGIC; + +static void quack_init_guc(void); + +void +_PG_init(void) { + quack_init_guc(); + elog(WARNING, "DuckDB version %s", quack_duckdb_version()); +} + +/* clang-format off */ +static void +quack_init_guc(void) { + +} diff --git a/src/quack_internal.cpp b/src/quack_internal.cpp new file mode 100644 index 0000000..5ff0a6a --- /dev/null +++ b/src/quack_internal.cpp @@ -0,0 +1,6 @@ +#include "duckdb.hpp" + +extern "C" const char * +quack_duckdb_version() { + return duckdb::DuckDB::LibraryVersion(); +} \ No newline at end of file diff --git a/third_party/duckdb b/third_party/duckdb new file mode 160000 index 0000000..8ef134f --- /dev/null +++ b/third_party/duckdb @@ -0,0 +1 @@ +Subproject commit 8ef134fa0e855ad0cd9d03af0f8907a6adab8718 diff --git a/third_party/third_party.cmake b/third_party/third_party.cmake new file mode 100644 index 0000000..36ef483 --- /dev/null +++ b/third_party/third_party.cmake @@ -0,0 +1,25 @@ +if(POLICY CMP0077) + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) +endif() + +# +# duckdb +# +execute_process(COMMAND git submodule update --init -- third_party/duckdb + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# Disable ASAN +SET(ENABLE_SANITIZER OFF) +SET(ENABLE_UBSAN OFF) + +# No DuckDB cli +SET(BUILD_SHELL OFF) + +# Disable unitest +SET(BUILD_UNITTESTS OFF) + +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third_party/duckdb EXCLUDE_FROM_ALL) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/duckdb/src/include) + +SET(QUACK_THIRD_PARTY_LIBS duckdb) \ No newline at end of file