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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ set(TARGET_NAME cactusdb)
# used in cmake with find_package. Feel free to remove or replace with other dependencies.
# Note that it should also be removed from vcpkg.json to prevent needlessly installing it..

## TO BE REMOVED
find_package(OpenSSL REQUIRED)
find_package(Eigen3 REQUIRED)

set(EXTENSION_NAME ${TARGET_NAME}_extension)

Expand All @@ -18,16 +18,19 @@ set(LOADABLE_EXTENSION_NAME ${TARGET_NAME}_loadable_extension)

project(${TARGET_NAME})
include_directories(src/include)
include_directories(${EIGEN3_INCLUDE_DIR})

## TO BE REPLACED
set(EXTENSION_SOURCES src/cactusdb_extension.cpp)
add_subdirectory(src/ml_functions)
add_subdirectory(src/util)
message(STATUS "EXTENSION_SOURCES include ${EXTENSION_SOURCES}")

build_static_extension(${TARGET_NAME} ${EXTENSION_SOURCES})
build_loadable_extension(${TARGET_NAME} " " ${EXTENSION_SOURCES})

# Link OpenSSL in both the static library as the loadable extension
target_link_libraries(${EXTENSION_NAME} OpenSSL::SSL OpenSSL::Crypto)
target_link_libraries(${LOADABLE_EXTENSION_NAME} OpenSSL::SSL OpenSSL::Crypto)
target_link_libraries(${EXTENSION_NAME} OpenSSL::SSL OpenSSL::Crypto Eigen3::Eigen)
target_link_libraries(${LOADABLE_EXTENSION_NAME} OpenSSL::SSL OpenSSL::Crypto Eigen3::Eigen)

