Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement session::get_last_query_context() #1164

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion include/soci/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,21 @@
#include "soci/soci-platform.h"

#include <ostream>
#include <vector>

namespace soci
{


struct SOCI_DECL query_parameter
{
explicit query_parameter(std::string name = {}, std::string value = {})
: name(std::move(name)), value(std::move(value)) {}

std::string name;
std::string value;
};

// Allows to customize the logging of database operations performed by SOCI.
//
// To do it, derive your own class from logger_impl and override its pure
Expand All @@ -28,7 +39,13 @@ class SOCI_DECL logger_impl
virtual ~logger_impl();

// Called to indicate that a new query is about to be executed.
virtual void start_query(std::string const & query) = 0;
virtual void start_query(std::string const & query);

// Called to log a parameter that is bound to the currently active query
virtual void add_query_parameter(std::string name, std::string value);

// Clears all currently logged query parameters
virtual void clear_query_parameters();

logger_impl * clone() const;

Expand All @@ -38,6 +55,10 @@ class SOCI_DECL logger_impl
virtual void set_stream(std::ostream * s);
virtual std::ostream * get_stream() const;
virtual std::string get_last_query() const;
virtual std::string get_last_query_context() const;

protected:
std::vector<query_parameter> queryParams_;

private:
// Override to return a new heap-allocated copy of this object.
Expand Down Expand Up @@ -68,10 +89,18 @@ class SOCI_DECL logger

void start_query(std::string const & query) { m_impl->start_query(query); }

virtual void add_query_parameter(std::string name, std::string value)
{
m_impl->add_query_parameter(std::move(name), std::move(value));
}

virtual void clear_query_parameters() { m_impl->clear_query_parameters(); }

// Methods used for the implementation of session basic logging support.
void set_stream(std::ostream * s) { m_impl->set_stream(s); }
std::ostream * get_stream() const { return m_impl->get_stream(); }
std::string get_last_query() const { return m_impl->get_last_query(); }
std::string get_last_query_context() const { return m_impl->get_last_query_context(); }

private:
logger_impl * m_impl;
Expand Down
3 changes: 3 additions & 0 deletions include/soci/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,10 @@ class SOCI_DECL session
std::ostream * get_log_stream() const;

void log_query(std::string const & query);
void clear_query_parameters();
void add_query_parameter(std::string name, std::string value);
std::string get_last_query() const;
std::string get_last_query_context() const;

void set_got_data(bool gotData);
bool got_data() const;
Expand Down
34 changes: 34 additions & 0 deletions src/core/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ void throw_not_supported()
} // namespace anonymous


void logger_impl::start_query(const std::string &)
{
clear_query_parameters();
}

void logger_impl::add_query_parameter(std::string name, std::string value)
{
queryParams_.emplace_back(std::move(name), std::move(value));
}

void logger_impl::clear_query_parameters() { queryParams_.clear(); }

logger_impl * logger_impl::clone() const
{
logger_impl * const impl = do_clone();
Expand Down Expand Up @@ -57,6 +69,28 @@ std::string logger_impl::get_last_query() const
SOCI_DUMMY_RETURN(std::string());
}

std::string logger_impl::get_last_query_context() const
{
std::string context;

bool first = true;
for (const query_parameter &param : queryParams_)
{
if (first)
{
first = false;
}
else
{
context += ", ";
}

context += ":" + param.name + "=" + param.value;
}

return context;
}

logger::logger(logger_impl * impl)
: m_impl(impl)
{
Expand Down
38 changes: 38 additions & 0 deletions src/core/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class standard_logger_impl : public logger_impl

virtual void start_query(std::string const & query)
{
logger_impl::start_query(query);

if (logStream_ != NULL)
{
*logStream_ << query << '\n';
Expand Down Expand Up @@ -449,6 +451,30 @@ void session::log_query(std::string const & query)
}
}

void session::clear_query_parameters()
{
if (isFromPool_)
{
pool_->at(poolPosition_).clear_query_parameters();
}
else
{
logger_.clear_query_parameters();
}
}

void session::add_query_parameter(std::string name, std::string value)
{
if (isFromPool_)
{
pool_->at(poolPosition_).add_query_parameter(std::move(name), std::move(value));
}
else
{
logger_.add_query_parameter(std::move(name), std::move(value));
}
}

std::string session::get_last_query() const
{
if (isFromPool_)
Expand All @@ -461,6 +487,18 @@ std::string session::get_last_query() const
}
}

