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:
@@ -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}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
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");
|
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 ¶meter_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
9
src/include/version.hpp
Normal 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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user