install(
TARGETS ${EXTENSION_NAME}
Expand Down
16 changes: 16 additions & 0 deletions logfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
2025-09-15 11:51:32.458 MST [77299] LOG: starting PostgreSQL 15.14 (Homebrew) on aarch64-apple-darwin23.6.0, compiled by Apple clang version 16.0.0 (clang-1600.0.26.6), 64-bit
2025-09-15 11:51:32.459 MST [77299] LOG: listening on IPv4 address "127.0.0.1", port 8888
2025-09-15 11:51:32.459 MST [77299] LOG: listening on IPv6 address "::1", port 8888
2025-09-15 11:51:32.460 MST [77299] LOG: listening on Unix socket "/tmp/.s.PGSQL.8888"
2025-09-15 11:51:32.466 MST [77302] LOG: database system was interrupted; last known up at 2025-09-03 13:56:52 MST
2025-09-15 11:51:32.537 MST [77302] LOG: database system was not properly shut down; automatic recovery in progress
2025-09-15 11:51:32.541 MST [77302] LOG: redo starts at 0/43401828
2025-09-15 11:51:35.046 MST [77302] LOG: invalid record length at 0/50F774F8: wanted 24, got 0
2025-09-15 11:51:35.046 MST [77302] LOG: redo done at 0/50F774C0 system usage: CPU: user: 0.22 s, system: 0.93 s, elapsed: 2.50 s
2025-09-15 11:51:35.051 MST [77300] LOG: checkpoint starting: end-of-recovery immediate wait
2025-09-15 11:51:35.580 MST [77300] LOG: checkpoint complete: wrote 16375 buffers (99.9%); 0 WAL file(s) added, 13 removed, 0 recycled; write=0.390 s, sync=0.005 s, total=0.533 s; sync files=64, longest=0.003 s, average=0.001 s; distance=224727 kB, estimate=224727 kB
2025-09-15 11:51:35.584 MST [77299] LOG: database system is ready to accept connections
2025-09-15 11:53:12.240 MST [77334] ERROR: relation "customers" does not exist at character 22
2025-09-15 11:53:12.240 MST [77334] STATEMENT: SELECT count(*) FROM CUSTOMERS;
2025-09-15 11:53:12.301 MST [77334] ERROR: relation "suppliers" does not exist at character 22
2025-09-15 11:53:12.301 MST [77334] STATEMENT: SELECT count(*) FROM SUPPLIERS;
6 changes: 4 additions & 2 deletions src/cactusdb_extension.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
#define DUCKDB_EXTENSION_MAIN

#include "cactusdb_extension.hpp"
#include "duckdb.hpp"
#include "functions.hpp"

// OpenSSL linked through vcpkg
#include <openssl/opensslv.h>

namespace duckdb {

static void LoadInternal(ExtensionLoader &loader) {

RegisterMLScalarFunctions(loader);

}

void CactusdbExtension::Load(ExtensionLoader &loader) {
Expand Down
239 changes: 239 additions & 0 deletions src/include/function_builder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
#pragma once

#include "duckdb.hpp"
#include "duckdb/function/function_set.hpp"
#include "duckdb/function/scalar_function.hpp"
#include "duckdb/parser/parsed_data/create_function_info.hpp"
#include "duckdb/common/insertion_order_preserving_map.hpp"
#include "duckdb/catalog/default/default_functions.hpp"

namespace duckdb {

//------------------------------------------------------------------------------
// Function Builder
//------------------------------------------------------------------------------

class ScalarFunctionBuilder;
class AggregateFunctionBuilder;
class MacroFunctionBuilder;

class FunctionBuilder {
public:
template <class CALLBACK>
static void RegisterScalar(ExtensionLoader &loader, const char *name, CALLBACK &&callback);

template <class CALLBACK>
static void RegisterAggregate(ExtensionLoader &loader, const char *name, CALLBACK &&callback);

template <class CALLBACK>
static void RegisterMacro(ExtensionLoader &loader, const char *name, CALLBACK &&callback);

// TODO:
static void AddTableFunctionDocs(ExtensionLoader &loader, const char *name, const char *desc, const char *example,
const InsertionOrderPreservingMap<string> &tags);

static string RemoveIndentAndTrailingWhitespace(const char *str);

private:
static void Register(ExtensionLoader &loader, const char *name, ScalarFunctionBuilder &builder);
static void Register(ExtensionLoader &loader, const char *name, AggregateFunctionBuilder &builder);
static void Register(ExtensionLoader &loader, const char *name, MacroFunctionBuilder &builder);
};

//------------------------------------------------------------------------------
// 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 <class CALLBACK>
void AddVariant(CALLBACK &&callback);
void SetTag(const string &key, const string &value);
void SetDescription(const string &desc);
void SetExample(const string &ex);

private:
explicit ScalarFunctionBuilder(const char *name) : set(name) {
}

ScalarFunctionSet set;
vector<FunctionDescription> descriptions = {};
InsertionOrderPreservingMap<string> tags = {};

// If not set by a variant
string default_description;
string default_example;
};

inline void ScalarFunctionBuilder::SetDescription(const string &desc) {
default_description = FunctionBuilder::RemoveIndentAndTrailingWhitespace(desc.c_str());
}

inline void ScalarFunctionBuilder::SetExample(const string &ex) {
default_example = FunctionBuilder::RemoveIndentAndTrailingWhitespace(ex.c_str());
}

inline void ScalarFunctionBuilder::SetTag(const string &key, const string &value) {
tags[key] = value;
}

template <class CALLBACK>
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 description
descriptions.emplace_back(std::move(builder.description));
}

//------------------------------------------------------------------------------
// Macro
//------------------------------------------------------------------------------
class MacroFunctionBuilder {
friend class FunctionBuilder;

public:
void AddDefinition(const vector<string> &parameters, const string &body, const char *desc = nullptr,
const char *example = nullptr) {
macros.push_back({parameters, body, desc, example});
}

private:
struct MacroDef {
vector<string> parameters;
string body;
const char *description;
const char *example;
};

vector<MacroDef> macros;
};

//------------------------------------------------------------------------------
// Aggregate
//------------------------------------------------------------------------------

class AggregateFunctionBuilder {
friend class FunctionBuilder;

public:
void SetTag(const string &key, const string &value);
void SetDescription(const string &desc);
void SetExample(const string &ex);
void SetFunction(const AggregateFunction &function);

private:
explicit AggregateFunctionBuilder(const char *name) : set(name) {
}
string description;
string example;
InsertionOrderPreservingMap<string> tags;
AggregateFunctionSet set;
};

inline void AggregateFunctionBuilder::SetFunction(const AggregateFunction &function) {
set.AddFunction(function);
}

inline void AggregateFunctionBuilder::SetDescription(const string &desc) {
description = desc;
}
inline void AggregateFunctionBuilder::SetExample(const string &ex) {
example = ex;
}
inline void AggregateFunctionBuilder::SetTag(const string &key, const string &value) {
tags[key] = value;
}

//------------------------------------------------------------------------------
// Function Builder Methods
//------------------------------------------------------------------------------

template <class CALLBACK>
void FunctionBuilder::RegisterScalar(ExtensionLoader &loader, const char *name, CALLBACK &&callback) {
ScalarFunctionBuilder builder(name);
callback(builder);

Register(loader, name, builder);
}

template <class CALLBACK>
void FunctionBuilder::RegisterAggregate(ExtensionLoader &loader, const char *name, CALLBACK &&callback) {
AggregateFunctionBuilder builder(name);
callback(builder);
Register(loader, name, builder);
}

template <class CALLBACK>
void FunctionBuilder::RegisterMacro(ExtensionLoader &loader, const char *name, CALLBACK &&callback) {
MacroFunctionBuilder builder;
callback(builder);
Register(loader, name, builder);
}

} // namespace duckdb
13 changes: 13 additions & 0 deletions src/include/functions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "duckdb/common/typedefs.hpp"

#include "duckdb.hpp"

namespace duckdb {

class ExtensionLoader;

void RegisterMLScalarFunctions(ExtensionLoader &loader);

}
4 changes: 4 additions & 0 deletions src/ml_functions/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set(EXTENSION_SOURCES
${EXTENSION_SOURCES}
${CMAKE_CURRENT_SOURCE_DIR}/ml_functions_scalar.cpp
PARENT_SCOPE)
Loading
Loading