std::string session::get_last_query_context() const
{
if (isFromPool_)
{
return pool_->at(poolPosition_).get_last_query_context();
}
else
{
return logger_.get_last_query_context();
}
}

void session::set_got_data(bool gotData)
{
if (isFromPool_)
Expand Down
36 changes: 24 additions & 12 deletions src/core/statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,27 @@
#include <ctime>
#include <cctype>
#include <cstdint>
#include <string>
#include <sstream>

using namespace soci;
using namespace soci::details;


std::string get_name(const details::use_type_base &param, std::size_t position,
const statement_backend *backend)
{
// Use the name specified in the "use()" call if any,
// otherwise get the name of the matching parameter from
// the query itself, as parsed by the backend.
std::string name = param.get_name();
if (backend && name.empty())
name = backend->get_parameter_name(static_cast<int>(position));

return name.empty() ? std::to_string(position + 1) : name;
}


statement_impl::statement_impl(session & s)
: session_(s), refCount_(1), row_(0),
fetchSize_(1), initialFetchSize_(1),
Expand Down Expand Up @@ -574,10 +590,17 @@ void statement_impl::pre_fetch()

void statement_impl::pre_use()
{
session_.clear_query_parameters();

std::size_t const usize = uses_.size();
for (std::size_t i = 0; i != usize; ++i)
{
uses_[i]->pre_use();

std::string name = get_name(*uses_[i], i, backEnd_);
std::stringstream value;
uses_[i]->dump_value(value);
session_.add_query_parameter(std::move(name), value.str());
}
}

Expand Down Expand Up @@ -854,20 +877,9 @@ statement_impl::rethrow_current_exception_with_context(char const* operation)

details::use_type_base const& u = *uses_[i];

// Use the name specified in the "use()" call if any,
// otherwise get the name of the matching parameter from
// the query itself, as parsed by the backend.
std::string name = u.get_name();
if (name.empty())
name = backEnd_->get_parameter_name(static_cast<int>(i));
oss << ":" << get_name(u, i, backEnd_);

oss << ":";
if (!name.empty())
oss << name;
else
oss << (i + 1);
oss << "=";

u.dump_value(oss);
}
}
Expand Down
39 changes: 34 additions & 5 deletions tests/common-tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -3640,16 +3640,45 @@ TEST_CASE_METHOD(common_tests, "Basic logging support", "[core][logging]")
catch (...) {}

CHECK(sql.get_last_query() == "drop table soci_test1");
CHECK(sql.get_last_query_context() == "");

sql.set_log_stream(NULL);

try
{
sql << "drop table soci_test2";
}
catch (...) {}
auto_table_creator tableCreator(tc_.table_creator_1(sql));

int id = 1;
std::string name = "b";
sql << "insert into soci_test (name,id) values (:name,:id)", use(name, "name"), use(id, "id");

CHECK(sql.get_last_query() == "insert into soci_test (name,id) values (:name,:id)");
CHECK(sql.get_last_query_context() == R"(:name="b", :id=1)");

CHECK(sql.get_last_query() == "drop table soci_test2");
statement stmt = (sql.prepare << "insert into soci_test(name, id) values (:name, :id)");
{
id = 5;
name = "alice";
stmt.exchange(use(name, "name"));
stmt.exchange(use(id, "id"));
stmt.define_and_bind();
stmt.execute(true);
stmt.bind_clean_up();
CHECK(sql.get_last_query() == "insert into soci_test(name, id) values (:name, :id)");
CHECK(sql.get_last_query_context() == R"(:name="alice", :id=5)");
}
{
id = 42;
name = "bob";
stmt.exchange(use(name, "name"));
stmt.exchange(use(id, "id"));
stmt.define_and_bind();
stmt.execute(true);
stmt.bind_clean_up();
CHECK(sql.get_last_query() == "insert into soci_test(name, id) values (:name, :id)");
CHECK(sql.get_last_query_context() == R"(:name="bob", :id=42)");
}

}

sql.set_log_stream(&log);

Expand Down