From d2d3d0b2c13ef6a73ed67aa26d54dd3d9717e3a2 Mon Sep 17 00:00:00 2001 From: Jeff Raymakers Date: Mon, 24 Feb 2025 13:00:17 -0800 Subject: [PATCH] add seq num to version; change header names; multi-param support --- CMakeLists.txt | 15 ++++++-- src/http_server.cpp | 76 +++++++++++++++++++++++++++++++---------- src/include/version.hpp | 9 +++++ src/ui_extension.cpp | 9 ++--- 4 files changed, 81 insertions(+), 28 deletions(-) create mode 100644 src/include/version.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ef3c84..5983840 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,23 +15,32 @@ project(${TARGET_NAME}) include_directories(src/include ${DuckDB_SOURCE_DIR}/third_party/httplib) set(EXTENSION_SOURCES - src/ui_extension.cpp src/event_dispatcher.cpp src/http_server.cpp src/settings.cpp src/state.cpp - src/watcher.cpp + src/ui_extension.cpp src/utils/encoding.cpp src/utils/env.cpp src/utils/helpers.cpp src/utils/md_helpers.cpp - src/utils/serialization.cpp) + src/utils/serialization.cpp + src/watcher.cpp) find_package(Git) if(NOT Git_FOUND) message(FATAL_ERROR "Git not found, unable to determine git sha") endif() +execute_process( + COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE UI_EXTENSION_SEQ_NUM + OUTPUT_STRIP_TRAILING_WHITESPACE) + +message(STATUS "UI_EXTENSION_SEQ_NUM=${UI_EXTENSION_SEQ_NUM}") +add_definitions(-DUI_EXTENSION_SEQ_NUM="${UI_EXTENSION_SEQ_NUM}") + execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --short=10 HEAD WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} diff --git a/src/http_server.cpp b/src/http_server.cpp index f73daba..3218a72 100644 --- a/src/http_server.cpp +++ b/src/http_server.cpp @@ -1,12 +1,13 @@ #include "http_server.hpp" +#include "event_dispatcher.hpp" #include "settings.hpp" #include "state.hpp" #include "utils/encoding.hpp" #include "utils/env.hpp" -#include "event_dispatcher.hpp" #include "utils/md_helpers.hpp" #include "utils/serialization.hpp" +#include "version.hpp" #include "watcher.hpp" #include #include @@ -83,12 +84,9 @@ void HttpServer::DoStart(const uint16_t _local_port, local_port = _local_port; remote_url = _remote_url; -#ifndef UI_EXTENSION_GIT_SHA -#error "UI_EXTENSION_GIT_SHA must be defined" -#endif user_agent = StringUtil::Format("duckdb-ui/%s-%s(%s)", DuckDB::LibraryVersion(), - UI_EXTENSION_GIT_SHA, DuckDB::Platform()); + UI_EXTENSION_VERSION, DuckDB::Platform()); event_dispatcher = make_uniq(); main_thread = make_uniq(&HttpServer::Run, this); watcher = make_uniq(*this); @@ -241,13 +239,23 @@ void HttpServer::HandleGet(const httplib::Request &req, // The UI looks for this to select the appropriate DuckDB mode (HTTP or Wasm). if (req.path == "/config") { res.set_header("X-MD-DuckDB-Mode", "HTTP"); + res.set_header("X-DuckDB-Version", DuckDB::LibraryVersion()); + res.set_header("X-DuckDB-Platform", DuckDB::Platform()); + res.set_header("X-DuckDB-UI-Extension-Version", UI_EXTENSION_VERSION); } } void HttpServer::HandleInterrupt(const httplib::Request &req, httplib::Response &res) { - auto description = req.get_header_value("X-MD-Description"); - auto connection_name = req.get_header_value("X-MD-Connection-Name"); + auto description = req.get_header_value("X-DuckDB-UI-Request-Description"); + if (description.empty()) { + description = req.get_header_value("X-MD-Description"); + } + + auto connection_name = req.get_header_value("X-DuckDB-UI-Connection-Name"); + if (connection_name.empty()) { + connection_name = req.get_header_value("X-MD-Connection-Name"); + } auto db = ddb_instance.lock(); if (!db) { @@ -279,11 +287,41 @@ void HttpServer::HandleRun(const httplib::Request &req, httplib::Response &res, void HttpServer::DoHandleRun(const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader) { - auto description = req.get_header_value("X-MD-Description"); - auto connection_name = req.get_header_value("X-MD-Connection-Name"); + auto description = req.get_header_value("X-DuckDB-UI-Request-Description"); + if (description.empty()) { + description = req.get_header_value("X-MD-Description"); + } - auto database_name = DecodeBase64(req.get_header_value("X-MD-Database-Name")); - auto parameter_count = req.get_header_value_count("X-MD-Parameter"); + auto connection_name = req.get_header_value("X-DuckDB-UI-Connection-Name"); + if (connection_name.empty()) { + connection_name = req.get_header_value("X-MD-Connection-Name"); + } + + auto database_name = + DecodeBase64(req.get_header_value("X-DuckDB-UI-Database-Name")); + if (database_name.empty()) { + database_name = req.get_header_value("X-MD-Database-Name"); + } + + std::vector parameter_values; + auto parameter_count_string = + req.get_header_value("X-DuckDB-UI-Parameter-Count"); + if (!parameter_count_string.empty()) { + auto parameter_count = std::stoi(parameter_count_string); + std::cout << "parameter_count " << parameter_count << std::endl; + for (idx_t i = 0; i < parameter_count; ++i) { + auto parameter_value = DecodeBase64(req.get_header_value( + StringUtil::Format("X-DuckDB-UI-Parameter-Value-%d", i))); + parameter_values.push_back(parameter_value); + } + } else { + auto parameter_count = req.get_header_value_count("X-MD-Parameter"); + for (idx_t i = 0; i < parameter_count; ++i) { + auto parameter_value = + DecodeBase64(req.get_header_value("X-MD-Parameter", i)); + parameter_values.push_back(parameter_value); + } + } std::string content = ReadContent(content_reader); @@ -312,7 +350,7 @@ void HttpServer::DoHandleRun(const httplib::Request &req, unique_ptr pending; // Create pending query, with request content as SQL. - if (parameter_count > 0) { + if (parameter_values.size() > 0) { auto prepared = connection->Prepare(content); if (prepared->HasError()) { SetResponseErrorResult(res, prepared->GetError()); @@ -320,10 +358,9 @@ void HttpServer::DoHandleRun(const httplib::Request &req, } vector values; - for (idx_t i = 0; i < parameter_count; ++i) { - auto parameter = DecodeBase64(req.get_header_value("X-MD-Parameter", i)); - values.push_back( - Value(parameter)); // TODO: support non-string parameters? (SURF-1546) + for (auto ¶meter_value : parameter_values) { + // TODO: support non-string parameters? + values.push_back(Value(parameter_value)); } pending = prepared->PendingQuery(values, true); } else { @@ -361,7 +398,7 @@ void HttpServer::DoHandleRun(const httplib::Request &req, success_result.column_names_and_types = {std::move(result->names), std::move(result->types)}; - // TODO: support limiting the number of chunks fetched (SURF-1540) + // TODO: support limiting the number of chunks fetched auto chunk = result->Fetch(); while (chunk) { success_result.chunks.push_back( @@ -383,7 +420,10 @@ void HttpServer::DoHandleRun(const httplib::Request &req, void HttpServer::HandleTokenize(const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader) { - auto description = req.get_header_value("X-MD-Description"); + auto description = req.get_header_value("X-DuckDB-UI-Request-Description"); + if (description.empty()) { + description = req.get_header_value("X-MD-Description"); + } std::string content = ReadContent(content_reader); diff --git a/src/include/version.hpp b/src/include/version.hpp new file mode 100644 index 0000000..af3f209 --- /dev/null +++ b/src/include/version.hpp @@ -0,0 +1,9 @@ +#pragma once + +#ifndef UI_EXTENSION_SEQ_NUM +#error "UI_EXTENSION_SEQ_NUM must be defined" +#endif +#ifndef UI_EXTENSION_GIT_SHA +#error "UI_EXTENSION_GIT_SHA must be defined" +#endif +#define UI_EXTENSION_VERSION UI_EXTENSION_SEQ_NUM "-" UI_EXTENSION_GIT_SHA diff --git a/src/ui_extension.cpp b/src/ui_extension.cpp index 568899e..d648279 100644 --- a/src/ui_extension.cpp +++ b/src/ui_extension.cpp @@ -9,6 +9,7 @@ #include "ui_extension.hpp" #include "utils/env.hpp" #include "utils/helpers.hpp" +#include "version.hpp" #ifdef _WIN32 #define OPEN_COMMAND "start" @@ -108,13 +109,7 @@ static void LoadInternal(DatabaseInstance &instance) { void UiExtension::Load(DuckDB &db) { LoadInternal(*db.instance); } std::string UiExtension::Name() { return "ui"; } -std::string UiExtension::Version() const { -#ifdef UI_EXTENSION_GIT_SHA - return UI_EXTENSION_GIT_SHA; -#else - return ""; -#endif -} +std::string UiExtension::Version() const { return UI_EXTENSION_VERSION; } } // namespace duckdb