diff --git a/Makefile b/Makefile index affc1380..b49bdc64 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,8 @@ SRCS = src/quack_heap_scan.cpp \ src/quack_hooks.cpp \ src/quack_select.cpp \ src/quack_types.cpp \ - src/quack.cpp + src/quack.cpp \ + src/scanner.cpp OBJS = $(subst .cpp,.o, $(SRCS)) @@ -21,15 +22,17 @@ PG_LIB := $(shell $(PG_CONFIG) --pkglibdir) INCLUDEDIR := ${shell $(PG_CONFIG) --includedir} INCLUDEDIR_SERVER := ${shell $(PG_CONFIG) --includedir-server} +HEADERS := include/quack/scanner.hpp $(wildcard third_party/duckdb/src/include/*/*/*/*/*/*) + DEBUG_FLAGS = -g -O0 -fsanitize=address -override PG_CPPFLAGS += -Iinclude -Ithird_party/duckdb/src/include -std=c++17 +override PG_CPPFLAGS += -Iinclude -Ithird_party/duckdb/src/include -std=c++17 -rdynamic SHLIB_LINK += -Wl,-rpath,$(PG_LIB)/ -lpq -L$(PG_LIB) -lduckdb -Lthird_party/duckdb/build/debug/src -lstdc++ -COMPILE.cc.bc = $(CXX) -Wno-ignored-attributes -Wno-register $(BITCODE_CXXFLAGS) $(CXXFLAGS) $(PG_CPPFLAGS) -I$(INCLUDEDIR_SERVER) -emit-llvm -c +COMPILE.cpp.bc = $(CXX) -Wno-ignored-attributes -Wno-register $(BITCODE_CXXFLAGS) $(CXXFLAGS) $(PG_CPPFLAGS) -I$(INCLUDEDIR_SERVER) -emit-llvm -c %.bc : %.cpp - $(COMPILE.cc.bc) $(SHLIB_LINK) $(PG_CPPFLAGS) -I$(INCLUDE_SERVER) -o $@ $< + $(COMPILE.cpp.bc) $(SHLIB_LINK) $(PG_CPPFLAGS) -I$(INCLUDE_SERVER) -o $@ $< # determine the name of the duckdb library that is built UNAME_S := $(shell uname -s) @@ -40,12 +43,15 @@ ifeq ($(UNAME_S),Linux) DUCKDB_LIB = libduckdb.so endif -all: duckdb $(OBJS) +all: duckdb $(OBJS) heap.so include $(PGXS) duckdb: third_party/duckdb third_party/duckdb/build/debug/src/$(DUCKDB_LIB) +heap.so: + $(CXX) $(PG_CPPFLAGS) $(CPPFLAGS) -Wl,-rpath,$(PG_LIB)/ -std=c++17 -shared src/scanner/heap.cpp -undefined dynamic_lookup -o heap.so + third_party/duckdb: git submodule update --init --recursive @@ -58,8 +64,19 @@ install_duckdb: clean_duckdb: rm -rf third_party/duckdb/build -install: install_duckdb -clean: clean_duckdb +install_heap_scanner: + $(install_bin) -m 755 heap.so $(DESTDIR)$(PG_LIB) + +install: install_duckdb install_heap_scanner + +clean_heap_so: + rm -f heap.so + +clean_depend: + rm -f .depend + +clean: clean_duckdb clean_heap_so clean_depend + lintcheck: clang-tidy $(SRCS) -- -I$(INCLUDEDIR) -I$(INCLUDEDIR_SERVER) -Iinclude $(CPPFLAGS) -std=c++17 diff --git a/include/quack/quack.h b/include/quack/quack.h index d98ff3e7..a592fd3d 100644 --- a/include/quack/quack.h +++ b/include/quack/quack.h @@ -1,7 +1,12 @@ #pragma once +#include + // quack.c extern "C" void _PG_init(void); // quack_hooks.c -extern void quack_init_hooks(void); \ No newline at end of file +extern void quack_init_hooks(void); + +// scanner.cpp +void load_scanner(std::string name); diff --git a/include/quack/scanner.hpp b/include/quack/scanner.hpp new file mode 100644 index 00000000..cb362562 --- /dev/null +++ b/include/quack/scanner.hpp @@ -0,0 +1,28 @@ +#pragma once + +extern "C" { +#include "postgres.h" + +#include "utils/relcache.h" +} + +#include +#include + +class Scanner { +public: + static Scanner *SetupScanner(Relation relation); + virtual ~Scanner() = 0; + virtual std::vector GetNextChunk(uint32 column_id) = 0; + virtual std::vector GetTypes() = 0; + virtual uint32 GetColumnCount() = 0; + virtual uint64 GetCurrentRow(uint32 column_id) = 0; + virtual std::string GetTableName() = 0; + + Relation relation; +}; + +extern "C" void RegisterScanner(char *, void *); + +/* Registration function for loaded scanners. */ +extern "C" void ScannerInit(); diff --git a/src/quack.cpp b/src/quack.cpp index 4cfd44f3..8a6c7df5 100644 --- a/src/quack.cpp +++ b/src/quack.cpp @@ -6,6 +6,8 @@ extern "C" { #include "quack/quack.h" +#include "quack/scanner.hpp" + static void quack_init_guc(void); extern "C" { @@ -22,5 +24,6 @@ _PG_init(void) { /* clang-format off */ static void quack_init_guc(void) { + load_scanner("heap"); } \ No newline at end of file diff --git a/src/scanner.cpp b/src/scanner.cpp new file mode 100644 index 00000000..690c348e --- /dev/null +++ b/src/scanner.cpp @@ -0,0 +1,48 @@ +#include + +#include +#include + +extern "C" { +#include "postgres.h" + +#include "miscadmin.h" +} + +#include "quack/scanner.hpp" + +std::unordered_map scanners; + +extern "C" void +RegisterScanner(char *name, void *ptr) { + Scanner *(*scanner)(Relation) = (Scanner * (*)(Relation)) ptr; + if (scanners[name] != nullptr) { + elog(WARNING, "Registering scanner %s, which already exists.", name); + } + + scanners[name] = scanner; +} + +void +load_scanner(std::string name) { + std::string path = std::string(pkglib_path) + "/" + name + ".so"; + void *shared_obj = dlopen(path.c_str(), RTLD_NOW); + + if (shared_obj == nullptr) { + elog(WARNING, "Unable to read scanner %s: %s", name.c_str(), dlerror()); + elog(WARNING, "Path: %s", path.c_str()); + + return; + } + + void (*init_scanner)(void) = (void (*)(void))dlsym(shared_obj, "ScannerInit"); + + if (init_scanner == nullptr) { + elog(WARNING, "Unable to find ScannerInit in scanner %s", name.c_str()); + + return; + } + + init_scanner(); + elog(DEBUG5, "Scanner %s initialized", name.c_str()); +} diff --git a/src/scanner/heap.cpp b/src/scanner/heap.cpp new file mode 100644 index 00000000..feab18cd --- /dev/null +++ b/src/scanner/heap.cpp @@ -0,0 +1,13 @@ +#include "quack/scanner.hpp" + +extern "C" { +#include "postgres.h" +} + +#include + +void +ScannerInit() { + elog(WARNING, "registering heap"); + RegisterScanner((char *)"heap", nullptr); +}