diff --git a/include/quack/quack.h b/include/quack/quack.h index 647c2496..ecf6588a 100644 --- a/include/quack/quack.h +++ b/include/quack/quack.h @@ -2,6 +2,7 @@ // quack.c extern int quack_max_threads_per_query; +extern char *quack_secret; extern "C" void _PG_init(void); // quack_hooks.c diff --git a/include/quack/quack_utils.hpp b/include/quack/quack_utils.hpp new file mode 100644 index 00000000..ec0177b0 --- /dev/null +++ b/include/quack/quack_utils.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace quack { + +inline std::vector +tokenizeString(char *str, const char delimiter) { + std::vector v; + std::stringstream ss(str); // Turn the string into a stream. + std::string tok; + while (getline(ss, tok, delimiter)) { + v.push_back(tok); + } + return v; +}; + +} // namespace quack \ No newline at end of file diff --git a/src/quack.cpp b/src/quack.cpp index 69ff02b5..b53b127b 100644 --- a/src/quack.cpp +++ b/src/quack.cpp @@ -5,10 +5,12 @@ extern "C" { #include "quack/quack.h" #include "quack/quack_node.hpp" +#include "quack/quack_utils.hpp" static void quack_init_guc(void); int quack_max_threads_per_query = 1; +char *quack_secret = nullptr; extern "C" { PG_MODULE_MAGIC; @@ -19,12 +21,36 @@ _PG_init(void) { quack_init_hooks(); quack_init_node(); } + +} + +static bool +quack_cloud_secret_check_hooks(char **newval, void **extra, GucSource source) { + + std::vector tokens = quack::tokenizeString(*newval, '#'); + + if (tokens.size() == 0) { + return true; + } + + if (tokens.size() != 4) { + elog(WARNING, "Incorrect quack.cloud_secret format."); + return false; + } + + if (tokens[0].compare("S3")) { + elog(WARNING, "quack.cloud_secret supports only S3."); + return false; + } + + return true; } /* clang-format off */ static void quack_init_guc(void) { - DefineCustomIntVariable("quack.max_threads_per_query", + + DefineCustomIntVariable("quack.max_threads_per_query", gettext_noop("DuckDB max no. threads per query."), NULL, &quack_max_threads_per_query, @@ -36,4 +62,15 @@ quack_init_guc(void) { NULL, NULL, NULL); + + DefineCustomStringVariable("quack.cloud_secret", + "Quack (duckdb) cloud secret GUC. Format is TYPE#ID#SECRET#REGION", + NULL, + &quack_secret, + "", + PGC_USERSET, + 0, + &quack_cloud_secret_check_hooks, + NULL, + NULL); } \ No newline at end of file diff --git a/src/quack_planner.cpp b/src/quack_planner.cpp index 780b9612..e748ceca 100644 --- a/src/quack_planner.cpp +++ b/src/quack_planner.cpp @@ -13,6 +13,7 @@ extern "C" { #include "quack/quack_node.hpp" #include "quack/quack_planner.hpp" #include "quack/quack_types.hpp" +#include "quack/quack_utils.hpp" namespace quack { @@ -47,6 +48,16 @@ quack_create_plan(Query *parse, const char *query) { catalog.CreateTableFunction(context, &heap_scan_info); context.transaction.Commit(); + if (strlen(quack_secret) != 0) { + std::vector quackSecret = quack::tokenizeString(quack_secret, '#'); + StringInfo s3SecretKey = makeStringInfo(); + appendStringInfoString(s3SecretKey, "CREATE SECRET s3Secret "); + appendStringInfo(s3SecretKey, "(TYPE S3, KEY_ID '%s', SECRET '%s', REGION '%s');", quackSecret[1].c_str(), + quackSecret[2].c_str(), quackSecret[3].c_str()); + context.Query(s3SecretKey->data, false); + pfree(s3SecretKey->data); + } + auto preparedQuery = context.Prepare(query); if (preparedQuery->HasError()) {