diff --git a/CMakeLists.txt b/CMakeLists.txt index 0909200..21ee03a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ else() message(STATUS "ghidrasql: Fetching libxsql from GitHub (shallow clone)...") FetchContent_Declare(libxsql GIT_REPOSITORY https://github.com/0xeb/libxsql.git - GIT_TAG v1.0.7 + GIT_TAG v1.0.8 GIT_SHALLOW TRUE ) FetchContent_MakeAvailable(libxsql) diff --git a/src/cli/main.cpp b/src/cli/main.cpp index 72c2879..77288de 100644 --- a/src/cli/main.cpp +++ b/src/cli/main.cpp @@ -574,11 +574,14 @@ int run_repl( return "HTTP already running at " + http.url(); } int port = http.start( - [&](const std::string& sql) { - std::vector results; - std::string error; - const bool ok = engine.execute_script(sql, results, error); - return ghidrasql::script_results_to_json(results, ok, error).dump(); + [&](const std::string& sql, xsql::ScriptStatementResult& out) { + const ghidrasql::QueryResult r = engine.query(sql); + out.columns = r.columns; + out.rows.reserve(r.rows.size()); + for (const auto& row : r.rows) out.rows.push_back(row.values); + out.success = r.success; + out.error = r.error; + out.elapsed_ms = r.elapsed_ms; }, [&]() { return engine.info(); }, http_options, @@ -871,11 +874,14 @@ int run_headless_live_server(const Args& args) { http_options.auth_token = args.auth_token; const int started_port = http.start( - [&](const std::string& sql) { - std::vector results; - std::string error; - const bool ok = engine.execute_script(sql, results, error); - return ghidrasql::script_results_to_json(results, ok, error).dump(); + [&](const std::string& sql, xsql::ScriptStatementResult& out) { + const ghidrasql::QueryResult r = engine.query(sql); + out.columns = r.columns; + out.rows.reserve(r.rows.size()); + for (const auto& row : r.rows) out.rows.push_back(row.values); + out.success = r.success; + out.error = r.error; + out.elapsed_ms = r.elapsed_ms; }, [&]() { return engine.info(); }, http_options, @@ -1043,11 +1049,14 @@ int main(int argc, char** argv) { if (args.serve) { int started_port = http.start( - [&](const std::string& sql) { - std::vector results; - std::string error; - const bool ok = engine.execute_script(sql, results, error); - return ghidrasql::script_results_to_json(results, ok, error).dump(); + [&](const std::string& sql, xsql::ScriptStatementResult& out) { + const ghidrasql::QueryResult r = engine.query(sql); + out.columns = r.columns; + out.rows.reserve(r.rows.size()); + for (const auto& row : r.rows) out.rows.push_back(row.values); + out.success = r.success; + out.error = r.error; + out.elapsed_ms = r.elapsed_ms; }, [&]() { return engine.info(); }, http_options, diff --git a/src/lib/include/ghidrasql/ghidrasql.hpp b/src/lib/include/ghidrasql/ghidrasql.hpp index 13af9f7..5418029 100644 --- a/src/lib/include/ghidrasql/ghidrasql.hpp +++ b/src/lib/include/ghidrasql/ghidrasql.hpp @@ -163,7 +163,10 @@ class HttpServer { kForceKilled = 4, }; - using QueryFn = std::function; + // Single-statement executor: runs one SQL statement and fills `out`. + // The thinclient owns multi-statement orchestration + output formatting. + using QueryFn = std::function; using InfoFn = std::function; using RefreshFn = std::function; diff --git a/src/lib/src/http.cpp b/src/lib/src/http.cpp index 37eab3f..6ce09f1 100644 --- a/src/lib/src/http.cpp +++ b/src/lib/src/http.cpp @@ -130,7 +130,8 @@ int HttpServer::start(QueryFn query_fn, InfoFn info_fn, Options options, Refresh // a worker is currently busy and how long the oldest in-flight call has // been running. The wrapper does not change the response body; it only // brackets the call with two atomic updates. - cfg.query_fn = [this, fn = std::move(query_fn)](const std::string& sql) -> std::string { + cfg.statement_executor = [this, fn = std::move(query_fn)]( + const std::string& sql, xsql::ScriptStatementResult& out) { const auto now_ms = std::chrono::duration_cast( std::chrono::steady_clock::now().time_since_epoch()).count(); latest_query_started_at_ms_.store(now_ms, std::memory_order_relaxed); @@ -139,7 +140,7 @@ int HttpServer::start(QueryFn query_fn, InfoFn info_fn, Options options, Refresh std::atomic* counter; ~CountGuard() { counter->fetch_sub(1, std::memory_order_relaxed); } } guard{&active_queries_}; - return fn(sql); + fn(sql, out); }; cfg.status_fn = [this]() -> xsql::json {