Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SQL scalar and table macros and tests #84

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
61 changes: 61 additions & 0 deletions src/quack_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,62 @@
#include "duckdb/function/scalar_function.hpp"
#include "duckdb/main/extension_util.hpp"
#include <duckdb/parser/parsed_data/create_scalar_function_info.hpp>
#include "duckdb/catalog/default/default_functions.hpp"
#include "duckdb/catalog/default/default_table_functions.hpp"

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

namespace duckdb {


// To add a new scalar SQL macro, add a new macro to this array!
// Copy and paste the top item in the array into the
// second-to-last position and make some modifications.
// (essentially, leave the last entry in the array as {nullptr, nullptr, {nullptr}, {{nullptr, nullptr}}, nullptr} )

// Keep the DEFAULT_SCHEMA (no change needed)
// Replace "times_two" with a name for your macro
// If your function has parameters without default values, add their names in quotes inside of the {}, with a nullptr at the end
// If you do not have parameters, simplify to {nullptr}
// If your function has parameters with default values, add their names and values in double quotes inside of {}'s inside of the {}.
// If you have default values that are strings, wrap them in single quotes inside the double quotes
// (Ex: {{"my_string":"'my_default_value'"}, {nullptr, nullptr}} )
// Be sure to keep {nullptr, nullptr} at the end
// If you do not have parameters with default values, simplify to {nullptr, nullptr}
// Add the text of your SQL macro as a raw string with the format R"( select 42 )"
// clang-format off
static DefaultMacro quack_macros[] = {
{DEFAULT_SCHEMA, "times_two", {"x", nullptr}, {{nullptr, nullptr}}, R"( x * 2 )"},
{DEFAULT_SCHEMA, "default_to_times_two", {"x", nullptr}, {{"multiplier", "2"}, {nullptr, nullptr}}, R"( x * multiplier )"},
{nullptr, nullptr, {nullptr}, {{nullptr, nullptr}}, nullptr}
};
// clang-format on

// To add a new SQL table macro, add a new macro to this array!
// Copy and paste the top item in the array into the
// second-to-last position and make some modifications.
// (essentially, leave the last entry in the array as {nullptr, nullptr, {nullptr}, {{nullptr, nullptr}}, nullptr}

// Keep the DEFAULT_SCHEMA (no change needed)
// Replace "times_two_table" with a name for your macro
// If your function has parameters without default values, add their names in quotes inside of the {}, with a nullptr at the end
// If you do not have parameters, simplify to {nullptr}
// If your function has parameters with default values, add their names and values in double quotes inside of {}'s inside of the {}.
// If you have default values that are strings, wrap them in single quotes inside the double quotes
// (Ex: {{"my_string":"'my_default_value'"}, {nullptr, nullptr}} )
// Be sure to keep {nullptr, nullptr} at the end
// If you do not have parameters with default values, simplify to {nullptr, nullptr}
// Add the text of your SQL macro as a raw string with the format R"( select 42; )"

// clang-format off
static const DefaultTableMacro quack_table_macros[] = {
{DEFAULT_SCHEMA, "times_two_table", {"x", nullptr}, {{nullptr, nullptr}}, R"( SELECT x * 2 as output_column; )"},
{DEFAULT_SCHEMA, "default_to_times_two_table", {"x", nullptr}, {{"multiplier", "2"}, {nullptr, nullptr}}, R"( SELECT x * multiplier as output_column; )"},
{nullptr, nullptr, {nullptr}, {{nullptr, nullptr}}, nullptr}
};
// clang-format on

inline void QuackScalarFun(DataChunk &args, ExpressionState &state, Vector &result) {
auto &name_vector = args.data[0];
UnaryExecutor::Execute<string_t, string_t>(
Expand All @@ -34,6 +84,17 @@ inline void QuackOpenSSLVersionScalarFun(DataChunk &args, ExpressionState &state
}

static void LoadInternal(DatabaseInstance &instance) {
// Register Scalar Macros
for (idx_t index = 0; quack_macros[index].name != nullptr; index++) {
auto info = DefaultFunctionGenerator::CreateInternalMacroInfo(quack_macros[index]);
ExtensionUtil::RegisterFunction(instance, *info);
}
// Register Table Macros
for (idx_t index = 0; quack_table_macros[index].name != nullptr; index++) {
auto table_info = DefaultTableFunctionGenerator::CreateTableMacroInfo(quack_table_macros[index]);
ExtensionUtil::RegisterFunction(instance, *table_info);
}

// Register a scalar function
auto quack_scalar_function = ScalarFunction("quack", {LogicalType::VARCHAR}, LogicalType::VARCHAR, QuackScalarFun);
ExtensionUtil::RegisterFunction(instance, quack_scalar_function);
Expand Down
38 changes: 38 additions & 0 deletions test/sql/quack.test
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,49 @@ Catalog Error: Scalar Function with name quack does not exist!
require quack

# Confirm the extension works
# Test scalar macro
query I
SELECT times_two(4);
----
8

# Test table macro
query I
SELECT * FROM times_two_table(5);
----
10

# Test scalar macro using a default
query I
SELECT default_to_times_two(4);
----
8

# Test scalar macro overriding the default
query I
SELECT default_to_times_two(4, multiplier:=3);
----
12

# Test table macro using a default
query I
SELECT * FROM default_to_times_two_table(5);
----
10

# Test table macro overriding the default
query I
SELECT * FROM default_to_times_two_table(5, multiplier:=3);
----
15

# Test scalar C++ function
query I
SELECT quack('Sam');
----
Quack Sam 🐥

# Test scalar C++ function using vcpkg and openssl
query I
SELECT quack_openssl_version('Michael') ILIKE 'Quack Michael, my linked OpenSSL version is OpenSSL%';
----
Expand Down
Loading