Merge pull request #1 from duckdb/jray/seq-num-and-headers

add seq num to version; change header names; multi-param support
This commit is contained in:
Jeff Raymakers
2025-02-24 13:41:39 -08:00
committed by GitHub
4 changed files with 81 additions and 28 deletions

View File

@@ -15,23 +15,32 @@ project(${TARGET_NAME})
include_directories(src/include ${DuckDB_SOURCE_DIR}/third_party/httplib) include_directories(src/include ${DuckDB_SOURCE_DIR}/third_party/httplib)
set(EXTENSION_SOURCES set(EXTENSION_SOURCES
src/ui_extension.cpp
src/event_dispatcher.cpp src/event_dispatcher.cpp
src/http_server.cpp src/http_server.cpp
src/settings.cpp src/settings.cpp
src/state.cpp src/state.cpp
src/watcher.cpp src/ui_extension.cpp
src/utils/encoding.cpp src/utils/encoding.cpp
src/utils/env.cpp src/utils/env.cpp
src/utils/helpers.cpp src/utils/helpers.cpp
src/utils/md_helpers.cpp src/utils/md_helpers.cpp
src/utils/serialization.cpp) src/utils/serialization.cpp
src/watcher.cpp)
find_package(Git) find_package(Git)
if(NOT Git_FOUND) if(NOT Git_FOUND)
message(FATAL_ERROR "Git not found, unable to determine git sha") message(FATAL_ERROR "Git not found, unable to determine git sha")
endif() 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( execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --short=10 HEAD COMMAND ${GIT_EXECUTABLE} rev-parse --short=10 HEAD
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}

View File

