From d0e2e4340e2baacd026b944252c724fb4de13af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 13 Oct 2025 16:14:03 +0200 Subject: [PATCH] statement binding progress --- .../postgres/include/postgres_statement.hpp | 1 - backends/postgres/src/postgres_statement.cpp | 4 +- include/matador/query/key_value_generator.hpp | 2 +- .../matador/sql/interface/statement_impl.hpp | 22 ++++-- .../matador/sql/interface/statement_proxy.hpp | 7 ++ .../matador/sql/object_parameter_binder.hpp | 78 ++----------------- include/matador/sql/object_pk_binder.hpp | 60 ++++++++++++++ include/matador/sql/statement.hpp | 15 ++++ source/orm/sql/interface/statement_impl.cpp | 31 ++++++-- source/orm/sql/interface/statement_proxy.cpp | 10 +++ source/orm/sql/object_parameter_binder.cpp | 11 +-- source/orm/sql/statement.cpp | 7 +- 12 files changed, 147 insertions(+), 101 deletions(-) create mode 100644 include/matador/sql/object_pk_binder.hpp diff --git a/backends/postgres/include/postgres_statement.hpp b/backends/postgres/include/postgres_statement.hpp index dd1b520..56a1ad9 100644 --- a/backends/postgres/include/postgres_statement.hpp +++ b/backends/postgres/include/postgres_statement.hpp @@ -15,7 +15,6 @@ public: utils::result execute(const sql::parameter_binder& bindings) override; utils::result, utils::error> fetch(const sql::parameter_binder& bindings) override; - void reset() override; protected: [[nodiscard]] std::unique_ptr create_binder() const override; diff --git a/backends/postgres/src/postgres_statement.cpp b/backends/postgres/src/postgres_statement.cpp index 6ee8a1d..ef5e8d5 100644 --- a/backends/postgres/src/postgres_statement.cpp +++ b/backends/postgres/src/postgres_statement.cpp @@ -6,7 +6,7 @@ namespace matador::backends::postgres { postgres_statement::postgres_statement(PGconn *db, std::string name, const sql::query_context &query) -: statement_impl(query) +: statement_impl(query, 0) , db_(db) , name_(std::move(name)) {} @@ -56,8 +56,6 @@ utils::result, utils::error> postgres_st return utils::ok(std::make_unique(std::make_unique(res), query_.prototype)); } -void postgres_statement::reset() {} - std::unique_ptr postgres_statement::create_binder() const { return std::make_unique(query_.bind_vars.size()); } diff --git a/include/matador/query/key_value_generator.hpp b/include/matador/query/key_value_generator.hpp index 96d0fab..bf55e90 100644 --- a/include/matador/query/key_value_generator.hpp +++ b/include/matador/query/key_value_generator.hpp @@ -29,7 +29,7 @@ public: template < class V > void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) { - // result_.emplace_back(id, x); + result_.emplace_back(id, x); } void on_revision(const char *id, uint64_t &/*rev*/); diff --git a/include/matador/sql/interface/statement_impl.hpp b/include/matador/sql/interface/statement_impl.hpp index 09e79c4..48713a5 100644 --- a/include/matador/sql/interface/statement_impl.hpp +++ b/include/matador/sql/interface/statement_impl.hpp @@ -17,7 +17,7 @@ class sql_error; class statement_impl { protected: - explicit statement_impl(query_context query); + explicit statement_impl(query_context query, size_t start_bind_pos); public: virtual ~statement_impl() = default; @@ -27,7 +27,7 @@ public: template < class Type > size_t bind_object(Type &obj, parameter_binder& bindings) { - object_parameter_binder object_binder_(query_.command != sql_command::SQL_UPDATE); + object_parameter_binder object_binder_; object_binder_.reset(start_index()); object_binder_.bind(obj, bindings); @@ -36,13 +36,21 @@ public: template < class Type > void bind(const size_t pos, Type &val, parameter_binder& bindings) { - utils::data_type_traits::bind_value(bindings, adjust_index(pos), val); + current_bind_pos_ = pos; + bind(val, bindings); } + template < class Type > + void bind(Type &val, parameter_binder& bindings) { + utils::data_type_traits::bind_value(bindings, adjust_index(current_bind_pos_++), val); + } + void bind(size_t pos, const char *value, size_t size, parameter_binder& bindings); + void bind(const char *value, size_t size, parameter_binder& bindings); + void bind(size_t pos, std::string &val, size_t size, parameter_binder& bindings); + void bind(std::string &value, size_t size, parameter_binder& bindings); - void bind(size_t pos, const char *value, size_t size, parameter_binder& bindings) const; - void bind(size_t pos, std::string &val, size_t size, parameter_binder& bindings) const; + virtual void reset(); - virtual void reset() = 0; + [[nodiscard]] size_t bind_pos() const; [[nodiscard]] const std::vector& bind_vars() const; [[nodiscard]] bool is_valid_host_var(const std::string &host_var, size_t pos) const; @@ -57,6 +65,8 @@ protected: friend class statement_proxy; query_context query_; + size_t start_bind_pos_{0}; + size_t current_bind_pos_{0}; }; } diff --git a/include/matador/sql/interface/statement_proxy.hpp b/include/matador/sql/interface/statement_proxy.hpp index d5d3601..b57546c 100644 --- a/include/matador/sql/interface/statement_proxy.hpp +++ b/include/matador/sql/interface/statement_proxy.hpp @@ -23,10 +23,17 @@ public: void bind(size_t pos, Type &value, parameter_binder& bindings) { statement_->bind(pos, value, bindings); } + template + void bind(Type &value, parameter_binder& bindings) { + statement_->bind(value, bindings); + } void bind(size_t pos, const char *value, size_t size, parameter_binder& bindings) const; + void bind(const char *value, size_t size, parameter_binder& bindings) const; void bind(size_t pos, std::string &val, size_t size, parameter_binder& bindings) const; + void bind(std::string &val, size_t size, parameter_binder& bindings) const; void reset() const; + [[nodiscard]] size_t bind_pos() const; [[nodiscard]] std::string sql() const; diff --git a/include/matador/sql/object_parameter_binder.hpp b/include/matador/sql/object_parameter_binder.hpp index 8d62185..554ac6a 100644 --- a/include/matador/sql/object_parameter_binder.hpp +++ b/include/matador/sql/object_parameter_binder.hpp @@ -1,68 +1,12 @@ #ifndef QUERY_OBJECT_PARAMETER_BINDER_HPP #define QUERY_OBJECT_PARAMETER_BINDER_HPP -#include "matador/utils/attribute_writer.hpp" -#include "matador/utils/default_type_traits.hpp" - -#include "matador/utils/access.hpp" -#include "matador/utils/field_attributes.hpp" -#include "matador/utils/foreign_attributes.hpp" -#include "matador/utils/primary_key_attribute.hpp" +#include "matador/sql/object_pk_binder.hpp" namespace matador::sql { -namespace detail { - -class fk_binder -{ -public: - template - void bind(Type &obj, const size_t column_index, utils::attribute_writer &binder) - { - binder_ = &binder; - index_ = column_index; - access::process(*this, obj); - binder_ = nullptr; - } - - template - void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes); - static void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {} - - template < class Type > - static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} - template < class Pointer > - static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} - template < class Pointer > - static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} - - template - static void on_has_many(const char * /*id*/, - ContainerType &/*c*/, - const char * /*join_column*/, - const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} - template - static void on_has_many_to_many(const char * /*id*/, - ContainerType &/*c*/, - const char * /*join_column*/, - const char * /*inverse_join_column*/, - const utils::foreign_attributes &/*attr*/) {} - template - static void on_has_many_to_many(const char * /*id*/, - ContainerType &/*c*/, - const utils::foreign_attributes &/*attr*/) {} - -private: - utils::attribute_writer *binder_{}; - size_t index_{0}; -}; - -} - class object_parameter_binder { public: - explicit object_parameter_binder(bool include_primary_key = true); - template void bind(Type &obj, utils::attribute_writer &binder) { binder_ = &binder; @@ -75,9 +19,7 @@ public: template < class Type > void on_primary_key(const char * /*id*/, Type &val, const utils::primary_key_attribute& attr = utils::default_pk_attributes) { - if (include_primary_key_) { - utils::data_type_traits::bind_value(*binder_, index_++, val, attr.size()); - } + utils::data_type_traits::bind_value(*binder_, index_++, val, attr.size()); } void on_revision(const char *id, uint64_t &/*rev*/); @@ -88,11 +30,11 @@ public: template class Pointer> void on_belongs_to(const char * /*id*/, Pointer &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) { - fk_binder_.bind(*x, index_++, *binder_); + pk_binder_.bind(*x, index_++, *binder_); } template class Pointer> void on_has_one(const char * /*id*/, Pointer &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) { - fk_binder_.bind(*x, index_++, *binder_); + pk_binder_.bind(*x, index_++, *binder_); } template static void on_has_many(const char * /*id*/, @@ -113,17 +55,7 @@ public: private: utils::attribute_writer *binder_{}; size_t index_{0}; - detail::fk_binder fk_binder_; - bool include_primary_key_{true}; + object_pk_binder pk_binder_; }; - -namespace detail { - -template -void fk_binder::on_primary_key(const char * /*id*/, ValueType &value, const utils::primary_key_attribute& attr) { - utils::data_type_traits::bind_value(*binder_, index_++, value, attr.size()); -} - -} } #endif //QUERY_OBJECT_PARAMETER_BINDER_HPP diff --git a/include/matador/sql/object_pk_binder.hpp b/include/matador/sql/object_pk_binder.hpp new file mode 100644 index 0000000..17a9cd2 --- /dev/null +++ b/include/matador/sql/object_pk_binder.hpp @@ -0,0 +1,60 @@ +#ifndef MATADOR_OBJECT_PK_BINDER_HPP +#define MATADOR_OBJECT_PK_BINDER_HPP + +#include "matador/utils/access.hpp" +#include "matador/utils/attribute_writer.hpp" +#include "matador/utils/default_type_traits.hpp" +#include "matador/utils/field_attributes.hpp" +#include "matador/utils/foreign_attributes.hpp" +#include "matador/utils/primary_key_attribute.hpp" + +namespace matador::sql { +class object_pk_binder { +public: + template + void bind(Type &obj, const size_t column_index, utils::attribute_writer &binder) { + binder_ = &binder; + index_ = column_index; + access::process(*this, obj); + binder_ = nullptr; + } + + template + void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes); + static void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {} + + template < class Type > + static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} + template < class Pointer > + static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} + template < class Pointer > + static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} + + template + static void on_has_many(const char * /*id*/, + ContainerType &/*c*/, + const char * /*join_column*/, + const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} + template + static void on_has_many_to_many(const char * /*id*/, + ContainerType &/*c*/, + const char * /*join_column*/, + const char * /*inverse_join_column*/, + const utils::foreign_attributes &/*attr*/) {} + template + static void on_has_many_to_many(const char * /*id*/, + ContainerType &/*c*/, + const utils::foreign_attributes &/*attr*/) {} + +private: + utils::attribute_writer *binder_{}; + size_t index_{0}; +}; + +template +void object_pk_binder::on_primary_key(const char * /*id*/, ValueType &value, const utils::primary_key_attribute& attr) { + utils::data_type_traits::bind_value(*binder_, index_++, value, attr.size()); +} + +} +#endif //MATADOR_OBJECT_PK_BINDER_HPP \ No newline at end of file diff --git a/include/matador/sql/statement.hpp b/include/matador/sql/statement.hpp index d32ade9..73ef331 100644 --- a/include/matador/sql/statement.hpp +++ b/include/matador/sql/statement.hpp @@ -121,6 +121,21 @@ public: */ void reset() const; + /** + * Returns the current binding position. + * Is set to the initial position after + * a call to reset(). + * + * @return The current binding position + */ + [[nodiscard]] size_t bind_pos() const; + + /** + * Returns the statements underlying SQL + * query string. + * + * @return The underlying SQL string + */ [[nodiscard]] std::string sql() const; [[nodiscard]] utils::result, utils::error> fetch_internal() const; diff --git a/source/orm/sql/interface/statement_impl.cpp b/source/orm/sql/interface/statement_impl.cpp index ba31d01..86de264 100644 --- a/source/orm/sql/interface/statement_impl.cpp +++ b/source/orm/sql/interface/statement_impl.cpp @@ -2,16 +2,35 @@ namespace matador::sql { -statement_impl::statement_impl(query_context query) +statement_impl::statement_impl(query_context query, const size_t start_bind_pos) : query_(std::move(query)) +, start_bind_pos_(start_bind_pos) {} -void statement_impl::bind(const size_t pos, const char *value, const size_t size, parameter_binder& bindings) const { - utils::data_type_traits::bind_value(bindings, adjust_index(pos), value, size); +void statement_impl::bind(const size_t pos, const char *value, const size_t size, parameter_binder& bindings) { + current_bind_pos_ = pos; + bind(value, size, bindings); } -void statement_impl::bind(const size_t pos, std::string &val, const size_t size, parameter_binder& bindings) const { - utils::data_type_traits::bind_value(bindings, adjust_index(pos), val, size); +void statement_impl::bind(const char* value, const size_t size, parameter_binder& bindings) { + utils::data_type_traits::bind_value(bindings, adjust_index(current_bind_pos_++), value, size); +} + +void statement_impl::bind(const size_t pos, std::string &value, const size_t size, parameter_binder& bindings) { + current_bind_pos_ = pos; + bind(value, size, bindings); +} + +void statement_impl::bind(std::string& value, const size_t size, parameter_binder& bindings) { + utils::data_type_traits::bind_value(bindings, adjust_index(current_bind_pos_++), value, size); +} + +void statement_impl::reset() { + current_bind_pos_ = start_bind_pos_; +} + +size_t statement_impl::bind_pos() const { + return current_bind_pos_; } const std::vector &statement_impl::bind_vars() const { @@ -25,7 +44,7 @@ bool statement_impl::is_valid_host_var(const std::string &host_var, const size_t } size_t statement_impl::start_index() const { - return 0; + return start_bind_pos_; } size_t statement_impl::adjust_index(const size_t index) const { diff --git a/source/orm/sql/interface/statement_proxy.cpp b/source/orm/sql/interface/statement_proxy.cpp index 429dc00..ff4eb4c 100644 --- a/source/orm/sql/interface/statement_proxy.cpp +++ b/source/orm/sql/interface/statement_proxy.cpp @@ -7,14 +7,24 @@ statement_proxy::statement_proxy(std::unique_ptr&& stmt) void statement_proxy::bind(const size_t pos, const char* value, const size_t size, parameter_binder& bindings) const { statement_->bind(pos, value, size, bindings); } +void statement_proxy::bind(const char* value, const size_t size, parameter_binder& bindings) const { + statement_->bind(value, size, bindings); +} void statement_proxy::bind(const size_t pos, std::string& val, const size_t size, parameter_binder& bindings) const { statement_->bind(pos, val, size, bindings); } +void statement_proxy::bind(std::string& val, const size_t size, parameter_binder& bindings) const { + statement_->bind(val, size, bindings); +} void statement_proxy::reset() const { statement_->reset(); } +size_t statement_proxy::bind_pos() const { + return statement_->bind_pos(); +} + std::string statement_proxy::sql() const { return statement_->query_.sql; } diff --git a/source/orm/sql/object_parameter_binder.cpp b/source/orm/sql/object_parameter_binder.cpp index 03fad1b..84ab192 100644 --- a/source/orm/sql/object_parameter_binder.cpp +++ b/source/orm/sql/object_parameter_binder.cpp @@ -1,13 +1,7 @@ #include "matador/sql/object_parameter_binder.hpp" -#include "matador/sql/interface/parameter_binder.hpp" namespace matador::sql { -object_parameter_binder::object_parameter_binder(bool include_primary_key) -: include_primary_key_(include_primary_key) { -} - -void object_parameter_binder::reset(const size_t start_index) -{ +void object_parameter_binder::reset(const size_t start_index) { index_ = start_index; } @@ -15,8 +9,7 @@ size_t object_parameter_binder::current_index() const { return index_; } -void object_parameter_binder::on_revision(const char * /*id*/, uint64_t &rev) -{ +void object_parameter_binder::on_revision(const char * /*id*/, uint64_t &rev) { utils::data_type_traits::bind_value(*binder_, index_++, rev); } diff --git a/source/orm/sql/statement.cpp b/source/orm/sql/statement.cpp index dfe8f3f..0c0be42 100644 --- a/source/orm/sql/statement.cpp +++ b/source/orm/sql/statement.cpp @@ -86,11 +86,14 @@ utils::result, utils::error> statement::fetch_one() const return utils::ok(std::optional{*first.release()}); } -void statement::reset() const -{ +void statement::reset() const { statement_proxy_->reset(); } +size_t statement::bind_pos() const { + return statement_proxy_->bind_pos(); +} + std::string statement::sql() const { return statement_proxy_->sql(); }