@@ -1,12 +1,13 @@
#include "http_server.hpp" #include "http_server.hpp"
#include "event_dispatcher.hpp"
#include "settings.hpp" #include "settings.hpp"
#include "state.hpp" #include "state.hpp"
#include "utils/encoding.hpp" #include "utils/encoding.hpp"
#include "utils/env.hpp" #include "utils/env.hpp"
#include "event_dispatcher.hpp"
#include "utils/md_helpers.hpp" #include "utils/md_helpers.hpp"
#include "utils/serialization.hpp" #include "utils/serialization.hpp"
#include "version.hpp"
#include "watcher.hpp" #include "watcher.hpp"
#include <duckdb/common/serializer/binary_serializer.hpp> #include <duckdb/common/serializer/binary_serializer.hpp>
#include <duckdb/common/serializer/memory_stream.hpp> #include <duckdb/common/serializer/memory_stream.hpp>
@@ -83,12 +84,9 @@ void HttpServer::DoStart(const uint16_t _local_port,
local_port = _local_port; local_port = _local_port;
remote_url = _remote_url; remote_url = _remote_url;
#ifndef UI_EXTENSION_GIT_SHA
#error "UI_EXTENSION_GIT_SHA must be defined"
#endif
user_agent = user_agent =
StringUtil::Format("duckdb-ui/%s-%s(%s)", DuckDB::LibraryVersion(), StringUtil::Format("duckdb-ui/%s-%s(%s)", DuckDB::LibraryVersion(),
UI_EXTENSION_GIT_SHA, DuckDB::Platform()); UI_EXTENSION_VERSION, DuckDB::Platform());
event_dispatcher = make_uniq<EventDispatcher>(); event_dispatcher = make_uniq<EventDispatcher>();
main_thread = make_uniq<std::thread>(&HttpServer::Run, this); main_thread = make_uniq<std::thread>(&HttpServer::Run, this);
watcher = make_uniq<Watcher>(*this); watcher = make_uniq<Watcher>(*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). // The UI looks for this to select the appropriate DuckDB mode (HTTP or Wasm).
if (req.path == "/config") { if (req.path == "/config") {
res.set_header("X-MD-DuckDB-Mode", "HTTP"); 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, void HttpServer::HandleInterrupt(const httplib::Request &req,
httplib::Response &res) { httplib::Response &res) {
auto description = req.get_header_value("X-MD-Description"); auto description = req.get_header_value("X-DuckDB-UI-Request-Description");
auto connection_name = req.get_header_value("X-MD-Connection-Name"); 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(); auto db = ddb_instance.lock();
if (!db) { if (!db) {
@@ -279,11 +287,41 @@ void HttpServer::HandleRun(const httplib::Request &req, httplib::Response &res,
void HttpServer::DoHandleRun(const httplib::Request &req, void HttpServer::DoHandleRun(const httplib::Request &req,
httplib::Response &res, httplib::Response &res,
const httplib::ContentReader &content_reader) { 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");
auto connection_name = req.get_header_value("X-MD-Connection-Name"); if (description.empty()) {
description = req.get_header_value("X-MD-Description");
}
auto database_name = DecodeBase64(req.get_header_value("X-MD-Database-Name")); auto connection_name = req.get_header_value("X-DuckDB-UI-Connection-Name");
auto parameter_count = req.get_header_value_count("X-MD-Parameter"); 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<std::string> 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); std::string content = ReadContent(content_reader);
@@ -312,7 +350,7 @@ void HttpServer::DoHandleRun(const httplib::Request &req,
unique_ptr<PendingQueryResult> pending; unique_ptr<PendingQueryResult> pending;
// Create pending query, with request content as SQL. // Create pending query, with request content as SQL.
if (parameter_count > 0) { if (parameter_values.size() > 0) {
auto prepared = connection->Prepare(content); auto prepared = connection->Prepare(content);
if (prepared->HasError()) { if (prepared->HasError()) {
SetResponseErrorResult(res, prepared->GetError()); SetResponseErrorResult(res, prepared->GetError());
@@ -320,10 +358,9 @@ void HttpServer::DoHandleRun(const httplib::Request &req,
} }
vector<Value> values; vector<Value> values;
for (idx_t i = 0; i < parameter_count; ++i) { for (auto &parameter_value : parameter_values) {
auto parameter = DecodeBase64(req.get_header_value("X-MD-Parameter", i)); // TODO: support non-string parameters?
values.push_back( values.push_back(Value(parameter_value));
Value(parameter)); // TODO: support non-string parameters? (SURF-1546)
} }
pending = prepared->PendingQuery(values, true); pending = prepared->PendingQuery(values, true);
} else { } else {
@@ -361,7 +398,7 @@ void HttpServer::DoHandleRun(const httplib::Request &req,
success_result.column_names_and_types = {std::move(result->names), success_result.column_names_and_types = {std::move(result->names),
std::move(result->types)}; 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(); auto chunk = result->Fetch();
while (chunk) { while (chunk) {
success_result.chunks.push_back( success_result.chunks.push_back(
@@ -383,7 +420,10 @@ void HttpServer::DoHandleRun(const httplib::Request &req,
void HttpServer::HandleTokenize(const httplib::Request &req, void HttpServer::HandleTokenize(const httplib::Request &req,
httplib::Response &res, httplib::Response &res,
const httplib::ContentReader &content_reader) { 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); std::string content = ReadContent(content_reader);

9
src/include/version.hpp Normal file
View File

@@ -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

View File

@@ -9,6 +9,7 @@
#include "ui_extension.hpp" #include "ui_extension.hpp"
#include "utils/env.hpp" #include "utils/env.hpp"
#include "utils/helpers.hpp" #include "utils/helpers.hpp"
#include "version.hpp"
#ifdef _WIN32 #ifdef _WIN32
#define OPEN_COMMAND "start" #define OPEN_COMMAND "start"
@@ -108,13 +109,7 @@ static void LoadInternal(DatabaseInstance &instance) {
void UiExtension::Load(DuckDB &db) { LoadInternal(*db.instance); } void UiExtension::Load(DuckDB &db) { LoadInternal(*db.instance); }
std::string UiExtension::Name() { return "ui"; } std::string UiExtension::Name() { return "ui"; }
std::string UiExtension::Version() const { std::string UiExtension::Version() const { return UI_EXTENSION_VERSION; }
#ifdef UI_EXTENSION_GIT_SHA
return UI_EXTENSION_GIT_SHA;
#else
return "";
#endif
}
} // namespace duckdb } // namespace duckdb