From 1aa67c6604bdbde070a821fe8c4608e3edd86bc0 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Tue, 19 Nov 2013 19:21:58 +0100 Subject: [PATCH 01/26] Added parameter and parameter_list parameters are to be used as placeholders in the query. parameter lists are to be used to assign values to these parameters and forward them to the database. --- include/sqlpp11/parameter.h | 52 +++++++++++++++++++++++++++ include/sqlpp11/parameter_list.h | 61 ++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 include/sqlpp11/parameter.h create mode 100644 include/sqlpp11/parameter_list.h diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h new file mode 100644 index 00000000..355c82da --- /dev/null +++ b/include/sqlpp11/parameter.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_PARAMETER_H +#define SQLPP_PARAMETER_H + +#include +#include +#include + +namespace sqlpp +{ + template + struct parameter_t + { + using _is_parameter = std::true_type; + + template + void serialize(std::ostream& os, Db& db) const + { + static_assert(Db::_supports_parameter, "parameter not supported by current database"); + os << " ? "; + } + + using _member_t = NameType::_name_t::_member_t; + }; +} + +#endif diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h new file mode 100644 index 00000000..39d297ed --- /dev/null +++ b/include/sqlpp11/parameter_list.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_PARAMETER_H +#define SQLPP_PARAMETER_H + +#include + +namespace sqlpp +{ + template + struct named_parameter_list_t: public Parameter::_member_t... + { + named_parameter_list_t(): + Parameter::_member_t()..., + _parameter_tuple(static_cast(*this)()...) + {} + + named_parameter_list_t(const named_parameter_list_t& rhs): + Parameter::_member_t(static_cast(rhs))..., + _parameter_tuple(static_cast(*this)()...) + {} + + named_parameter_list_t(named_parameter_list_t&& rhs): + Parameter::_member_t(std::move(static_cast(rhs)))..., + _parameter_tuple(static_cast(*this)()...) + {} + + named_parameter_list_t& operator=(const named_parameter_list_t&) = delete; + named_parameter_list_t& operator=(named_parameter_list_t&&) = delete; + ~named_parameter_list_t() = default; + + std::tuple _parameter_tuple; + }; + +} + +#endif From 8f99a03359efba729469ad7391ae80e28ebc7228 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Fri, 22 Nov 2013 09:42:28 +0100 Subject: [PATCH 02/26] Can extract parameters from expression --- include/sqlpp11/boolean.h | 1 + include/sqlpp11/expression.h | 10 ++-- include/sqlpp11/floating_point.h | 1 + include/sqlpp11/functions.h | 2 + include/sqlpp11/integral.h | 1 + include/sqlpp11/like.h | 1 + include/sqlpp11/parameter.h | 11 ++++- include/sqlpp11/parameter_list.h | 33 ++++++++++++- include/sqlpp11/text.h | 1 + include/sqlpp11/type_traits.h | 1 + tests/CMakeLists.txt | 1 + tests/PreparedTest.cpp | 79 ++++++++++++++++++++++++++++++++ 12 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 tests/PreparedTest.cpp diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 00ffbc3a..8358da7f 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -63,6 +63,7 @@ namespace sqlpp using _is_boolean = std::true_type; using _is_value = std::true_type; using _is_expression = std::true_type; + using _cpp_value_type = bool; struct plus_ { diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index 9a5b2288..261fb2fa 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -40,6 +40,7 @@ namespace sqlpp using _is_assignment = std::true_type; using column_type = Lhs; using value_type = Rhs; + using _parameters = std::tuple; template void serialize(std::ostream& os, Db& db) const @@ -64,6 +65,7 @@ namespace sqlpp struct equal_t: public ValueType::template operators> { using _value_type = ValueType; + using _parameters = std::tuple; template equal_t(L&& l, R&& r): @@ -103,6 +105,7 @@ namespace sqlpp struct not_equal_t: public ValueType::template operators> { using _value_type = ValueType; + using _parameters = std::tuple; template not_equal_t(L&& l, R&& r): @@ -142,10 +145,10 @@ namespace sqlpp struct not_t: public ValueType::template operators> { using _value_type = ValueType; + using _parameters = std::tuple; - template - not_t(L&& l): - _lhs(std::forward(l)) + not_t(Lhs l): + _lhs(l) {} not_t(const not_t&) = default; @@ -179,6 +182,7 @@ namespace sqlpp struct binary_expression_t: public O::_value_type::template operators> { using _value_type = typename O::_value_type; + using _parameters = std::tuple; binary_expression_t(Lhs&& l, Rhs&& r): _lhs(std::move(l)), diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 65215ac5..eb030ee9 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -46,6 +46,7 @@ namespace sqlpp using _is_floating_point = std::true_type; using _is_value = std::true_type; using _is_expression = std::true_type; + using _cpp_value_type = double; template struct _result_entry_t diff --git a/include/sqlpp11/functions.h b/include/sqlpp11/functions.h index 54d49b3a..bdd45294 100644 --- a/include/sqlpp11/functions.h +++ b/include/sqlpp11/functions.h @@ -28,6 +28,8 @@ #define SQLPP_FUNCTIONS_H #include +#include +#include #include #include #include diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index cbf0b298..fca44822 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -46,6 +46,7 @@ namespace sqlpp using _is_integral = std::true_type; using _is_value = std::true_type; using _is_expression = std::true_type; + using _cpp_value_type = int64_t; template struct _result_entry_t diff --git a/include/sqlpp11/like.h b/include/sqlpp11/like.h index 51e7698c..f2ea27cd 100644 --- a/include/sqlpp11/like.h +++ b/include/sqlpp11/like.h @@ -41,6 +41,7 @@ namespace sqlpp { static_assert(is_text_t::value, "Operand for like() has to be a text"); static_assert(is_text_t::value, "Pattern for like() has to be a text"); + using _parameters = std::tuple; struct _value_type: public ValueType::_base_value_type // we requite fully defined boolean here { diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index 355c82da..3de5e6d9 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -37,6 +37,8 @@ namespace sqlpp struct parameter_t { using _is_parameter = std::true_type; + using _value_type = ValueType; + using _is_expression_t = std::true_type; template void serialize(std::ostream& os, Db& db) const @@ -45,8 +47,15 @@ namespace sqlpp os << " ? "; } - using _member_t = NameType::_name_t::_member_t; + using _member_t = typename NameType::_name_t::template _member_t; }; + + template + auto parameter(NamedExpr&& namedExpr) + -> parameter_t::type::_value_type, typename std::decay::type> + { + return {}; + } } #endif diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index 39d297ed..071e849e 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -24,8 +24,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_PARAMETER_H -#define SQLPP_PARAMETER_H +#ifndef SQLPP_PARAMETER_LIST_H +#define SQLPP_PARAMETER_LIST_H #include @@ -56,6 +56,35 @@ namespace sqlpp std::tuple _parameter_tuple; }; + namespace detail + { + template + struct get_parameter_tuple + { + using type = std::tuple<>; + }; + + template + struct get_parameter_tuple::value, void>::type> + { + using type = std::tuple; + }; + + template + struct get_parameter_tuple, void> + { + // cat together parameter tuples + using type = decltype(std::tuple_cat(std::declval::type>()...)); + }; + + template + struct get_parameter_tuple::value, void>::type> + { + using type = typename get_parameter_tuple::type; + }; + + } + } #endif diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 8ba3d6b7..e2470242 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -46,6 +46,7 @@ namespace sqlpp using _is_text = std::true_type; using _is_value = std::true_type; using _is_expression = std::true_type; + using _cpp_value_type = std::string; template struct _result_entry_t diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index ef495acf..d4afca01 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -116,6 +116,7 @@ namespace sqlpp SQLPP_TYPE_TRAIT_GENERATOR(is_insert_list); SQLPP_TYPE_TRAIT_GENERATOR(is_sort_order); SQLPP_TYPE_TRAIT_GENERATOR(requires_braces); + SQLPP_TYPE_TRAIT_GENERATOR(is_parameter); SQLPP_CONNECTOR_TRAIT_GENERATOR(has_empty_list_insert); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index abc1625f..ebf4c6f1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,4 +8,5 @@ build_and_run(RemoveTest) build_and_run(UpdateTest) build_and_run(SelectTest) build_and_run(FunctionTest) +build_and_run(PreparedTest) diff --git a/tests/PreparedTest.cpp b/tests/PreparedTest.cpp new file mode 100644 index 00000000..eed5920d --- /dev/null +++ b/tests/PreparedTest.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include "MockDb.h" +#include "is_regular.h" +#include + +#include + +DbMock db = {}; + +int main() +{ + TabSample t; + TabFoo f; + + // empty parameter lists + { + using T = typename sqlpp::detail::get_parameter_tuple::type; + static_assert(std::is_same>::value, "type requirement"); + } + + // single parameter + { + using T = typename sqlpp::detail::get_parameter_tuple::type; + static_assert(std::is_same>::value, "type requirement"); + } + + // single parameter + { + using T = typename sqlpp::detail::get_parameter_tuple::type; + static_assert(std::is_same>::value, "type requirement"); + } + + // single parameter in expression + { + using T = typename sqlpp::detail::get_parameter_tuple::type; + static_assert(std::is_same>::value, "type requirement"); + } + + // single parameter in larger expression + { + using T = typename sqlpp::detail::get_parameter_tuple::type; + static_assert(std::is_same>::value, "type requirement"); + } + + // three parameters in expression + { + using T = typename sqlpp::detail::get_parameter_tuple::type; + static_assert(std::tuple_size::value == 3, "type requirement"); + static_assert(std::is_same>::value, "type requirement"); + } + + + return 0; +} From 221e20918b1f08122331920f53c17a4d9d42c81f Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Tue, 26 Nov 2013 23:45:31 +0100 Subject: [PATCH 03/26] select now collects parameters from Where and Having --- include/sqlpp11/expression.h | 10 ++++---- include/sqlpp11/having.h | 3 ++- include/sqlpp11/like.h | 2 +- include/sqlpp11/parameter_list.h | 44 ++++++++++++++++++++++++++------ include/sqlpp11/select.h | 2 ++ include/sqlpp11/where.h | 3 ++- tests/FunctionTest.cpp | 2 +- tests/PreparedTest.cpp | 30 ++++++++++++++++++++++ tests/TabSample.h | 10 ++++++++ 9 files changed, 89 insertions(+), 17 deletions(-) diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index 261fb2fa..607bca33 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -40,7 +40,7 @@ namespace sqlpp using _is_assignment = std::true_type; using column_type = Lhs; using value_type = Rhs; - using _parameters = std::tuple; + using _parameter_t = std::tuple; template void serialize(std::ostream& os, Db& db) const @@ -65,7 +65,7 @@ namespace sqlpp struct equal_t: public ValueType::template operators> { using _value_type = ValueType; - using _parameters = std::tuple; + using _parameter_t = std::tuple; template equal_t(L&& l, R&& r): @@ -105,7 +105,7 @@ namespace sqlpp struct not_equal_t: public ValueType::template operators> { using _value_type = ValueType; - using _parameters = std::tuple; + using _parameter_t = std::tuple; template not_equal_t(L&& l, R&& r): @@ -145,7 +145,7 @@ namespace sqlpp struct not_t: public ValueType::template operators> { using _value_type = ValueType; - using _parameters = std::tuple; + using _parameter_t = std::tuple; not_t(Lhs l): _lhs(l) @@ -182,7 +182,7 @@ namespace sqlpp struct binary_expression_t: public O::_value_type::template operators> { using _value_type = typename O::_value_type; - using _parameters = std::tuple; + using _parameter_t = std::tuple; binary_expression_t(Lhs&& l, Rhs&& r): _lhs(std::move(l)), diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index 0547a969..ec31d62e 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -65,7 +65,8 @@ namespace sqlpp _dynamic_expressions.serialize(os, db, " AND ", sizeof...(Expr) == 0); } - std::tuple _expressions; + using _parameter_t = std::tuple; + _parameter_t _expressions; detail::serializable_list _dynamic_expressions; }; diff --git a/include/sqlpp11/like.h b/include/sqlpp11/like.h index f2ea27cd..d0d037b1 100644 --- a/include/sqlpp11/like.h +++ b/include/sqlpp11/like.h @@ -41,7 +41,7 @@ namespace sqlpp { static_assert(is_text_t::value, "Operand for like() has to be a text"); static_assert(is_text_t::value, "Pattern for like() has to be a text"); - using _parameters = std::tuple; + using _parameter_t = std::tuple; struct _value_type: public ValueType::_base_value_type // we requite fully defined boolean here { diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index 071e849e..249c0391 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -27,33 +27,54 @@ #ifndef SQLPP_PARAMETER_LIST_H #define SQLPP_PARAMETER_LIST_H +#include #include namespace sqlpp { + template + struct named_parameter_list_t + { + static_assert(detail::wrong::value, "Template parameter for named_parameter_list_t has to be a tuple"); + }; + template - struct named_parameter_list_t: public Parameter::_member_t... + struct named_parameter_list_t>: public Parameter::_member_t... { named_parameter_list_t(): Parameter::_member_t()..., _parameter_tuple(static_cast(*this)()...) {} - named_parameter_list_t(const named_parameter_list_t& rhs): + named_parameter_list_t(const named_parameter_list_t& rhs) + noexcept(std::is_nothrow_copy_constructible>::value): Parameter::_member_t(static_cast(rhs))..., _parameter_tuple(static_cast(*this)()...) {} - named_parameter_list_t(named_parameter_list_t&& rhs): + named_parameter_list_t(named_parameter_list_t&& rhs) + noexcept(std::is_nothrow_move_constructible>::value): Parameter::_member_t(std::move(static_cast(rhs)))..., _parameter_tuple(static_cast(*this)()...) {} - named_parameter_list_t& operator=(const named_parameter_list_t&) = delete; - named_parameter_list_t& operator=(named_parameter_list_t&&) = delete; + named_parameter_list_t& operator=(const named_parameter_list_t& rhs) + noexcept(std::is_nothrow_copy_assignable>::value) + { + _parameter_tuple = rhs._parameter_tuple; + return *this; + } + + named_parameter_list_t& operator=(named_parameter_list_t&& rhs) + noexcept(std::is_nothrow_move_assignable>::value) + { + _parameter_tuple = std::move(rhs._parameter_tuple); + return *this; + } + ~named_parameter_list_t() = default; - std::tuple _parameter_tuple; + std::tuple _parameter_tuple; }; namespace detail @@ -78,13 +99,20 @@ namespace sqlpp }; template - struct get_parameter_tuple::value, void>::type> + struct get_parameter_tuple::value, void>::type> { - using type = typename get_parameter_tuple::type; + using type = typename get_parameter_tuple::type; }; } + template + auto named_parameter_list(const Exp& exp) + -> named_parameter_list_t::type>::type> + { + return {}; + } + } #endif diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 82fb0869..4f62e01e 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -589,6 +590,7 @@ namespace sqlpp OrderBy _order_by; Limit _limit; Offset _offset; + decltype(named_parameter_list(std::declval>())) _parameter_list; }; // construct select flag list diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 56d517a3..ca2008d4 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -64,7 +64,8 @@ namespace sqlpp _dynamic_expressions.serialize(os, db, " AND ", sizeof...(Expr) == 0); } - std::tuple _expressions; + using _parameter_t = std::tuple; + _parameter_t _expressions; detail::serializable_list _dynamic_expressions; }; } diff --git a/tests/FunctionTest.cpp b/tests/FunctionTest.cpp index 0cf35d4f..f4b24e93 100644 --- a/tests/FunctionTest.cpp +++ b/tests/FunctionTest.cpp @@ -32,6 +32,7 @@ #include DbMock db = {}; +SQLPP_ALIAS_PROVIDER_GENERATOR(kaesekuchen); int main() { @@ -374,7 +375,6 @@ int main() // test verbatim_table alias { - SQLPP_ALIAS_PROVIDER_GENERATOR(kaesekuchen); using T = decltype(sqlpp::verbatim_table("cheesecake").as(kaesekuchen)); static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); static_assert(not sqlpp::is_expression_t::value, "type requirement"); diff --git a/tests/PreparedTest.cpp b/tests/PreparedTest.cpp index eed5920d..ae6fc935 100644 --- a/tests/PreparedTest.cpp +++ b/tests/PreparedTest.cpp @@ -27,6 +27,7 @@ #include "MockDb.h" #include "is_regular.h" #include +#include #include @@ -74,6 +75,35 @@ int main() static_assert(std::is_same>::value, "type requirement"); } + // OK, fine, now create a named parameter list from an expression + { + auto npl = named_parameter_list(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma)); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + + static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.beta)&>::value, "type requirement"); + static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.alpha)&>::value, "type requirement"); + static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.gamma)&>::value, "type requirement"); + } + + // Wonderful, now take a look at the parameter list of a select + { + auto npl = select(all_of(t)).from(t).where(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma))._parameter_list; + + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + + static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.beta)&>::value, "type requirement"); + static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.alpha)&>::value, "type requirement"); + static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.gamma)&>::value, "type requirement"); + npl.alpha = 7; + auto x = npl; + x = npl; + std::cerr << x.alpha << std::endl; + } + return 0; } diff --git a/tests/TabSample.h b/tests/TabSample.h index 903bf62d..85f78ac1 100644 --- a/tests/TabSample.h +++ b/tests/TabSample.h @@ -42,6 +42,8 @@ namespace TabFoo_ struct _member_t { T epsilon; + T& operator()() { return epsilon; } + const T& operator()() const { return epsilon; } }; }; using _value_type = sqlpp::bigint; @@ -59,6 +61,8 @@ namespace TabFoo_ struct _member_t { T omega; + T& operator()() { return omega; } + const T& operator()() const { return omega; } }; }; using _value_type = sqlpp::floating_point; @@ -102,6 +106,8 @@ namespace TabSample_ struct _member_t { T alpha; + T& operator()() { return alpha; } + const T& operator()() const { return alpha; } }; }; using _value_type = sqlpp::bigint; @@ -124,6 +130,8 @@ namespace TabSample_ struct _member_t { T beta; + T& operator()() { return beta; } + const T& operator()() const { return beta; } }; }; using _value_type = sqlpp::varchar; @@ -144,6 +152,8 @@ namespace TabSample_ struct _member_t { T gamma; + T& operator()() { return gamma; } + const T& operator()() const { return gamma; } }; }; using _value_type = sqlpp::boolean; From 51786a9f1de37e19c8c3e2137120d6cddffc819f Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Thu, 28 Nov 2013 11:12:44 +0100 Subject: [PATCH 04/26] Added a prepared_select_t type and a prepare method for select This is not done yet, but it indicates the way to go... --- include/sqlpp11/prepared_select.h | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 include/sqlpp11/prepared_select.h diff --git a/include/sqlpp11/prepared_select.h b/include/sqlpp11/prepared_select.h new file mode 100644 index 00000000..a93c229b --- /dev/null +++ b/include/sqlpp11/prepared_select.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_PREPARED_SELECT_H +#define SQLPP_PREPARED_SELECT_H + +#include +#include + +namespace sqlpp +{ + template + struct prepared_select_t + { + using _result_row_t = typename Select::_result_row_t; + using _parameter_list_t = typename Select::_parameter_list_t; + + typename Db::prepared_query_handle _name; + }; + +} + +#endif From 9597c3712c00bd373a69d89512e9d34f2f8b8e88 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sun, 15 Dec 2013 13:02:41 +0100 Subject: [PATCH 05/26] Moved result construction more towards connector. This will make it easier to handle different formats --- include/sqlpp11/parameter_list.h | 31 ++++++++++--------- include/sqlpp11/prepared_select.h | 14 +++++++-- include/sqlpp11/result.h | 51 ++++++++++++++----------------- include/sqlpp11/result_row.h | 21 +++++++++++-- include/sqlpp11/select.h | 23 ++++++++++++-- tests/PreparedTest.cpp | 11 +++++-- 6 files changed, 98 insertions(+), 53 deletions(-) diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index 249c0391..664a4274 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -33,48 +33,50 @@ namespace sqlpp { template - struct named_parameter_list_t + struct parameter_list_t { - static_assert(detail::wrong::value, "Template parameter for named_parameter_list_t has to be a tuple"); + static_assert(detail::wrong::value, "Template parameter for parameter_list_t has to be a tuple"); }; template - struct named_parameter_list_t>: public Parameter::_member_t... + struct parameter_list_t>: public Parameter::_member_t... { - named_parameter_list_t(): + parameter_list_t(): Parameter::_member_t()..., _parameter_tuple(static_cast(*this)()...) {} - named_parameter_list_t(const named_parameter_list_t& rhs) + parameter_list_t(const parameter_list_t& rhs) noexcept(std::is_nothrow_copy_constructible>::value): Parameter::_member_t(static_cast(rhs))..., _parameter_tuple(static_cast(*this)()...) {} - named_parameter_list_t(named_parameter_list_t&& rhs) + parameter_list_t(parameter_list_t&& rhs) noexcept(std::is_nothrow_move_constructible>::value): Parameter::_member_t(std::move(static_cast(rhs)))..., _parameter_tuple(static_cast(*this)()...) {} - named_parameter_list_t& operator=(const named_parameter_list_t& rhs) + parameter_list_t& operator=(const parameter_list_t& rhs) noexcept(std::is_nothrow_copy_assignable>::value) { _parameter_tuple = rhs._parameter_tuple; return *this; } - named_parameter_list_t& operator=(named_parameter_list_t&& rhs) + parameter_list_t& operator=(parameter_list_t&& rhs) noexcept(std::is_nothrow_move_assignable>::value) { _parameter_tuple = std::move(rhs._parameter_tuple); return *this; } - ~named_parameter_list_t() = default; + ~parameter_list_t() = default; - std::tuple _parameter_tuple; + using parameter_tuple_t = std::tuple; + using size = std::tuple_size; + parameter_tuple_t _parameter_tuple; }; namespace detail @@ -107,11 +109,10 @@ namespace sqlpp } template - auto named_parameter_list(const Exp& exp) - -> named_parameter_list_t::type>::type> - { - return {}; - } + struct make_parameter_list_t + { + using type = parameter_list_t::type>::type>; + }; } diff --git a/include/sqlpp11/prepared_select.h b/include/sqlpp11/prepared_select.h index a93c229b..867c16fd 100644 --- a/include/sqlpp11/prepared_select.h +++ b/include/sqlpp11/prepared_select.h @@ -28,7 +28,7 @@ #define SQLPP_PREPARED_SELECT_H #include -#include +#include namespace sqlpp { @@ -37,8 +37,18 @@ namespace sqlpp { using _result_row_t = typename Select::_result_row_t; using _parameter_list_t = typename Select::_parameter_list_t; + using _dynamic_names_t = typename Select::_dynamic_names_t; + using _handle_t = typename Db::_prepared_handle_t; - typename Db::prepared_query_handle _name; + auto run(Db& db) const + -> result_t + { + return {db.run_prepared_select(_handle, params), _dynamic_names}; + } + + _parameter_list_t params; + _dynamic_names_t _dynamic_names; + _handle_t _handle; }; } diff --git a/include/sqlpp11/result.h b/include/sqlpp11/result.h index 3acf6de4..8c346f4e 100644 --- a/include/sqlpp11/result.h +++ b/include/sqlpp11/result.h @@ -33,31 +33,27 @@ namespace sqlpp { - template + template class result_t { - using db_result_t = typename Db::_result_t; + using db_result_t = DbResult; + using result_row_t = typename db_result_t::result_row_t; - db_result_t _result; - raw_result_row_t _raw_result_row; - raw_result_row_t _end; - DynamicNames _dynamic_columns; // only needed in case of dynamic columns in the select - ResultRow _result_row; + db_result_t _db_result; + result_row_t _result_row; + result_row_t _end; public: result_t(): - _raw_result_row({}), - _end({}), - _dynamic_columns(), - _result_row(_raw_result_row, _dynamic_columns) + _db_result(), + _result_row(), + _end() {} - result_t(db_result_t&& result, DynamicNames dynamic_columns): - _result(std::move(result)), - _raw_result_row(_result.next()), - _end({}), - _dynamic_columns(dynamic_columns), - _result_row(_raw_result_row, _dynamic_columns) + result_t(db_result_t&& result): + _db_result(std::move(result)), + _result_row(_db_result.next()), + _end({}) {} result_t(const result_t&) = delete; @@ -69,26 +65,26 @@ namespace sqlpp class iterator { public: - iterator(result_t& result, raw_result_row_t& raw_result_row): + iterator(result_t& result, result_row_t& result_row): _result(result), - _raw_result_row(raw_result_row) + _result_row(result_row) { //std::cerr << "result::iterator::constructor" << std::endl; } - const ResultRow& operator*() const + const result_row_t& operator*() const { return _result.front(); } - const ResultRow* operator->() const + const result_row_t* operator->() const { return &_result.front(); } bool operator==(const iterator& rhs) const { - return _raw_result_row == rhs._raw_result_row; + return _result_row == rhs._result_row; } bool operator!=(const iterator& rhs) const @@ -102,12 +98,12 @@ namespace sqlpp } result_t& _result; - raw_result_row_t& _raw_result_row; + result_row_t& _result_row; }; iterator begin() { - return iterator(*this, _raw_result_row); + return iterator(*this, _result_row); } iterator end() @@ -115,20 +111,19 @@ namespace sqlpp return iterator(*this, _end); } - const ResultRow& front() const + const result_row_t& front() const { return _result_row; } bool empty() const { - return _raw_result_row == _end; + return _result_row == _end; } void pop_front() { - _raw_result_row = _result.next(); - _result_row = _raw_result_row; + _result_row = _db_result.next(); } }; diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 827dad68..59f95d4b 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -103,21 +103,36 @@ namespace sqlpp { using _impl = detail::result_row_impl<0, 0, NamedExpr...>; bool _is_row; + raw_result_row_t _raw_result_row; + + result_row_t(): + _raw_result_row(), + _impl(_raw_result_row), + _is_row(false) + { + } template result_row_t(const raw_result_row_t& raw_result_row, const T&): - _impl(raw_result_row), - _is_row(raw_result_row.data != nullptr) + _raw_result_row(raw_result_row), + _impl(_raw_result_row), + _is_row(_raw_result_row.data != nullptr) { } result_row_t& operator=(const raw_result_row_t& raw_result_row) { _impl::operator=(raw_result_row); - _is_row = raw_result_row.data != nullptr; + _raw_result_row = raw_result_row; + _is_row = _raw_result_row.data != nullptr; return *this; } + bool operator==(const result_row_t& rhs) + { + return _raw_result_row == rhs._raw_result_row; + } + explicit operator bool() const { return _is_row; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 4f62e01e..88dfb636 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -569,7 +570,21 @@ namespace sqlpp // Execute template - result_t run(Db& db) const + auto run(Db& db) const + -> result_t + { + static_assert(not is_noop::value, "cannot run select without having selected anything"); + static_assert(is_from_t::value, "cannot run select without a from()"); + static_assert(_parameter_list_t::size::value == 0, "cannot run select directly with parameters, use prepare instead"); + // FIXME: Check for missing aliases (if references are used) + // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. + + return {db.select(*this)}; + } + + /* + template + prepared_select_t run(Db& db) const { static_assert(not is_noop::value, "cannot run select without having selected anything"); static_assert(is_from_t::value, "cannot run select without a from()"); @@ -578,8 +593,9 @@ namespace sqlpp std::ostringstream oss; serialize(oss, db); - return {db.select(oss.str()), _expression_list._dynamic_expressions._dynamic_expression_names}; + return {db.prepare_select(oss.str()), _expression_list._dynamic_expressions._dynamic_expression_names}; } + */ Flags _flags; ExpressionList _expression_list; @@ -590,7 +606,8 @@ namespace sqlpp OrderBy _order_by; Limit _limit; Offset _offset; - decltype(named_parameter_list(std::declval>())) _parameter_list; + using _parameter_t = std::tuple; + using _parameter_list_t = typename make_parameter_list_t::type; }; // construct select flag list diff --git a/tests/PreparedTest.cpp b/tests/PreparedTest.cpp index ae6fc935..c83db03b 100644 --- a/tests/PreparedTest.cpp +++ b/tests/PreparedTest.cpp @@ -77,7 +77,9 @@ int main() // OK, fine, now create a named parameter list from an expression { - auto npl = named_parameter_list(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma)); + using Exp = decltype(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma)); + using T = sqlpp::make_parameter_list_t::type; + T npl; static_assert(std::is_same::value, "type requirement"); static_assert(std::is_same::value, "type requirement"); static_assert(std::is_same::value, "type requirement"); @@ -89,7 +91,10 @@ int main() // Wonderful, now take a look at the parameter list of a select { - auto npl = select(all_of(t)).from(t).where(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma))._parameter_list; + auto s = select(all_of(t)).from(t).where(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma)); + using S = decltype(s); + using T = sqlpp::make_parameter_list_t::type; + T npl; static_assert(std::is_same::value, "type requirement"); static_assert(std::is_same::value, "type requirement"); @@ -102,6 +107,8 @@ int main() auto x = npl; x = npl; std::cerr << x.alpha << std::endl; + x = decltype(npl)(); + std::cerr << x.alpha << std::endl; } From 2b43d3bc15edf50ffc2d18e923d8afc446efbdcd Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sun, 15 Dec 2013 18:52:05 +0100 Subject: [PATCH 06/26] Added default constructor to result field types --- include/sqlpp11/boolean.h | 6 +++--- include/sqlpp11/floating_point.h | 13 ++++++++++--- include/sqlpp11/integral.h | 13 ++++++++++--- include/sqlpp11/text.h | 14 +++++++------- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 8358da7f..7959acc2 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -103,19 +103,19 @@ namespace sqlpp return _is_null; } - bool value() const + _cpp_value_type value() const { if (not _is_valid) throw exception("accessing value in non-existing row"); return _value; } - operator bool() const { return value(); } + operator _cpp_value_type() const { return value(); } private: bool _is_valid; bool _is_null; - bool _value; + _cpp_value_type _value; }; template diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index eb030ee9..c8926c9b 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -52,6 +52,13 @@ namespace sqlpp struct _result_entry_t { using _value_type = floating_point; + + _result_entry_t(): + _is_valid(false), + _is_null(true), + _value(0) + {} + _result_entry_t(const raw_result_row_t& row): _is_valid(row.data != nullptr), _is_null(row.data == nullptr or row.data[index] == nullptr), @@ -81,19 +88,19 @@ namespace sqlpp return _is_null; } - double value() const + _cpp_value_type value() const { if (not _is_valid) throw exception("accessing value in non-existing row"); return _value; } - operator double() const { return value(); } + operator _cpp_value_type() const { return value(); } private: bool _is_valid; bool _is_null; - double _value; + _cpp_value_type _value; }; struct plus_ diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index fca44822..524dbb74 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -52,6 +52,13 @@ namespace sqlpp struct _result_entry_t { using _value_type = integral; + + _result_entry_t(): + _is_valid(false), + _is_null(true), + _value(0) + {} + _result_entry_t(const raw_result_row_t& row): _is_valid(row.data != nullptr), _is_null(row.data == nullptr or row.data[index] == nullptr), @@ -81,19 +88,19 @@ namespace sqlpp return _is_null; } - int64_t value() const + _cpp_value_type value() const { if (not _is_valid) throw exception("accessing value in non-existing row"); return _value; } - operator int64_t() const { return value(); } + operator _cpp_value_type() const { return value(); } private: bool _is_valid; bool _is_null; - int64_t _value; + _cpp_value_type _value; }; template diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index e2470242..f8da60d6 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -54,14 +54,14 @@ namespace sqlpp _result_entry_t(const raw_result_row_t& row): _is_valid(row.data != nullptr), _is_null(row.data == nullptr or row.data[index] == nullptr), - _value(_is_null ? "" : std::string(row.data[index], row.data[index] + row.len[index])) + _value(_is_null ? "" : _cpp_value_type(row.data[index], row.data[index] + row.len[index])) {} _result_entry_t& operator=(const raw_result_row_t& row) { _is_valid = (row.data != nullptr); _is_null = row.data == nullptr or row.data[index] == nullptr; - _value = _is_null ? "" : std::string(row.data[index], row.data[index] + row.len[index]); + _value = _is_null ? "" : _cpp_value_type(row.data[index], row.data[index] + row.len[index]); return *this; } @@ -73,8 +73,8 @@ namespace sqlpp bool _is_trivial() const { return value().empty(); } - bool operator==(const std::string& rhs) const { return value() == rhs; } - bool operator!=(const std::string& rhs) const { return not operator==(rhs); } + bool operator==(const _cpp_value_type& rhs) const { return value() == rhs; } + bool operator!=(const _cpp_value_type& rhs) const { return not operator==(rhs); } bool is_null() const { @@ -83,19 +83,19 @@ namespace sqlpp return _is_null; } - std::string value() const + _cpp_value_type value() const { if (not _is_valid) throw exception("accessing value in non-existing row"); return _value; } - operator std::string() const { return value(); } + operator _cpp_value_type() const { return value(); } private: bool _is_valid; bool _is_null; - std::string _value; + _cpp_value_type _value; }; template From a915bd9e502471c5f6743a5ea070b2c65d331e47 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Tue, 17 Dec 2013 22:12:13 +0100 Subject: [PATCH 07/26] Refactored of result and result row (clearer structure depending on connectors) --- include/sqlpp11/result.h | 31 +++++++++++++------------------ include/sqlpp11/result_row.h | 35 ++++++++++++++++++++++++++++++----- include/sqlpp11/select.h | 5 +++++ include/sqlpp11/text.h | 6 ++++++ tests/SelectTest.cpp | 2 -- 5 files changed, 54 insertions(+), 25 deletions(-) diff --git a/include/sqlpp11/result.h b/include/sqlpp11/result.h index 8c346f4e..f7ea4c8d 100644 --- a/include/sqlpp11/result.h +++ b/include/sqlpp11/result.h @@ -40,21 +40,19 @@ namespace sqlpp using result_row_t = typename db_result_t::result_row_t; db_result_t _db_result; - result_row_t _result_row; - result_row_t _end; + db_result_t _end; public: result_t(): _db_result(), - _result_row(), _end() {} result_t(db_result_t&& result): _db_result(std::move(result)), - _result_row(_db_result.next()), - _end({}) - {} + _end() + { + } result_t(const result_t&) = delete; result_t(result_t&&) = default; @@ -65,11 +63,9 @@ namespace sqlpp class iterator { public: - iterator(result_t& result, result_row_t& result_row): - _result(result), - _result_row(result_row) + iterator(db_result_t& result): + _result(result) { - //std::cerr << "result::iterator::constructor" << std::endl; } const result_row_t& operator*() const @@ -84,7 +80,7 @@ namespace sqlpp bool operator==(const iterator& rhs) const { - return _result_row == rhs._result_row; + return _result.front() == rhs._result.front(); } bool operator!=(const iterator& rhs) const @@ -97,33 +93,32 @@ namespace sqlpp _result.pop_front(); } - result_t& _result; - result_row_t& _result_row; + db_result_t& _result; }; iterator begin() { - return iterator(*this, _result_row); + return iterator(_db_result); } iterator end() { - return iterator(*this, _end); + return iterator(_end); } const result_row_t& front() const { - return _result_row; + return _db_result.front(); } bool empty() const { - return _result_row == _end; + return _db_result.front() == _end.front(); } void pop_front() { - _result_row = _db_result.next(); + _db_result.pop_front(); } }; diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 59f95d4b..930ce2ce 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -106,20 +106,25 @@ namespace sqlpp raw_result_row_t _raw_result_row; result_row_t(): - _raw_result_row(), - _impl(_raw_result_row), + _impl({}), + _raw_result_row({}), _is_row(false) { } template result_row_t(const raw_result_row_t& raw_result_row, const T&): + _impl(raw_result_row), _raw_result_row(raw_result_row), - _impl(_raw_result_row), _is_row(_raw_result_row.data != nullptr) { } + result_row_t(const result_row_t&) = delete; + result_row_t(result_row_t&&) = default; + result_row_t& operator=(const result_row_t&) = delete; + result_row_t& operator=(result_row_t&&) = default; + result_row_t& operator=(const raw_result_row_t& raw_result_row) { _impl::operator=(raw_result_row); @@ -128,7 +133,7 @@ namespace sqlpp return *this; } - bool operator==(const result_row_t& rhs) + bool operator==(const result_row_t& rhs) const { return _raw_result_row == rhs._raw_result_row; } @@ -146,12 +151,21 @@ namespace sqlpp using _field_type = detail::text::_result_entry_t<0>; static constexpr size_t _last_static_index = _impl::_last_index; + raw_result_row_t _raw_result_row; bool _is_row; std::vector _dynamic_columns; std::map _dynamic_fields; + dynamic_result_row_t(): + _impl({}), + _raw_result_row({}), + _is_row(false) + { + } + dynamic_result_row_t(const raw_result_row_t& raw_result_row, std::vector dynamic_columns): - detail::result_row_impl<0, 0, NamedExpr...>(raw_result_row), + _impl(raw_result_row), + _raw_result_row(raw_result_row), _is_row(raw_result_row.data != nullptr) { raw_result_row_t dynamic_row = raw_result_row; @@ -176,9 +190,15 @@ namespace sqlpp } + dynamic_result_row_t(const dynamic_result_row_t&) = delete; + dynamic_result_row_t(dynamic_result_row_t&&) = default; + dynamic_result_row_t& operator=(const dynamic_result_row_t&) = delete; + dynamic_result_row_t& operator=(dynamic_result_row_t&&) = default; + dynamic_result_row_t& operator=(const raw_result_row_t& raw_result_row) { detail::result_row_impl<0, 0, NamedExpr...>::operator=(raw_result_row); + _raw_result_row = raw_result_row; _is_row = raw_result_row.data != nullptr; raw_result_row_t dynamic_row = raw_result_row; @@ -204,6 +224,11 @@ namespace sqlpp return *this; } + bool operator==(const dynamic_result_row_t& rhs) const + { + return _raw_result_row == rhs._raw_result_row; + } + const _field_type& at(const std::string& field_name) const { return _dynamic_fields.at(field_name); diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 88dfb636..58ecca82 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -568,6 +568,11 @@ namespace sqlpp return *this; } + const typename ExpressionList::_dynamic_names_t& get_dynamic_names() const + { + return _expression_list._dynamic_expressions._dynamic_expression_names; + } + // Execute template auto run(Db& db) const diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index f8da60d6..461b7c3e 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -51,6 +51,12 @@ namespace sqlpp template struct _result_entry_t { + _result_entry_t(): + _is_valid(false), + _is_null(true), + _value("") + {} + _result_entry_t(const raw_result_row_t& row): _is_valid(row.data != nullptr), _is_null(row.data == nullptr or row.data[index] == nullptr), diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 3e579680..c413509a 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -298,8 +298,6 @@ int main() decltype(t.alpha)::_value_type::_base_value_type, decltype(f.epsilon)::_value_type::_base_value_type>::value, "Two bigint columns must have identical base_value_type"); static_assert(std::is_same::value, "select with identical columns(name/value_type) need to have identical result_types"); - static_assert(sqlpp::is_regular::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); } { From 3ef3faa0f475a8ab72cd8f4fa657f87c9d03d888 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Wed, 18 Dec 2013 08:19:50 +0100 Subject: [PATCH 08/26] Fixed bug in dynamic result row. --- include/sqlpp11/result_row.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 930ce2ce..20ead6fe 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -166,7 +166,8 @@ namespace sqlpp dynamic_result_row_t(const raw_result_row_t& raw_result_row, std::vector dynamic_columns): _impl(raw_result_row), _raw_result_row(raw_result_row), - _is_row(raw_result_row.data != nullptr) + _is_row(raw_result_row.data != nullptr), + _dynamic_columns(dynamic_columns) { raw_result_row_t dynamic_row = raw_result_row; if (_is_row) @@ -197,7 +198,7 @@ namespace sqlpp dynamic_result_row_t& operator=(const raw_result_row_t& raw_result_row) { - detail::result_row_impl<0, 0, NamedExpr...>::operator=(raw_result_row); + _impl::operator=(raw_result_row); _raw_result_row = raw_result_row; _is_row = raw_result_row.data != nullptr; From b4baf38fab77c6e296f462dcb47cf07eb545106a Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Thu, 26 Dec 2013 19:05:05 +0100 Subject: [PATCH 09/26] Parameters of prepared statements can be null now --- include/sqlpp11/boolean.h | 58 +++++++++++++++++++++++++++----- include/sqlpp11/floating_point.h | 54 +++++++++++++++++++++++++++++ include/sqlpp11/integral.h | 54 +++++++++++++++++++++++++++++ include/sqlpp11/parameter.h | 14 ++++---- include/sqlpp11/parameter_list.h | 2 +- include/sqlpp11/text.h | 54 +++++++++++++++++++++++++++++ tests/PreparedTest.cpp | 12 +++---- 7 files changed, 227 insertions(+), 21 deletions(-) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 7959acc2..937a4682 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -50,12 +50,6 @@ namespace sqlpp static constexpr const char* _name = "AND"; }; - struct not_ - { - using _value_type = boolean; - static constexpr const char* _name = "NOT"; - }; - // boolean value type struct boolean { @@ -65,10 +59,58 @@ namespace sqlpp using _is_expression = std::true_type; using _cpp_value_type = bool; - struct plus_ + template + struct _parameter_t { using _value_type = boolean; - static constexpr const char* _name = "+"; + + _parameter_t(): + _value(false), + _is_null(TrivialValueIsNull and _is_trivial()) + {} + + _parameter_t(const _cpp_value_type& value): + _value(value), + _is_null(TrivialValueIsNull and _is_trivial()) + {} + + _parameter_t& operator=(const _cpp_value_type& value) + { + _value = value; + _is_null = (TrivialValueIsNull and _is_trivial()); + return *this; + } + + _parameter_t& operator=(const std::nullptr_t&) + { + _value = false; + _is_null = true; + return *this; + } + + template + void serialize(std::ostream& os, Db& db) const + { + os << value(); + } + + bool _is_trivial() const { return value() == false; } + + bool is_null() const + { + return _is_null; + } + + _cpp_value_type value() const + { + return _value; + } + + operator _cpp_value_type() const { return value(); } + + private: + _cpp_value_type _value; + bool _is_null; }; template diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index c8926c9b..24ae32e9 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -48,6 +48,60 @@ namespace sqlpp using _is_expression = std::true_type; using _cpp_value_type = double; + template + struct _parameter_t + { + using _value_type = floating_point; + + _parameter_t(): + _value(0), + _is_null(TrivialValueIsNull and _is_trivial()) + {} + + _parameter_t(const _cpp_value_type& value): + _value(value), + _is_null(TrivialValueIsNull and _is_trivial()) + {} + + _parameter_t& operator=(const _cpp_value_type& value) + { + _value = value; + _is_null = (TrivialValueIsNull and _is_trivial()); + return *this; + } + + _parameter_t& operator=(const std::nullptr_t&) + { + _value = 0; + _is_null = true; + return *this; + } + + template + void serialize(std::ostream& os, Db& db) const + { + os << value(); + } + + bool _is_trivial() const { return value() == 0; } + + bool is_null() const + { + return _is_null; + } + + _cpp_value_type value() const + { + return _value; + } + + operator _cpp_value_type() const { return value(); } + + private: + _cpp_value_type _value; + bool _is_null; + }; + template struct _result_entry_t { diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index 524dbb74..8582a8b2 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -48,6 +48,60 @@ namespace sqlpp using _is_expression = std::true_type; using _cpp_value_type = int64_t; + template + struct _parameter_t + { + using _value_type = integral; + + _parameter_t(): + _value(0), + _is_null(TrivialValueIsNull and _is_trivial()) + {} + + _parameter_t(const _cpp_value_type& value): + _value(value), + _is_null(TrivialValueIsNull and _is_trivial()) + {} + + _parameter_t& operator=(const _cpp_value_type& value) + { + _value = value; + _is_null = (TrivialValueIsNull and _is_trivial()); + return *this; + } + + _parameter_t& operator=(const std::nullptr_t&) + { + _value = 0; + _is_null = true; + return *this; + } + + template + void serialize(std::ostream& os, Db& db) const + { + os << value(); + } + + bool _is_trivial() const { return value() == 0; } + + bool is_null() const + { + return _is_null; + } + + _cpp_value_type value() const + { + return _value; + } + + operator _cpp_value_type() const { return value(); } + + private: + _cpp_value_type _value; + bool _is_null; + }; + template struct _result_entry_t { diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index 3de5e6d9..054d5687 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -33,29 +33,31 @@ namespace sqlpp { - template + template struct parameter_t { - using _is_parameter = std::true_type; using _value_type = ValueType; + using _parameter_type = typename ValueType::template _parameter_t; + using _is_parameter = std::true_type; using _is_expression_t = std::true_type; template void serialize(std::ostream& os, Db& db) const { static_assert(Db::_supports_parameter, "parameter not supported by current database"); - os << " ? "; + os << " ? "; // FIXME: Need to support positional placeholders and also type indicators for postgres for instance } - using _member_t = typename NameType::_name_t::template _member_t; + using _member_t = typename NameType::_name_t::template _member_t<_parameter_type>; }; - template + template::type>::value> auto parameter(NamedExpr&& namedExpr) - -> parameter_t::type::_value_type, typename std::decay::type> + -> parameter_t::type::_value_type, typename std::decay::type, TrivialValueIsNull> { return {}; } + } #endif diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index 664a4274..4f21a557 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -74,7 +74,7 @@ namespace sqlpp ~parameter_list_t() = default; - using parameter_tuple_t = std::tuple; + using parameter_tuple_t = std::tuple; using size = std::tuple_size; parameter_tuple_t _parameter_tuple; }; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 461b7c3e..59e3b803 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -48,6 +48,60 @@ namespace sqlpp using _is_expression = std::true_type; using _cpp_value_type = std::string; + template + struct _parameter_t + { + using _value_type = integral; + + _parameter_t(): + _value(""), + _is_null(TrivialValueIsNull and _is_trivial()) + {} + + _parameter_t(const _cpp_value_type& value): + _value(value), + _is_null(TrivialValueIsNull and _is_trivial()) + {} + + _parameter_t& operator=(const _cpp_value_type& value) + { + _value = value; + _is_null = (TrivialValueIsNull and _is_trivial()); + return *this; + } + + _parameter_t& operator=(const std::nullptr_t&) + { + _value = ""; + _is_null = true; + return *this; + } + + template + void serialize(std::ostream& os, Db& db) const + { + os << value(); + } + + bool _is_trivial() const { return value() == ""; } + + bool is_null() const + { + return _is_null; + } + + _cpp_value_type value() const + { + return _value; + } + + operator _cpp_value_type() const { return value(); } + + private: + _cpp_value_type _value; + bool _is_null; + }; + template struct _result_entry_t { diff --git a/tests/PreparedTest.cpp b/tests/PreparedTest.cpp index c83db03b..01936c1a 100644 --- a/tests/PreparedTest.cpp +++ b/tests/PreparedTest.cpp @@ -80,9 +80,9 @@ int main() using Exp = decltype(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma)); using T = sqlpp::make_parameter_list_t::type; T npl; - static_assert(std::is_same::value, "type requirement"); - static_assert(std::is_same::value, "type requirement"); - static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same, decltype(npl.alpha)>::value, "type requirement"); + static_assert(std::is_same, decltype(npl.beta)>::value, "type requirement"); + static_assert(std::is_same, decltype(npl.gamma)>::value, "type requirement"); static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.beta)&>::value, "type requirement"); static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.alpha)&>::value, "type requirement"); @@ -96,9 +96,9 @@ int main() using T = sqlpp::make_parameter_list_t::type; T npl; - static_assert(std::is_same::value, "type requirement"); - static_assert(std::is_same::value, "type requirement"); - static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same, decltype(npl.alpha)>::value, "type requirement"); + static_assert(std::is_same, decltype(npl.beta)>::value, "type requirement"); + static_assert(std::is_same, decltype(npl.gamma)>::value, "type requirement"); static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.beta)&>::value, "type requirement"); static_assert(std::is_same(npl._parameter_tuple)), decltype(npl.alpha)&>::value, "type requirement"); From b031bda5fcc386930f2cd38855677834f0078714 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sat, 28 Dec 2013 22:52:54 +0100 Subject: [PATCH 10/26] Can now prepare a select (tested with mysql) --- include/sqlpp11/alias.h | 8 ++----- include/sqlpp11/expression.h | 29 ++++++++++++++++++++++++ include/sqlpp11/from.h | 2 +- include/sqlpp11/having.h | 5 +++++ include/sqlpp11/like.h | 2 +- include/sqlpp11/parameter.h | 16 ++++++++++--- include/sqlpp11/parameter_list.h | 37 +------------------------------ include/sqlpp11/prepared_select.h | 2 +- include/sqlpp11/select.h | 8 ++----- include/sqlpp11/where.h | 5 +++++ tests/PreparedTest.cpp | 8 ------- tests/TabSample.h | 4 ++++ 12 files changed, 64 insertions(+), 62 deletions(-) diff --git a/include/sqlpp11/alias.h b/include/sqlpp11/alias.h index 32b1f165..0d281e56 100644 --- a/include/sqlpp11/alias.h +++ b/include/sqlpp11/alias.h @@ -41,13 +41,9 @@ namespace sqlpp template\ struct _member_t\ {\ - template\ - _member_t(TT&&... t): name(std::forward(t)...) {}\ - \ - template\ - _member_t& operator=(TT&& t) { name = std::forward(t); return *this; }\ - \ T name;\ + T& operator()() { return name; }\ + const T& operator()() const { return name; }\ };\ };\ };\ diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index 607bca33..b79a89de 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -42,6 +42,12 @@ namespace sqlpp using value_type = Rhs; using _parameter_t = std::tuple; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_lhs, index); + return set_parameter_index(_rhs, index); + } + template void serialize(std::ostream& os, Db& db) const { @@ -67,6 +73,12 @@ namespace sqlpp using _value_type = ValueType; using _parameter_t = std::tuple; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_lhs, index); + return set_parameter_index(_rhs, index); + } + template equal_t(L&& l, R&& r): _lhs(std::forward(l)), @@ -107,6 +119,12 @@ namespace sqlpp using _value_type = ValueType; using _parameter_t = std::tuple; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_lhs, index); + return set_parameter_index(_rhs, index); + } + template not_equal_t(L&& l, R&& r): _lhs(std::forward(l)), @@ -147,6 +165,11 @@ namespace sqlpp using _value_type = ValueType; using _parameter_t = std::tuple; + size_t _set_parameter_index(size_t index) + { + return set_parameter_index(_lhs, index); + } + not_t(Lhs l): _lhs(l) {} @@ -184,6 +207,12 @@ namespace sqlpp using _value_type = typename O::_value_type; using _parameter_t = std::tuple; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_lhs, index); + return set_parameter_index(_rhs, index); + } + binary_expression_t(Lhs&& l, Rhs&& r): _lhs(std::move(l)), _rhs(std::move(r)) diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index 7e10c0b8..7e82de70 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -51,7 +51,7 @@ namespace sqlpp using _valid_expressions = typename detail::make_set_if::type; static_assert(_valid_expressions::size::value == sizeof...(TableOrJoin), "at least one argument is not a table or join in from()"); - // FIXME: Joins contain two tables. This is not being dealt with at the moment + // FIXME: Joins contain two tables. This is not being dealt with at the moment when looking at duplicates, for instance template diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index ec31d62e..d0c67e6f 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -65,6 +65,11 @@ namespace sqlpp _dynamic_expressions.serialize(os, db, " AND ", sizeof...(Expr) == 0); } + size_t _set_parameter_index(size_t index) + { + return set_parameter_index(_expressions, index); + } + using _parameter_t = std::tuple; _parameter_t _expressions; detail::serializable_list _dynamic_expressions; diff --git a/include/sqlpp11/like.h b/include/sqlpp11/like.h index d0d037b1..8e9b5bab 100644 --- a/include/sqlpp11/like.h +++ b/include/sqlpp11/like.h @@ -43,7 +43,7 @@ namespace sqlpp static_assert(is_text_t::value, "Pattern for like() has to be a text"); using _parameter_t = std::tuple; - struct _value_type: public ValueType::_base_value_type // we requite fully defined boolean here + struct _value_type: public ValueType::_base_value_type // we require fully defined boolean here { using _is_named_expression = std::true_type; }; diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index 054d5687..9959082d 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -40,15 +40,25 @@ namespace sqlpp using _parameter_type = typename ValueType::template _parameter_t; using _is_parameter = std::true_type; using _is_expression_t = std::true_type; + using _member_t = typename NameType::_name_t::template _member_t<_parameter_type>; template void serialize(std::ostream& os, Db& db) const { - static_assert(Db::_supports_parameter, "parameter not supported by current database"); - os << " ? "; // FIXME: Need to support positional placeholders and also type indicators for postgres for instance + static_assert(Db::_supports_prepared, "prepared statements not supported by current database"); + static_assert(Db::_use_questionmark_parameter or Db::_use_positional_dollar_parameter, "no known way to serialize parameter placeholders for current database"); + if (Db::_use_questionmark_parameter) + os << '?'; + else if (Db::_use_positional_dollar_parameter) + os << '$' << index + 1; } - using _member_t = typename NameType::_name_t::template _member_t<_parameter_type>; + constexpr bool _is_trivial() const + { + return false; + } + + size_t index; }; template::type>::value> diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index 4f21a557..d24bdeed 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -41,42 +41,7 @@ namespace sqlpp template struct parameter_list_t>: public Parameter::_member_t... { - parameter_list_t(): - Parameter::_member_t()..., - _parameter_tuple(static_cast(*this)()...) - {} - - parameter_list_t(const parameter_list_t& rhs) - noexcept(std::is_nothrow_copy_constructible>::value): - Parameter::_member_t(static_cast(rhs))..., - _parameter_tuple(static_cast(*this)()...) - {} - - parameter_list_t(parameter_list_t&& rhs) - noexcept(std::is_nothrow_move_constructible>::value): - Parameter::_member_t(std::move(static_cast(rhs)))..., - _parameter_tuple(static_cast(*this)()...) - {} - - parameter_list_t& operator=(const parameter_list_t& rhs) - noexcept(std::is_nothrow_copy_assignable>::value) - { - _parameter_tuple = rhs._parameter_tuple; - return *this; - } - - parameter_list_t& operator=(parameter_list_t&& rhs) - noexcept(std::is_nothrow_move_assignable>::value) - { - _parameter_tuple = std::move(rhs._parameter_tuple); - return *this; - } - - ~parameter_list_t() = default; - - using parameter_tuple_t = std::tuple; - using size = std::tuple_size; - parameter_tuple_t _parameter_tuple; + using size = std::integral_constant; }; namespace detail diff --git a/include/sqlpp11/prepared_select.h b/include/sqlpp11/prepared_select.h index 867c16fd..40cb2314 100644 --- a/include/sqlpp11/prepared_select.h +++ b/include/sqlpp11/prepared_select.h @@ -38,7 +38,7 @@ namespace sqlpp using _result_row_t = typename Select::_result_row_t; using _parameter_list_t = typename Select::_parameter_list_t; using _dynamic_names_t = typename Select::_dynamic_names_t; - using _handle_t = typename Db::_prepared_handle_t; + using _handle_t = typename Db::template _prepared_query_t; + using _prepared_query_t = typename Db::_prepared_query_t; auto run(Db& db) const - -> result_t + -> result_t { - return {db.run_prepared_select(_handle, params), _dynamic_names}; + return {db.run_prepared_select(*this)}; + } + + void bind_params() const + { + params._bind(_prepared_query); } _parameter_list_t params; _dynamic_names_t _dynamic_names; - _handle_t _handle; + mutable _prepared_query_t _prepared_query; }; } diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 20ead6fe..8ffda248 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -142,6 +142,11 @@ namespace sqlpp { return _is_row; } + + static constexpr size_t static_size() + { + return sizeof...(NamedExpr); + } }; template diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index d94b56a6..3d38183a 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -573,6 +573,16 @@ namespace sqlpp return _expression_list._dynamic_expressions._dynamic_expression_names; } + static constexpr size_t get_no_of_parameters() + { + return _parameter_list_t::size::value; + } + + size_t get_no_of_result_columns() const + { + return _result_row_t::static_size(); // FIXME: Need to add the size of dynamic columns + } + // Execute template auto run(Db& db) const @@ -580,7 +590,7 @@ namespace sqlpp { static_assert(not is_noop::value, "cannot run select without having selected anything"); static_assert(is_from_t::value, "cannot run select without a from()"); - static_assert(_parameter_list_t::size::value == 0, "cannot run select directly with parameters, use prepare instead"); + static_assert(get_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead"); // FIXME: Check for missing aliases (if references are used) // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. From 1360b1d9dbbf502076c87f031888f5bafcedd10d Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Thu, 2 Jan 2014 13:11:19 +0100 Subject: [PATCH 12/26] Turned value_type::parameter_t into a non-template --- include/sqlpp11/boolean.h | 17 ++++++++++---- include/sqlpp11/expression.h | 10 ++++---- include/sqlpp11/having.h | 4 ++-- include/sqlpp11/integral.h | 39 ++++++++++++++++++++++++++------ include/sqlpp11/like.h | 2 +- include/sqlpp11/parameter.h | 10 ++++---- include/sqlpp11/parameter_list.h | 15 ++++++++---- include/sqlpp11/result_row.h | 35 +++++++++++++++++++++++++--- include/sqlpp11/select.h | 2 +- include/sqlpp11/text.h | 17 ++++++++++---- include/sqlpp11/type_traits.h | 6 ++--- include/sqlpp11/where.h | 4 ++-- tests/PreparedTest.cpp | 12 +++++----- 13 files changed, 124 insertions(+), 49 deletions(-) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 937a4682..c4d6eb05 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -59,25 +59,31 @@ namespace sqlpp using _is_expression = std::true_type; using _cpp_value_type = bool; - template struct _parameter_t { using _value_type = boolean; - _parameter_t(): + _parameter_t(const std::true_type&): + _trivial_value_is_null(true), _value(false), - _is_null(TrivialValueIsNull and _is_trivial()) + _is_null(_trivial_value_is_null and _is_trivial()) + {} + + _parameter_t(const std::false_type&): + _trivial_value_is_null(false), + _value(false), + _is_null(_trivial_value_is_null and _is_trivial()) {} _parameter_t(const _cpp_value_type& value): _value(value), - _is_null(TrivialValueIsNull and _is_trivial()) + _is_null(_trivial_value_is_null and _is_trivial()) {} _parameter_t& operator=(const _cpp_value_type& value) { _value = value; - _is_null = (TrivialValueIsNull and _is_trivial()); + _is_null = (_trivial_value_is_null and _is_trivial()); return *this; } @@ -109,6 +115,7 @@ namespace sqlpp operator _cpp_value_type() const { return value(); } private: + bool _trivial_value_is_null; _cpp_value_type _value; bool _is_null; }; diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index b79a89de..1b655e4a 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -40,7 +40,7 @@ namespace sqlpp using _is_assignment = std::true_type; using column_type = Lhs; using value_type = Rhs; - using _parameter_t = std::tuple; + using _parameter_tuple_t = std::tuple; size_t _set_parameter_index(size_t index) { @@ -71,7 +71,7 @@ namespace sqlpp struct equal_t: public ValueType::template operators> { using _value_type = ValueType; - using _parameter_t = std::tuple; + using _parameter_tuple_t = std::tuple; size_t _set_parameter_index(size_t index) { @@ -117,7 +117,7 @@ namespace sqlpp struct not_equal_t: public ValueType::template operators> { using _value_type = ValueType; - using _parameter_t = std::tuple; + using _parameter_tuple_t = std::tuple; size_t _set_parameter_index(size_t index) { @@ -163,7 +163,7 @@ namespace sqlpp struct not_t: public ValueType::template operators> { using _value_type = ValueType; - using _parameter_t = std::tuple; + using _parameter_tuple_t = std::tuple; size_t _set_parameter_index(size_t index) { @@ -205,7 +205,7 @@ namespace sqlpp struct binary_expression_t: public O::_value_type::template operators> { using _value_type = typename O::_value_type; - using _parameter_t = std::tuple; + using _parameter_tuple_t = std::tuple; size_t _set_parameter_index(size_t index) { diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index d0c67e6f..eed521d5 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -70,8 +70,8 @@ namespace sqlpp return set_parameter_index(_expressions, index); } - using _parameter_t = std::tuple; - _parameter_t _expressions; + using _parameter_tuple_t = std::tuple; + _parameter_tuple_t _expressions; // FIXME: Do we need those? detail::serializable_list _dynamic_expressions; }; diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index fc9211d1..7c28fcad 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -48,25 +48,37 @@ namespace sqlpp using _is_expression = std::true_type; using _cpp_value_type = int64_t; - template struct _parameter_t { using _value_type = integral; - _parameter_t(): + _parameter_t(const std::true_type&): + _trivial_value_is_null(true), _value(0), - _is_null(TrivialValueIsNull and _is_trivial()) + _is_null(_trivial_value_is_null and _is_trivial()) + {} + + _parameter_t(const std::false_type&): + _trivial_value_is_null(false), + _value(0), + _is_null(_trivial_value_is_null and _is_trivial()) + {} + + _parameter_t(bool trivial_value_is_null): + _trivial_value_is_null(trivial_value_is_null), + _value(0), + _is_null(_trivial_value_is_null and _is_trivial()) {} _parameter_t(const _cpp_value_type& value): _value(value), - _is_null(TrivialValueIsNull and _is_trivial()) + _is_null(_trivial_value_is_null and _is_trivial()) {} _parameter_t& operator=(const _cpp_value_type& value) { _value = value; - _is_null = (TrivialValueIsNull and _is_trivial()); + _is_null = (_trivial_value_is_null and _is_trivial()); return *this; } @@ -90,14 +102,21 @@ namespace sqlpp return _is_null; } - const _cpp_value_type* value() const + const _cpp_value_type& value() const { - return &_value; + return _value; } operator _cpp_value_type() const { return _value; } + template + void bind(Target& target, size_t index) const + { + target.bind_integral_parameter(index, &_value, _is_null); + } + private: + bool _trivial_value_is_null; _cpp_value_type _value; bool _is_null; }; @@ -151,6 +170,12 @@ namespace sqlpp operator _cpp_value_type() const { return value(); } + template + void bind(Target& target, size_t i) const // Hint: Cannot use index here because of dynamic result rows which can use index==0 for several fields + { + target.bind_integral_result(i, &_value, _is_null); + } + private: bool _is_valid; bool _is_null; diff --git a/include/sqlpp11/like.h b/include/sqlpp11/like.h index 8e9b5bab..4ee099d0 100644 --- a/include/sqlpp11/like.h +++ b/include/sqlpp11/like.h @@ -41,7 +41,7 @@ namespace sqlpp { static_assert(is_text_t::value, "Operand for like() has to be a text"); static_assert(is_text_t::value, "Pattern for like() has to be a text"); - using _parameter_t = std::tuple; + using _parameter_tuple_t = std::tuple; struct _value_type: public ValueType::_base_value_type // we require fully defined boolean here { diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index 9959082d..2563f32c 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -33,14 +33,16 @@ namespace sqlpp { - template + template struct parameter_t { using _value_type = ValueType; - using _parameter_type = typename ValueType::template _parameter_t; using _is_parameter = std::true_type; using _is_expression_t = std::true_type; - using _member_t = typename NameType::_name_t::template _member_t<_parameter_type>; + using _instance_t = typename NameType::_name_t::template _member_t; + using _trivial_value_is_null = TrivialValueIsNull; + + static_assert(std::is_same<_trivial_value_is_null, std::true_type>::value or std::is_same<_trivial_value_is_null, std::false_type>::value, "Invalid template parameter TrivialValueIsNull"); template void serialize(std::ostream& os, Db& db) const @@ -61,7 +63,7 @@ namespace sqlpp size_t index; }; - template::type>::value> + template::type>> auto parameter(NamedExpr&& namedExpr) -> parameter_t::type::_value_type, typename std::decay::type, TrivialValueIsNull> { diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index 498599e7..406d752d 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -39,11 +39,15 @@ namespace sqlpp }; template - struct parameter_list_t>: public Parameter::_member_t... + struct parameter_list_t>: public Parameter::_instance_t... { - using _member_tuple_t = std::tuple; + using _member_tuple_t = std::tuple; using size = std::integral_constant; + parameter_list_t(): + Parameter::_instance_t({typename Parameter::_trivial_value_is_null()})... + {} + template void _bind(Target& target) const { @@ -56,7 +60,8 @@ namespace sqlpp template void _bind_impl(Target& target, const index_t&) const { - target.bind_param(index, static_cast::type&>(*this)()); + const auto& parameter = static_cast::type&>(*this)(); + parameter.bind(target, index); _bind_impl(target, index_t()); } @@ -88,9 +93,9 @@ namespace sqlpp }; template - struct get_parameter_tuple::value, void>::type> + struct get_parameter_tuple::value, void>::type> { - using type = typename get_parameter_tuple::type; + using type = typename get_parameter_tuple::type; }; } diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 8ffda248..da67140a 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -37,6 +37,8 @@ namespace sqlpp { namespace detail { + template struct index_t {}; // this is just for overloading + template struct result_row_impl; @@ -60,14 +62,22 @@ namespace sqlpp _rest::operator=(raw_result_row); return *this; } + + template + void _bind(Target& target) + { + _field::operator().bind(target, index); + std::cerr << "binding result " << index << std::endl; + _rest::_bind(target); + } }; template struct result_row_impl>, Rest...>: - public AliasProvider::_name_t::template _member_t>, // level prevents identical closures to be present twice in the inheritance tree + public AliasProvider::_name_t::template _member_t>, // level prevents identical closures to be present twice in the inheritance tree public result_row_impl { - using _multi_field = typename AliasProvider::_name_t::template _member_t>; + using _multi_field = typename AliasProvider::_name_t::template _member_t>; using _rest = result_row_impl; static constexpr size_t _last_index = _rest::_last_index; @@ -82,6 +92,13 @@ namespace sqlpp _rest::operator=(raw_result_row); return *this; } + + template + void _bind(const Target& target) + { + _multi_field::_bind(target); + _rest::_bind(target); + } }; template @@ -95,6 +112,11 @@ namespace sqlpp { return *this; } + + template + void _bind(Target& target) + { + } }; } @@ -104,6 +126,7 @@ namespace sqlpp using _impl = detail::result_row_impl<0, 0, NamedExpr...>; bool _is_row; raw_result_row_t _raw_result_row; + static constexpr size_t _last_static_index = _impl::_last_index; result_row_t(): _impl({}), @@ -145,8 +168,14 @@ namespace sqlpp static constexpr size_t static_size() { - return sizeof...(NamedExpr); + return _last_static_index; } + + template + void bind_result(Target& target) + { + _impl::_bind(target); + } }; template diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 3d38183a..9fa3592f 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -617,7 +617,7 @@ namespace sqlpp OrderBy _order_by; Limit _limit; Offset _offset; - using _parameter_t = std::tuple; + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; }; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 59e3b803..83e3e6a4 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -48,25 +48,31 @@ namespace sqlpp using _is_expression = std::true_type; using _cpp_value_type = std::string; - template struct _parameter_t { using _value_type = integral; - _parameter_t(): + _parameter_t(const std::true_type&): + _trivial_value_is_null(true), _value(""), - _is_null(TrivialValueIsNull and _is_trivial()) + _is_null(_trivial_value_is_null and _is_trivial()) + {} + + _parameter_t(const std::false_type&): + _trivial_value_is_null(false), + _value(""), + _is_null(_trivial_value_is_null and _is_trivial()) {} _parameter_t(const _cpp_value_type& value): _value(value), - _is_null(TrivialValueIsNull and _is_trivial()) + _is_null(_trivial_value_is_null and _is_trivial()) {} _parameter_t& operator=(const _cpp_value_type& value) { _value = value; - _is_null = (TrivialValueIsNull and _is_trivial()); + _is_null = (_trivial_value_is_null and _is_trivial()); return *this; } @@ -98,6 +104,7 @@ namespace sqlpp operator _cpp_value_type() const { return value(); } private: + bool _trivial_value_is_null; _cpp_value_type _value; bool _is_null; }; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index d4afca01..ac3967d6 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -47,12 +47,12 @@ namespace sqlpp namespace detail\ {\ template\ - struct name##_impl: std::false_type {};\ + struct name##_impl { using type = std::false_type; };\ template\ - struct name##_impl::value>::type>: std::true_type {};\ + struct name##_impl::value>::type> { using type = std::true_type; };\ }\ template\ - struct name##_t: detail::name##_impl {}; + using name##_t = typename detail::name##_impl::type; #define SQLPP_TYPE_TRAIT_GENERATOR(name) \ namespace detail\ diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index a7204273..d9996d3f 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -69,8 +69,8 @@ namespace sqlpp return set_parameter_index(_expressions, index); } - using _parameter_t = std::tuple; - _parameter_t _expressions; + using _parameter_tuple_t = std::tuple; + _parameter_tuple_t _expressions; // FIXME: Do we need those? detail::serializable_list _dynamic_expressions; }; } diff --git a/tests/PreparedTest.cpp b/tests/PreparedTest.cpp index 6fac99e2..f3c36cc1 100644 --- a/tests/PreparedTest.cpp +++ b/tests/PreparedTest.cpp @@ -80,9 +80,9 @@ int main() using Exp = decltype(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma)); using T = sqlpp::make_parameter_list_t::type; T npl; - static_assert(std::is_same, decltype(npl.alpha)>::value, "type requirement"); - static_assert(std::is_same, decltype(npl.beta)>::value, "type requirement"); - static_assert(std::is_same, decltype(npl.gamma)>::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); } // Wonderful, now take a look at the parameter list of a select @@ -92,9 +92,9 @@ int main() using T = sqlpp::make_parameter_list_t::type; T npl; - static_assert(std::is_same, decltype(npl.alpha)>::value, "type requirement"); - static_assert(std::is_same, decltype(npl.beta)>::value, "type requirement"); - static_assert(std::is_same, decltype(npl.gamma)>::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); npl.alpha = 7; auto x = npl; x = npl; From 9ca174054d27c222d19ac94ce6c1c07b6211eb7a Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Thu, 2 Jan 2014 19:05:27 +0100 Subject: [PATCH 13/26] Can bind results. --- include/sqlpp11/boolean.h | 40 ++++++--- include/sqlpp11/integral.h | 32 +++---- include/sqlpp11/raw_result_row.h | 4 +- include/sqlpp11/result_row.h | 138 ++++++++++++++++--------------- include/sqlpp11/text.h | 51 +++++++----- 5 files changed, 153 insertions(+), 112 deletions(-) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index c4d6eb05..798d2175 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -120,21 +120,32 @@ namespace sqlpp bool _is_null; }; - template struct _result_entry_t { - _result_entry_t(const raw_result_row_t& row): - _is_valid(row.data != nullptr), - _is_null(row.data == nullptr or row.data[index] == nullptr), - _value(_is_null ? false : (std::strtoll(row.data[index], nullptr, 10) != 0)) + _result_entry_t(): + _is_valid(false), + _is_null(true), + _value(false) {} - _result_entry_t& operator=(const raw_result_row_t& row) + _result_entry_t(const char* data, size_t): + _is_valid(true), + _is_null(data == nullptr), + _value(_is_null ? false : (data[0] == 't' or data[0] == '1')) + {} + + void assign(const char* data, size_t) { - _is_valid = (row.data != nullptr); - _is_null = row.data == nullptr or row.data[index] == nullptr; - _value = _is_null ? false : (std::strtoll(row.data[index], nullptr, 10) != 0); - return *this; + _is_valid = true; + _is_null = data == nullptr; + _value = _is_null ? false : (data[0] == 't' or data[0] == '1'); + } + + void invalidate() + { + _is_valid = false; + _is_null = true; + _value = 0; } template @@ -161,6 +172,12 @@ namespace sqlpp operator _cpp_value_type() const { return value(); } + template + void bind(Target& target, size_t i) + { + target.bind_boolean_result(i, &_value, &_is_null); + } + private: bool _is_valid; bool _is_null; @@ -195,8 +212,7 @@ namespace sqlpp }; }; - template - std::ostream& operator<<(std::ostream& os, const boolean::_result_entry_t& e) + inline std::ostream& operator<<(std::ostream& os, const boolean::_result_entry_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index 7c28fcad..a52d44c2 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -121,7 +121,6 @@ namespace sqlpp bool _is_null; }; - template struct _result_entry_t { using _value_type = integral; @@ -132,18 +131,24 @@ namespace sqlpp _value(0) {} - _result_entry_t(const raw_result_row_t& row): - _is_valid(row.data != nullptr), - _is_null(row.data == nullptr or row.data[index] == nullptr), - _value(_is_null ? 0 : std::strtoll(row.data[index], nullptr, 10)) + _result_entry_t(const char* data, size_t): + _is_valid(true), + _is_null(data == nullptr), + _value(_is_null ? 0 : std::strtoll(data, nullptr, 10)) {} - _result_entry_t& operator=(const raw_result_row_t& row) + void assign(const char* data, size_t) { - _is_valid = (row.data != nullptr); - _is_null = row.data == nullptr or row.data[index] == nullptr; - _value = _is_null ? 0 : std::strtoll(row.data[index], nullptr, 10); - return *this; + _is_valid = true; + _is_null = data == nullptr; + _value = _is_null ? 0 : std::strtoll(data, nullptr, 10); + } + + void invalidate() + { + _is_valid = false; + _is_null = true; + _value = 0; } template @@ -171,9 +176,9 @@ namespace sqlpp operator _cpp_value_type() const { return value(); } template - void bind(Target& target, size_t i) const // Hint: Cannot use index here because of dynamic result rows which can use index==0 for several fields + void bind(Target& target, size_t i) { - target.bind_integral_result(i, &_value, _is_null); + target.bind_integral_result(i, &_value, &_is_null); } private: @@ -271,8 +276,7 @@ namespace sqlpp }; }; - template - std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t& e) + inline std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/raw_result_row.h b/include/sqlpp11/raw_result_row.h index 0baaf9ff..32f15626 100644 --- a/include/sqlpp11/raw_result_row.h +++ b/include/sqlpp11/raw_result_row.h @@ -31,8 +31,8 @@ namespace sqlpp { struct raw_result_row_t { - const char** data; - const size_t* len; + char** data; + size_t* len; bool operator==(const raw_result_row_t& rhs) const { diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index da67140a..9ed148b9 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -44,29 +44,37 @@ namespace sqlpp template struct result_row_impl: - public NamedExpr::_name_t::template _member_t>, + public NamedExpr::_name_t::template _member_t, public result_row_impl { - using _field = typename NamedExpr::_name_t::template _member_t>; + using _field = typename NamedExpr::_name_t::template _member_t; using _rest = result_row_impl; static constexpr size_t _last_index = _rest::_last_index; + result_row_impl() = default; result_row_impl(const raw_result_row_t& raw_result_row): - _field({raw_result_row}), + _field({{raw_result_row.data[index], raw_result_row.len[index]}}), _rest(raw_result_row) - {} + { + } result_row_impl& operator=(const raw_result_row_t& raw_result_row) { - _field::operator=({raw_result_row}); + _field::operator()().assign(raw_result_row.data[index], raw_result_row.len[index]); _rest::operator=(raw_result_row); return *this; } + void invalidate() + { + _field::operator()().invalidate(); + _rest::invalidate(); + } + template void _bind(Target& target) { - _field::operator().bind(target, index); + _field::operator()().bind(target, index); std::cerr << "binding result " << index << std::endl; _rest::_bind(target); } @@ -81,6 +89,7 @@ namespace sqlpp using _rest = result_row_impl; static constexpr size_t _last_index = _rest::_last_index; + result_row_impl() = default; result_row_impl(const raw_result_row_t& raw_result_row): _multi_field({raw_result_row}), _rest(raw_result_row) @@ -93,6 +102,12 @@ namespace sqlpp return *this; } + void invalidate() + { + _multi_field::invalidate(); + _rest::invalidate(); + } + template void _bind(const Target& target) { @@ -105,14 +120,20 @@ namespace sqlpp struct result_row_impl { static constexpr size_t _last_index = index; + result_row_impl() = default; result_row_impl(const raw_result_row_t& raw_result_row) - {} + { + } result_row_impl& operator=(const raw_result_row_t& raw_result_row) { return *this; } + void invalidate() + { + } + template void _bind(Target& target) { @@ -124,22 +145,19 @@ namespace sqlpp struct result_row_t: public detail::result_row_impl<0, 0, NamedExpr...> { using _impl = detail::result_row_impl<0, 0, NamedExpr...>; - bool _is_row; - raw_result_row_t _raw_result_row; + bool _is_valid; static constexpr size_t _last_static_index = _impl::_last_index; result_row_t(): - _impl({}), - _raw_result_row({}), - _is_row(false) + _impl(), + _is_valid(false) { } template result_row_t(const raw_result_row_t& raw_result_row, const T&): _impl(raw_result_row), - _raw_result_row(raw_result_row), - _is_row(_raw_result_row.data != nullptr) + _is_valid(true) { } @@ -151,19 +169,24 @@ namespace sqlpp result_row_t& operator=(const raw_result_row_t& raw_result_row) { _impl::operator=(raw_result_row); - _raw_result_row = raw_result_row; - _is_row = _raw_result_row.data != nullptr; + _is_valid = true; return *this; } + void invalidate() + { + _impl::invalidate(); + _is_valid = false; + } + bool operator==(const result_row_t& rhs) const { - return _raw_result_row == rhs._raw_result_row; + return _is_valid == rhs._is_valid; } explicit operator bool() const { - return _is_row; + return _is_valid; } static constexpr size_t static_size() @@ -182,47 +205,33 @@ namespace sqlpp struct dynamic_result_row_t: public detail::result_row_impl<0, 0, NamedExpr...> { using _impl = detail::result_row_impl<0, 0, NamedExpr...>; - using _field_type = detail::text::_result_entry_t<0>; + using _field_type = detail::text::_result_entry_t; static constexpr size_t _last_static_index = _impl::_last_index; - raw_result_row_t _raw_result_row; - bool _is_row; + bool _is_valid; std::vector _dynamic_columns; std::map _dynamic_fields; dynamic_result_row_t(): - _impl({}), - _raw_result_row({}), - _is_row(false) + _impl(), + _is_valid(false) { } dynamic_result_row_t(const raw_result_row_t& raw_result_row, std::vector dynamic_columns): _impl(raw_result_row), - _raw_result_row(raw_result_row), - _is_row(raw_result_row.data != nullptr), + _is_valid(true), _dynamic_columns(dynamic_columns) { raw_result_row_t dynamic_row = raw_result_row; - if (_is_row) + dynamic_row.data += _last_static_index; + dynamic_row.len += _last_static_index; + for (const auto& column : _dynamic_columns) { - dynamic_row.data += _last_static_index; - dynamic_row.len += _last_static_index; - for (const auto& column : _dynamic_columns) - { - _dynamic_fields.insert(std::make_pair(column, _field_type(dynamic_row))); - ++dynamic_row.data; - ++dynamic_row.len; - } + _dynamic_fields.insert(std::make_pair(column, _field_type(dynamic_row.data[0], dynamic_row.len[0]))); + ++dynamic_row.data; + ++dynamic_row.len; } - else - { - for (const auto& column : _dynamic_columns) - { - _dynamic_fields.insert(std::make_pair(column, _field_type(dynamic_row))); - } - } - } dynamic_result_row_t(const dynamic_result_row_t&) = delete; @@ -233,35 +242,34 @@ namespace sqlpp dynamic_result_row_t& operator=(const raw_result_row_t& raw_result_row) { _impl::operator=(raw_result_row); - _raw_result_row = raw_result_row; - _is_row = raw_result_row.data != nullptr; + _is_valid = true; raw_result_row_t dynamic_row = raw_result_row; - if (_is_row) - { - dynamic_row.data += _last_static_index; - dynamic_row.len += _last_static_index; - for (const auto& column : _dynamic_columns) - { - _dynamic_fields.at(column) = dynamic_row; - ++dynamic_row.data; - ++dynamic_row.len; - } - } - else - { - for (const auto& column : _dynamic_columns) - { - _dynamic_fields.at(column) = dynamic_row; - } - } + dynamic_row.data += _last_static_index; + dynamic_row.len += _last_static_index; + for (const auto& column : _dynamic_columns) + { + _dynamic_fields.at(column).assign(dynamic_row.data[0], dynamic_row.len[0]); + ++dynamic_row.data; + ++dynamic_row.len; + } return *this; } + void invalidate() + { + _impl::invalidate(); + _is_valid = false; + for (const auto& column : _dynamic_columns) + { + _dynamic_fields.at(column).invalidate(); + } + } + bool operator==(const dynamic_result_row_t& rhs) const { - return _raw_result_row == rhs._raw_result_row; + return _is_valid == rhs._is_valid; } const _field_type& at(const std::string& field_name) const @@ -271,7 +279,7 @@ namespace sqlpp explicit operator bool() const { - return _is_row; + return _is_valid; } }; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 83e3e6a4..8eee1774 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -109,27 +109,32 @@ namespace sqlpp bool _is_null; }; - template struct _result_entry_t { _result_entry_t(): _is_valid(false), - _is_null(true), - _value("") + _value_ptr(nullptr), + _len(0) {} - _result_entry_t(const raw_result_row_t& row): - _is_valid(row.data != nullptr), - _is_null(row.data == nullptr or row.data[index] == nullptr), - _value(_is_null ? "" : _cpp_value_type(row.data[index], row.data[index] + row.len[index])) + _result_entry_t(char* data, size_t len): + _is_valid(true), + _value_ptr(data), + _len(_value_ptr ? 0 : len) {} - _result_entry_t& operator=(const raw_result_row_t& row) + void assign(char* data, size_t len) { - _is_valid = (row.data != nullptr); - _is_null = row.data == nullptr or row.data[index] == nullptr; - _value = _is_null ? "" : _cpp_value_type(row.data[index], row.data[index] + row.len[index]); - return *this; + _is_valid = true; + _value_ptr = data; + _len = _value_ptr ? 0 : len; + } + + void invalidate() + { + _is_valid = false; + _value_ptr = nullptr; + _len = 0; } template @@ -138,7 +143,7 @@ namespace sqlpp os << value(); } - bool _is_trivial() const { return value().empty(); } + bool _is_trivial() const { return _len == 0; } bool operator==(const _cpp_value_type& rhs) const { return value() == rhs; } bool operator!=(const _cpp_value_type& rhs) const { return not operator==(rhs); } @@ -147,22 +152,31 @@ namespace sqlpp { if (not _is_valid) throw exception("accessing is_null in non-existing row"); - return _is_null; + return _value_ptr == nullptr; } _cpp_value_type value() const { if (not _is_valid) throw exception("accessing value in non-existing row"); - return _value; + if (_value_ptr) + return std::string(_value_ptr, _value_ptr + _len); + else + return ""; } operator _cpp_value_type() const { return value(); } + template + void bind(Target& target, size_t i) + { + target.bind_text_result(i, &_value_ptr, &_len); + } + private: bool _is_valid; - bool _is_null; - _cpp_value_type _value; + char* _value_ptr; + size_t _len; }; template @@ -188,8 +202,7 @@ namespace sqlpp }; }; - template - std::ostream& operator<<(std::ostream& os, const text::_result_entry_t& e) + inline std::ostream& operator<<(std::ostream& os, const text::_result_entry_t& e) { return os << e.value(); } From 6e5ee5657772c5788d04c64788bf70de410547eb Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Thu, 2 Jan 2014 20:20:58 +0100 Subject: [PATCH 14/26] prepared to detemplatify connector results --- include/sqlpp11/boolean.h | 1 - .../{raw_result_row.h => char_result_row.h} | 8 +-- include/sqlpp11/floating_point.h | 6 +- include/sqlpp11/integral.h | 1 - include/sqlpp11/prepared_select.h | 2 +- include/sqlpp11/result.h | 47 +++++++------- include/sqlpp11/result_row.h | 63 ++++++++----------- include/sqlpp11/select.h | 2 +- include/sqlpp11/text.h | 1 - 9 files changed, 60 insertions(+), 71 deletions(-) rename include/sqlpp11/{raw_result_row.h => char_result_row.h} (91%) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 798d2175..f345406a 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -30,7 +30,6 @@ #include #include #include -#include #include namespace sqlpp diff --git a/include/sqlpp11/raw_result_row.h b/include/sqlpp11/char_result_row.h similarity index 91% rename from include/sqlpp11/raw_result_row.h rename to include/sqlpp11/char_result_row.h index 32f15626..b4f884a9 100644 --- a/include/sqlpp11/raw_result_row.h +++ b/include/sqlpp11/char_result_row.h @@ -24,17 +24,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_RAW_RESULT_ROW_H -#define SQLPP_RAW_RESULT_ROW_H +#ifndef SQLPP_CHAR_RESULT_ROW_H +#define SQLPP_CHAR_RESULT_ROW_H namespace sqlpp { - struct raw_result_row_t + struct char_result_row_t { char** data; size_t* len; - bool operator==(const raw_result_row_t& rhs) const + bool operator==(const char_result_row_t& rhs) const { return data == rhs.data and len == rhs.len; } diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 24ae32e9..ad6c3f29 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include // FIXME: Need to update floating_point #include namespace sqlpp @@ -113,13 +113,13 @@ namespace sqlpp _value(0) {} - _result_entry_t(const raw_result_row_t& row): + _result_entry_t(const char_result_row_t& row): _is_valid(row.data != nullptr), _is_null(row.data == nullptr or row.data[index] == nullptr), _value(_is_null ? 0 : std::strtod(row.data[index], nullptr)) {} - _result_entry_t& operator=(const raw_result_row_t& row) + _result_entry_t& operator=(const char_result_row_t& row) { _is_valid = (row.data != nullptr); _is_null = row.data == nullptr or row.data[index] == nullptr; diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index a52d44c2..c1208874 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -30,7 +30,6 @@ #include #include #include -#include #include namespace sqlpp diff --git a/include/sqlpp11/prepared_select.h b/include/sqlpp11/prepared_select.h index 8f3304d4..27696bf3 100644 --- a/include/sqlpp11/prepared_select.h +++ b/include/sqlpp11/prepared_select.h @@ -41,7 +41,7 @@ namespace sqlpp using _prepared_query_t = typename Db::_prepared_query_t; auto run(Db& db) const - -> result_t + -> result_t { return {db.run_prepared_select(*this)}; } diff --git a/include/sqlpp11/result.h b/include/sqlpp11/result.h index f7ea4c8d..7f893ee6 100644 --- a/include/sqlpp11/result.h +++ b/include/sqlpp11/result.h @@ -27,31 +27,30 @@ #ifndef SQLPP_RESULT_H #define SQLPP_RESULT_H -#include - #include namespace sqlpp { - template + template class result_t { using db_result_t = DbResult; - using result_row_t = typename db_result_t::result_row_t; + using result_row_t = ResultRow; - db_result_t _db_result; + db_result_t _result; + result_row_t _result_row; db_result_t _end; + result_row_t _end_row; public: - result_t(): - _db_result(), - _end() - {} + result_t() = default; - result_t(db_result_t&& result): - _db_result(std::move(result)), - _end() + template + result_t(db_result_t&& result, const DynamicNames& dynamic_names): + _result(std::move(result)), + _result_row(dynamic_names) { + _result.next(_result_row); } result_t(const result_t&) = delete; @@ -63,24 +62,25 @@ namespace sqlpp class iterator { public: - iterator(db_result_t& result): - _result(result) + iterator(db_result_t& result, result_row_t& result_row): + _result(result), + _result_row(result_row) { } const result_row_t& operator*() const { - return _result.front(); + return _result_row; } const result_row_t* operator->() const { - return &_result.front(); + return &_result_row; } bool operator==(const iterator& rhs) const { - return _result.front() == rhs._result.front(); + return _result_row == rhs._result_row; } bool operator!=(const iterator& rhs) const @@ -90,35 +90,36 @@ namespace sqlpp void operator++() { - _result.pop_front(); + _result.next(result_row); } db_result_t& _result; + result_row_t& _result_row; }; iterator begin() { - return iterator(_db_result); + return iterator(_result, _result_row); } iterator end() { - return iterator(_end); + return iterator(_end, _end_row); } const result_row_t& front() const { - return _db_result.front(); + return _result_row; } bool empty() const { - return _db_result.front() == _end.front(); + return _result_row == _end_row; } void pop_front() { - _db_result.pop_front(); + _result.next(_result_row); } }; diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 9ed148b9..644c0869 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -27,7 +27,7 @@ #ifndef SQLPP_RESULT_ROW_H #define SQLPP_RESULT_ROW_H -#include +#include #include #include #include @@ -52,16 +52,16 @@ namespace sqlpp static constexpr size_t _last_index = _rest::_last_index; result_row_impl() = default; - result_row_impl(const raw_result_row_t& raw_result_row): - _field({{raw_result_row.data[index], raw_result_row.len[index]}}), - _rest(raw_result_row) + result_row_impl(const char_result_row_t& char_result_row_t): + _field({{char_result_row_t.data[index], char_result_row_t.len[index]}}), + _rest(char_result_row_t) { } - result_row_impl& operator=(const raw_result_row_t& raw_result_row) + result_row_impl& operator=(const char_result_row_t& char_result_row_t) { - _field::operator()().assign(raw_result_row.data[index], raw_result_row.len[index]); - _rest::operator=(raw_result_row); + _field::operator()().assign(char_result_row_t.data[index], char_result_row_t.len[index]); + _rest::operator=(char_result_row_t); return *this; } @@ -90,15 +90,15 @@ namespace sqlpp static constexpr size_t _last_index = _rest::_last_index; result_row_impl() = default; - result_row_impl(const raw_result_row_t& raw_result_row): - _multi_field({raw_result_row}), - _rest(raw_result_row) + result_row_impl(const char_result_row_t& char_result_row_t): + _multi_field({char_result_row_t}), + _rest(char_result_row_t) {} - result_row_impl& operator=(const raw_result_row_t& raw_result_row) + result_row_impl& operator=(const char_result_row_t& char_result_row_t) { - _multi_field::operator=({raw_result_row}); - _rest::operator=(raw_result_row); + _multi_field::operator=({char_result_row_t}); + _rest::operator=(char_result_row_t); return *this; } @@ -121,11 +121,11 @@ namespace sqlpp { static constexpr size_t _last_index = index; result_row_impl() = default; - result_row_impl(const raw_result_row_t& raw_result_row) + result_row_impl(const char_result_row_t& char_result_row_t) { } - result_row_impl& operator=(const raw_result_row_t& raw_result_row) + result_row_impl& operator=(const char_result_row_t& char_result_row_t) { return *this; } @@ -154,10 +154,10 @@ namespace sqlpp { } - template - result_row_t(const raw_result_row_t& raw_result_row, const T&): - _impl(raw_result_row), - _is_valid(true) + template + result_row_t(const DynamicNames&): + _impl(), + _is_valid(false) { } @@ -166,9 +166,9 @@ namespace sqlpp result_row_t& operator=(const result_row_t&) = delete; result_row_t& operator=(result_row_t&&) = default; - result_row_t& operator=(const raw_result_row_t& raw_result_row) + result_row_t& operator=(const char_result_row_t& char_result_row_t) { - _impl::operator=(raw_result_row); + _impl::operator=(char_result_row_t); _is_valid = true; return *this; } @@ -218,20 +218,11 @@ namespace sqlpp { } - dynamic_result_row_t(const raw_result_row_t& raw_result_row, std::vector dynamic_columns): - _impl(raw_result_row), - _is_valid(true), + dynamic_result_row_t(const std::vector& dynamic_columns): + _impl(), + _is_valid(false), _dynamic_columns(dynamic_columns) { - raw_result_row_t dynamic_row = raw_result_row; - dynamic_row.data += _last_static_index; - dynamic_row.len += _last_static_index; - for (const auto& column : _dynamic_columns) - { - _dynamic_fields.insert(std::make_pair(column, _field_type(dynamic_row.data[0], dynamic_row.len[0]))); - ++dynamic_row.data; - ++dynamic_row.len; - } } dynamic_result_row_t(const dynamic_result_row_t&) = delete; @@ -239,12 +230,12 @@ namespace sqlpp dynamic_result_row_t& operator=(const dynamic_result_row_t&) = delete; dynamic_result_row_t& operator=(dynamic_result_row_t&&) = default; - dynamic_result_row_t& operator=(const raw_result_row_t& raw_result_row) + dynamic_result_row_t& operator=(const char_result_row_t& char_result_row) { - _impl::operator=(raw_result_row); + _impl::operator=(char_result_row); _is_valid = true; - raw_result_row_t dynamic_row = raw_result_row; + char_result_row_t dynamic_row = char_result_row; dynamic_row.data += _last_static_index; dynamic_row.len += _last_static_index; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 9fa3592f..df5f9732 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -586,7 +586,7 @@ namespace sqlpp // Execute template auto run(Db& db) const - -> result_t + -> result_t { static_assert(not is_noop::value, "cannot run select without having selected anything"); static_assert(is_from_t::value, "cannot run select without a from()"); diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 8eee1774..d2fda13c 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include From 099250945cc9743e91e606a9a0e7e23293aa01f0 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Fri, 3 Jan 2014 14:27:06 +0100 Subject: [PATCH 15/26] Successfully running the first prepared select statement including result evaluation --- include/sqlpp11/any.h | 2 + include/sqlpp11/avg.h | 2 + include/sqlpp11/count.h | 2 + include/sqlpp11/exists.h | 2 + include/sqlpp11/floating_point.h | 65 +++++++++++++++++++++---------- include/sqlpp11/integral.h | 16 ++++---- include/sqlpp11/max.h | 2 + include/sqlpp11/min.h | 2 + include/sqlpp11/prepared_select.h | 2 +- include/sqlpp11/result.h | 2 +- include/sqlpp11/result_row.h | 26 ++++++++++++- include/sqlpp11/select.h | 2 +- include/sqlpp11/some.h | 2 + include/sqlpp11/sum.h | 2 + 14 files changed, 94 insertions(+), 35 deletions(-) diff --git a/include/sqlpp11/any.h b/include/sqlpp11/any.h index 43b6f3c4..12393dff 100644 --- a/include/sqlpp11/any.h +++ b/include/sqlpp11/any.h @@ -52,6 +52,8 @@ namespace sqlpp struct _member_t { T any; + T& operator()() { return any; } + const T& operator()() const { return any; } }; }; diff --git a/include/sqlpp11/avg.h b/include/sqlpp11/avg.h index 01223923..b0782dd3 100644 --- a/include/sqlpp11/avg.h +++ b/include/sqlpp11/avg.h @@ -51,6 +51,8 @@ namespace sqlpp struct _member_t { T avg; + T& operator()() { return avg; } + const T& operator()() const { return avg; } }; }; diff --git a/include/sqlpp11/count.h b/include/sqlpp11/count.h index f1b4d187..28e331e4 100644 --- a/include/sqlpp11/count.h +++ b/include/sqlpp11/count.h @@ -51,6 +51,8 @@ namespace sqlpp struct _member_t { T count; + T& operator()() { return count; } + const T& operator()() const { return count; } }; }; diff --git a/include/sqlpp11/exists.h b/include/sqlpp11/exists.h index 83f96b44..0451ba36 100644 --- a/include/sqlpp11/exists.h +++ b/include/sqlpp11/exists.h @@ -51,6 +51,8 @@ namespace sqlpp struct _member_t { T exists; + T& operator()() { return exists; } + const T& operator()() const { return exists; } }; }; diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index ad6c3f29..484ec538 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -48,25 +48,31 @@ namespace sqlpp using _is_expression = std::true_type; using _cpp_value_type = double; - template struct _parameter_t { - using _value_type = floating_point; + using _value_type = integral; - _parameter_t(): + _parameter_t(const std::true_type&): + _trivial_value_is_null(true), _value(0), - _is_null(TrivialValueIsNull and _is_trivial()) + _is_null(_trivial_value_is_null and _is_trivial()) + {} + + _parameter_t(const std::false_type&): + _trivial_value_is_null(false), + _value(0), + _is_null(_trivial_value_is_null and _is_trivial()) {} _parameter_t(const _cpp_value_type& value): _value(value), - _is_null(TrivialValueIsNull and _is_trivial()) + _is_null(_trivial_value_is_null and _is_trivial()) {} _parameter_t& operator=(const _cpp_value_type& value) { _value = value; - _is_null = (TrivialValueIsNull and _is_trivial()); + _is_null = (_trivial_value_is_null and _is_trivial()); return *this; } @@ -90,22 +96,28 @@ namespace sqlpp return _is_null; } - _cpp_value_type value() const + const _cpp_value_type& value() const { return _value; } - operator _cpp_value_type() const { return value(); } + operator _cpp_value_type() const { return _value; } + + template + void bind(Target& target, size_t index) const + { + target.bind_floating_point_parameter(index, &_value, _is_null); + } private: + bool _trivial_value_is_null; _cpp_value_type _value; bool _is_null; }; - template struct _result_entry_t { - using _value_type = floating_point; + using _value_type = integral; _result_entry_t(): _is_valid(false), @@ -113,18 +125,24 @@ namespace sqlpp _value(0) {} - _result_entry_t(const char_result_row_t& row): - _is_valid(row.data != nullptr), - _is_null(row.data == nullptr or row.data[index] == nullptr), - _value(_is_null ? 0 : std::strtod(row.data[index], nullptr)) + _result_entry_t(const char* data, size_t): + _is_valid(true), + _is_null(data == nullptr), + _value(_is_null ? 0 : std::strtoll(data, nullptr, 10)) {} - _result_entry_t& operator=(const char_result_row_t& row) + void assign(const char* data, size_t) { - _is_valid = (row.data != nullptr); - _is_null = row.data == nullptr or row.data[index] == nullptr; - _value = _is_null ? 0 : std::strtod(row.data[index], nullptr); - return *this; + _is_valid = true; + _is_null = data == nullptr; + _value = _is_null ? 0 : std::strtoll(data, nullptr, 10); + } + + void invalidate() + { + _is_valid = false; + _is_null = true; + _value = 0; } template @@ -151,6 +169,12 @@ namespace sqlpp operator _cpp_value_type() const { return value(); } + template + void bind(Target& target, size_t i) + { + target.bind_floating_point_result(i, &_value, &_is_null); + } + private: bool _is_valid; bool _is_null; @@ -243,8 +267,7 @@ namespace sqlpp }; }; - template - std::ostream& operator<<(std::ostream& os, const floating_point::_result_entry_t& e) + inline std::ostream& operator<<(std::ostream& os, const floating_point::_result_entry_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index c1208874..ac2e6b82 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -63,13 +63,7 @@ namespace sqlpp _is_null(_trivial_value_is_null and _is_trivial()) {} - _parameter_t(bool trivial_value_is_null): - _trivial_value_is_null(trivial_value_is_null), - _value(0), - _is_null(_trivial_value_is_null and _is_trivial()) - {} - - _parameter_t(const _cpp_value_type& value): + explicit _parameter_t(const _cpp_value_type& value): _value(value), _is_null(_trivial_value_is_null and _is_trivial()) {} @@ -81,11 +75,10 @@ namespace sqlpp return *this; } - _parameter_t& operator=(const std::nullptr_t&) + void set_null() { _value = 0; _is_null = true; - return *this; } template @@ -150,6 +143,11 @@ namespace sqlpp _value = 0; } + void validate() + { + _is_valid = true; + } + template void serialize(std::ostream& os, Db& db) const { diff --git a/include/sqlpp11/max.h b/include/sqlpp11/max.h index d3e32690..1310e674 100644 --- a/include/sqlpp11/max.h +++ b/include/sqlpp11/max.h @@ -51,6 +51,8 @@ namespace sqlpp struct _member_t { T max; + T& operator()() { return max; } + const T& operator()() const { return max; } }; }; diff --git a/include/sqlpp11/min.h b/include/sqlpp11/min.h index 3d1c76b4..2e0f6205 100644 --- a/include/sqlpp11/min.h +++ b/include/sqlpp11/min.h @@ -51,6 +51,8 @@ namespace sqlpp struct _member_t { T min; + T& operator()() { return min; } + const T& operator()() const { return min; } }; }; diff --git a/include/sqlpp11/prepared_select.h b/include/sqlpp11/prepared_select.h index 27696bf3..6553aa4e 100644 --- a/include/sqlpp11/prepared_select.h +++ b/include/sqlpp11/prepared_select.h @@ -43,7 +43,7 @@ namespace sqlpp auto run(Db& db) const -> result_t { - return {db.run_prepared_select(*this)}; + return {db.run_prepared_select(*this), _dynamic_names}; } void bind_params() const diff --git a/include/sqlpp11/result.h b/include/sqlpp11/result.h index 7f893ee6..f27f3937 100644 --- a/include/sqlpp11/result.h +++ b/include/sqlpp11/result.h @@ -90,7 +90,7 @@ namespace sqlpp void operator++() { - _result.next(result_row); + _result.next(_result_row); } db_result_t& _result; diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 644c0869..15479324 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -65,6 +65,12 @@ namespace sqlpp return *this; } + void validate() + { + _field::operator()().validate(); + _rest::validate(); + } + void invalidate() { _field::operator()().invalidate(); @@ -97,14 +103,20 @@ namespace sqlpp result_row_impl& operator=(const char_result_row_t& char_result_row_t) { - _multi_field::operator=({char_result_row_t}); + _multi_field::operator()() = char_result_row_t; _rest::operator=(char_result_row_t); return *this; } + void validate() + { + _multi_field::operator()().validate(); + _rest::validate(); + } + void invalidate() { - _multi_field::invalidate(); + _multi_field::operator()().invalidate(); _rest::invalidate(); } @@ -130,6 +142,10 @@ namespace sqlpp return *this; } + void validate() + { + } + void invalidate() { } @@ -173,6 +189,12 @@ namespace sqlpp return *this; } + void validate() + { + _impl::validate(); + _is_valid = true; + } + void invalidate() { _impl::invalidate(); diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index df5f9732..df6d860f 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -594,7 +594,7 @@ namespace sqlpp // FIXME: Check for missing aliases (if references are used) // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. - return {db.select(*this)}; + return {db.select(*this), get_dynamic_names()}; } template diff --git a/include/sqlpp11/some.h b/include/sqlpp11/some.h index 0a538822..f4c8bd40 100644 --- a/include/sqlpp11/some.h +++ b/include/sqlpp11/some.h @@ -52,6 +52,8 @@ namespace sqlpp struct _member_t { T some; + T& operator()() { return some; } + const T& operator()() const { return some; } }; }; diff --git a/include/sqlpp11/sum.h b/include/sqlpp11/sum.h index 1f9b3ef4..7d11201e 100644 --- a/include/sqlpp11/sum.h +++ b/include/sqlpp11/sum.h @@ -51,6 +51,8 @@ namespace sqlpp struct _member_t { T sum; + T& operator()() { return sum; } + const T& operator()() const { return sum; } }; }; From 5b77bf3fea850a5983f8674692dd1ae2693980fc Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sat, 4 Jan 2014 10:20:58 +0100 Subject: [PATCH 16/26] Added missing validate methods --- include/sqlpp11/boolean.h | 5 +++++ include/sqlpp11/floating_point.h | 5 +++++ include/sqlpp11/text.h | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index f345406a..f1fb9c35 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -140,6 +140,11 @@ namespace sqlpp _value = _is_null ? false : (data[0] == 't' or data[0] == '1'); } + void validate() + { + _is_valid = true; + } + void invalidate() { _is_valid = false; diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 484ec538..b5236ab3 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -138,6 +138,11 @@ namespace sqlpp _value = _is_null ? 0 : std::strtoll(data, nullptr, 10); } + void validate() + { + _is_valid = true; + } + void invalidate() { _is_valid = false; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index d2fda13c..3947bb16 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -129,6 +129,11 @@ namespace sqlpp _len = _value_ptr ? 0 : len; } + void validate() + { + _is_valid = true; + } + void invalidate() { _is_valid = false; From bbf18e4f7a3d0320cc3e55eda5b1d258b5eaab61 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sat, 4 Jan 2014 18:21:48 +0100 Subject: [PATCH 17/26] Changed data type for boolean to signed char (seems to be more common for binary bindings) --- include/sqlpp11/boolean.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index f1fb9c35..f2d743c8 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -115,7 +115,7 @@ namespace sqlpp private: bool _trivial_value_is_null; - _cpp_value_type _value; + signed char _value; bool _is_null; }; @@ -185,7 +185,7 @@ namespace sqlpp private: bool _is_valid; bool _is_null; - _cpp_value_type _value; + signed char _value; }; template From c140e13510ee272b4d7b4c971d070e225554dc07 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sat, 4 Jan 2014 18:26:11 +0100 Subject: [PATCH 18/26] Small fix for dynamic results and a hint for positional parameters --- include/sqlpp11/result_row.h | 2 +- include/sqlpp11/select.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 15479324..32518e12 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -263,7 +263,7 @@ namespace sqlpp dynamic_row.len += _last_static_index; for (const auto& column : _dynamic_columns) { - _dynamic_fields.at(column).assign(dynamic_row.data[0], dynamic_row.len[0]); + _dynamic_fields[column].assign(dynamic_row.data[0], dynamic_row.len[0]); ++dynamic_row.data; ++dynamic_row.len; } diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index df6d860f..7c3d3a2b 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -150,6 +150,7 @@ namespace sqlpp _limit(std::move(limit)), _offset(std::move(offset)) { + // FIXME: Need to calculate parameter positions here and in other constructors } constexpr select_t(const Flags& flags, const ExpressionList& expression_list, const From& from, From 409fa3baaca2eb57c2a6c191be5378a9c55f4175 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sat, 4 Jan 2014 19:32:18 +0100 Subject: [PATCH 19/26] Test with boolean and text parameters in prepared query compiles and runs with mysql --- include/sqlpp11/boolean.h | 6 ++++++ include/sqlpp11/text.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index f2d743c8..fa86f3c6 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -113,6 +113,12 @@ namespace sqlpp operator _cpp_value_type() const { return value(); } + template + void bind(Target& target, size_t index) const + { + target.bind_boolean_parameter(index, &_value, _is_null); + } + private: bool _trivial_value_is_null; signed char _value; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 3947bb16..f003c115 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -102,6 +102,12 @@ namespace sqlpp operator _cpp_value_type() const { return value(); } + template + void bind(Target& target, size_t index) const + { + target.bind_text_parameter(index, &_value, _is_null); + } + private: bool _trivial_value_is_null; _cpp_value_type _value; From 51e0db883f632b456c5c707f38e76e6464047148 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sun, 5 Jan 2014 13:29:08 +0100 Subject: [PATCH 20/26] Added static assert to prevent automatic rivial->null conversion to happen in where/having --- include/sqlpp11/having.h | 7 +++++-- include/sqlpp11/parameter.h | 11 +++++++++-- include/sqlpp11/parameter_list.h | 22 +++++++++++++++++++++- include/sqlpp11/where.h | 8 ++++++-- tests/PreparedTest.cpp | 2 +- 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index eed521d5..93db4806 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -41,11 +41,15 @@ namespace sqlpp { using _is_having = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in having()"); using _valid_expressions = typename detail::make_set_if::type; static_assert(_valid_expressions::size::value == sizeof...(Expr), "at least one argument is not an expression in having()"); + using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; + static_assert(not _parameter_list_t::_contains_trivial_value_is_null_t::value, "must not use trivial_value_is_null in parameters of having expression, use where_parameter() instead of parameter() to turn off automatic conversion"); + template void add(E&& expr) { @@ -70,8 +74,7 @@ namespace sqlpp return set_parameter_index(_expressions, index); } - using _parameter_tuple_t = std::tuple; - _parameter_tuple_t _expressions; // FIXME: Do we need those? + _parameter_tuple_t _expressions; detail::serializable_list _dynamic_expressions; }; diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index 2563f32c..f76fded8 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -40,9 +40,9 @@ namespace sqlpp using _is_parameter = std::true_type; using _is_expression_t = std::true_type; using _instance_t = typename NameType::_name_t::template _member_t; - using _trivial_value_is_null = TrivialValueIsNull; + using _trivial_value_is_null_t = TrivialValueIsNull; - static_assert(std::is_same<_trivial_value_is_null, std::true_type>::value or std::is_same<_trivial_value_is_null, std::false_type>::value, "Invalid template parameter TrivialValueIsNull"); + static_assert(std::is_same<_trivial_value_is_null_t, std::true_type>::value or std::is_same<_trivial_value_is_null_t, std::false_type>::value, "Invalid template parameter TrivialValueIsNull"); template void serialize(std::ostream& os, Db& db) const @@ -70,6 +70,13 @@ namespace sqlpp return {}; } + template + auto where_parameter(NamedExpr&& namedExpr) + -> parameter_t::type::_value_type, typename std::decay::type, std::false_type> + { + return {}; + } + } #endif diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index 406d752d..51571ee9 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -32,6 +32,25 @@ namespace sqlpp { + namespace detail + { + template + struct or_t; + + template + struct or_t + { + static constexpr bool value = T::value or or_t::value; + }; + + template<> + struct or_t<> + { + static constexpr bool value = false; + }; + + } + template struct parameter_list_t { @@ -43,9 +62,10 @@ namespace sqlpp { using _member_tuple_t = std::tuple; using size = std::integral_constant; + using _contains_trivial_value_is_null_t = detail::or_t; parameter_list_t(): - Parameter::_instance_t({typename Parameter::_trivial_value_is_null()})... + Parameter::_instance_t({typename Parameter::_trivial_value_is_null_t()})... {} template diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index d9996d3f..bd774dd6 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -34,6 +34,7 @@ #include #include #include +#include namespace sqlpp { @@ -42,11 +43,15 @@ namespace sqlpp { using _is_where = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in where()"); using _valid_expressions = typename detail::make_set_if::type; static_assert(_valid_expressions::size::value == sizeof...(Expr), "at least one argument is not an expression in where()"); + using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; + static_assert(not _parameter_list_t::_contains_trivial_value_is_null_t::value, "must not use trivial_value_is_null in parameters of where expression, use where_parameter() instead of parameter() to turn off automatic conversion"); + template void add(E&& expr) { @@ -69,8 +74,7 @@ namespace sqlpp return set_parameter_index(_expressions, index); } - using _parameter_tuple_t = std::tuple; - _parameter_tuple_t _expressions; // FIXME: Do we need those? + _parameter_tuple_t _expressions; detail::serializable_list _dynamic_expressions; }; } diff --git a/tests/PreparedTest.cpp b/tests/PreparedTest.cpp index f3c36cc1..627bcf3a 100644 --- a/tests/PreparedTest.cpp +++ b/tests/PreparedTest.cpp @@ -87,7 +87,7 @@ int main() // Wonderful, now take a look at the parameter list of a select { - auto s = select(all_of(t)).from(t).where(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma)); + auto s = select(all_of(t)).from(t).where(t.beta.like(where_parameter(t.beta)) and t.alpha == where_parameter(t.alpha) or t.gamma != parameter(t.gamma)); using S = decltype(s); using T = sqlpp::make_parameter_list_t::type; T npl; From b8907df4efbe29d83e0a0f64dc2df4477ecf433b Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sun, 5 Jan 2014 19:25:52 +0100 Subject: [PATCH 21/26] Implemented parameter index determination --- include/sqlpp11/expression.h | 4 +- include/sqlpp11/like.h | 7 ++++ include/sqlpp11/parameter.h | 10 ++++- include/sqlpp11/parameter_list.h | 64 ++++++++++++++++++++++++++++++++ include/sqlpp11/select.h | 19 +++++++--- 5 files changed, 96 insertions(+), 8 deletions(-) diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index 1b655e4a..3e38679c 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -31,6 +31,7 @@ #include #include #include +#include // FIXME: a forward for set_parameter_index would be nice here namespace sqlpp { @@ -45,7 +46,8 @@ namespace sqlpp size_t _set_parameter_index(size_t index) { index = set_parameter_index(_lhs, index); - return set_parameter_index(_rhs, index); + index = set_parameter_index(_rhs, index); + return index; } template diff --git a/include/sqlpp11/like.h b/include/sqlpp11/like.h index 4ee099d0..1043d4d6 100644 --- a/include/sqlpp11/like.h +++ b/include/sqlpp11/like.h @@ -74,6 +74,13 @@ namespace sqlpp like_t& operator=(like_t&&) = default; ~like_t() = default; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_operand, index); + index = set_parameter_index(_pattern, index); + return index; + } + template void serialize(std::ostream& os, Db& db) const { diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index f76fded8..eaa8b72f 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -52,7 +52,7 @@ namespace sqlpp if (Db::_use_questionmark_parameter) os << '?'; else if (Db::_use_positional_dollar_parameter) - os << '$' << index + 1; + os << '$' << _index + 1; } constexpr bool _is_trivial() const @@ -60,7 +60,13 @@ namespace sqlpp return false; } - size_t index; + size_t _set_parameter_index(size_t index) + { + _index = index; + return index + 1; + } + + size_t _index; }; template::type>> diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index 51571ee9..c2bf0b68 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -126,6 +126,70 @@ namespace sqlpp using type = parameter_list_t::type>::type>; }; + template + size_t set_parameter_index(T& t, size_t index); + + namespace detail + { + template + struct set_parameter_index_t + { + size_t operator()(Exp& e, size_t index) + { + return index; + } + }; + + template + struct set_parameter_index_t::value, void>::type> + { + size_t operator()(Exp& e, size_t index) + { + return e._set_parameter_index(index); + } + }; + + template + struct set_parameter_index_t, void> + { + template struct type{}; + + size_t operator()(std::tuple& t, size_t index) + { + return impl(t, index, type<0>()); + } + private: + template + size_t impl(std::tuple& t, size_t index, const type&) + { + index = sqlpp::set_parameter_index(std::get(t), index); + return impl(t, index, type()); + } + + size_t impl(std::tuple& t, size_t index, const type&) + { + return index; + } + }; + + template + struct set_parameter_index_t::value, void>::type> + { + size_t operator()(Exp& e, size_t index) + { + return e._set_parameter_index(index); + } + }; + + } + + + template + size_t set_parameter_index(T& t, size_t index) + { + return detail::set_parameter_index_t()(t, index); + } + } #endif diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 7c3d3a2b..68e42f14 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -111,6 +111,8 @@ namespace sqlpp using _result_row_t = typename ExpressionList::_result_row_t; using _dynamic_names_t = typename ExpressionList::_dynamic_names_t; + using _parameter_tuple_t = std::tuple; + using _parameter_list_t = typename make_parameter_list_t::type; // Indicators using _value_type = typename std::conditional< @@ -127,6 +129,7 @@ namespace sqlpp { static_assert(std::is_same>::value, "basic constructor only available for select_t (default template parameters)"); + _set_parameter_index(0); } select_t(const select_t& rhs) = default; @@ -137,7 +140,7 @@ namespace sqlpp // Other constructors - constexpr select_t(Flags&& flags, ExpressionList&& expression_list, From&& from, + select_t(Flags&& flags, ExpressionList&& expression_list, From&& from, Where&& where, GroupBy&& group_by, Having&& having, OrderBy&& order_by, Limit&& limit, Offset&& offset): _flags(std::move(flags)), @@ -150,10 +153,10 @@ namespace sqlpp _limit(std::move(limit)), _offset(std::move(offset)) { - // FIXME: Need to calculate parameter positions here and in other constructors + _set_parameter_index(0); } - constexpr select_t(const Flags& flags, const ExpressionList& expression_list, const From& from, + select_t(const Flags& flags, const ExpressionList& expression_list, const From& from, const Where& where, const GroupBy& group_by, const Having& having, const OrderBy& order_by, const Limit& limit, const Offset& offset): _flags(flags), @@ -166,6 +169,7 @@ namespace sqlpp _limit(limit), _offset(offset) { + _set_parameter_index(0); } auto dynamic_columns() @@ -609,6 +613,13 @@ namespace sqlpp return {{}, get_dynamic_names(), db.prepare_select(*this)}; } + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_where, index); + index = set_parameter_index(_having, index); + return index; + } + Flags _flags; ExpressionList _expression_list; From _from; @@ -618,8 +629,6 @@ namespace sqlpp OrderBy _order_by; Limit _limit; Offset _offset; - using _parameter_tuple_t = std::tuple; - using _parameter_list_t = typename make_parameter_list_t::type; }; // construct select flag list From e601747fca529bf75f912624ec8891b4276e3a11 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Tue, 7 Jan 2014 07:29:55 +0100 Subject: [PATCH 22/26] Assert that parameters are not used in dynamic elements of a query. This will need to change in the future --- include/sqlpp11/detail/serializable.h | 2 ++ include/sqlpp11/having.h | 3 ++- include/sqlpp11/where.h | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/sqlpp11/detail/serializable.h b/include/sqlpp11/detail/serializable.h index 99c78454..1f7e754a 100644 --- a/include/sqlpp11/detail/serializable.h +++ b/include/sqlpp11/detail/serializable.h @@ -30,6 +30,7 @@ #include #include #include +#include namespace sqlpp { @@ -65,6 +66,7 @@ namespace sqlpp template struct _impl_t: public _impl_base { + static_assert(not make_parameter_list_t::type::size::value, "parameters not supported in dynamic query parts"); _impl_t(const T& t): _t(t) {} diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index 93db4806..fe9927e3 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -71,7 +71,8 @@ namespace sqlpp size_t _set_parameter_index(size_t index) { - return set_parameter_index(_expressions, index); + index = set_parameter_index(_expressions, index); + return index; } _parameter_tuple_t _expressions; diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index bd774dd6..782f1ac4 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -71,7 +71,8 @@ namespace sqlpp size_t _set_parameter_index(size_t index) { - return set_parameter_index(_expressions, index); + index = set_parameter_index(_expressions, index); + return index; } _parameter_tuple_t _expressions; From a122924d3751f7013c9eaa1cabdaa89e444236e0 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Wed, 8 Jan 2014 08:02:17 +0100 Subject: [PATCH 23/26] Accepting parameters in other parts of select now (formerly only where and having clauses) --- include/sqlpp11/group_by.h | 9 +++- include/sqlpp11/limit.h | 28 +++++++++---- include/sqlpp11/offset.h | 27 ++++++++---- include/sqlpp11/order_by.h | 9 +++- include/sqlpp11/select.h | 53 ++++++++++++++---------- include/sqlpp11/select_expression_list.h | 9 +++- include/sqlpp11/select_fwd.h | 2 + 7 files changed, 94 insertions(+), 43 deletions(-) diff --git a/include/sqlpp11/group_by.h b/include/sqlpp11/group_by.h index 35312d0a..c25e462b 100644 --- a/include/sqlpp11/group_by.h +++ b/include/sqlpp11/group_by.h @@ -43,6 +43,7 @@ namespace sqlpp { using _is_group_by = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; // ensure one argument at least static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression (e.g. a column) required in group_by()"); @@ -73,7 +74,13 @@ namespace sqlpp _dynamic_expressions.serialize(os, db, sizeof...(Expr) == 0); } - std::tuple _expressions; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_expressions, index); + return index; + } + + _parameter_tuple_t _expressions; detail::serializable_list _dynamic_expressions; }; diff --git a/include/sqlpp11/limit.h b/include/sqlpp11/limit.h index 4205be16..15ec9f08 100644 --- a/include/sqlpp11/limit.h +++ b/include/sqlpp11/limit.h @@ -33,19 +33,29 @@ namespace sqlpp { - struct limit_t - { - using _is_limit = std::true_type; + template + struct limit_t + { + using _is_limit = std::true_type; + using _parameter_tuple_t = std::tuple; + static_assert(std::is_integral::value + or (is_parameter_t::value and is_numeric_t::value), "limit requires an integral value or integral parameter"); - template - void serialize(std::ostream& os, Db& db) const + template + void serialize(std::ostream& os, Db& db) const + { + static_assert(Db::_supports_limit, "limit not supported by current database"); + os << " LIMIT " << _limit; + } + + size_t _set_parameter_index(size_t index) { - static_assert(Db::_supports_limit, "limit not supported by current database"); - os << " LIMIT " << _limit; + index = set_parameter_index(_limit, index); + return index; } - std::size_t _limit; - }; + Limit _limit; + }; struct dynamic_limit_t { diff --git a/include/sqlpp11/offset.h b/include/sqlpp11/offset.h index 2ed223f9..18593d43 100644 --- a/include/sqlpp11/offset.h +++ b/include/sqlpp11/offset.h @@ -33,18 +33,29 @@ namespace sqlpp { - struct offset_t - { - using _is_offset = std::true_type; + template + struct offset_t + { + using _is_offset = std::true_type; + using _parameter_tuple_t = std::tuple; + static_assert(std::is_integral::value + or (is_parameter_t::value and is_numeric_t::value), "offset requires an integral value or integral parameter"); - template - void serialize(std::ostream& os, Db& db) const + + template + void serialize(std::ostream& os, Db& db) const + { + os << " OFFSET " << _offset; + } + + size_t _set_parameter_index(size_t index) { - os << " OFFSET " << _offset; + index = set_parameter_index(_offset, index); + return index; } - const std::size_t _offset; - }; + Offset _offset; + }; struct dynamic_offset_t { diff --git a/include/sqlpp11/order_by.h b/include/sqlpp11/order_by.h index e8c5d22d..8f04cf0f 100644 --- a/include/sqlpp11/order_by.h +++ b/include/sqlpp11/order_by.h @@ -41,6 +41,7 @@ namespace sqlpp { using _is_order_by = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; // check for at least one order expression static_assert(_is_dynamic::value or sizeof...(Expr), "at least one sort-order expression required in order_by()"); @@ -71,7 +72,13 @@ namespace sqlpp _dynamic_expressions.serialize(os, db, sizeof...(Expr) == 0); } - std::tuple _expressions; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_expressions, index); + return index; + } + + _parameter_tuple_t _expressions; detail::serializable_list _dynamic_expressions; }; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 68e42f14..7f549c69 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -111,7 +111,7 @@ namespace sqlpp using _result_row_t = typename ExpressionList::_result_row_t; using _dynamic_names_t = typename ExpressionList::_dynamic_names_t; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; // Indicators @@ -129,7 +129,6 @@ namespace sqlpp { static_assert(std::is_same>::value, "basic constructor only available for select_t (default template parameters)"); - _set_parameter_index(0); } select_t(const select_t& rhs) = default; @@ -153,7 +152,6 @@ namespace sqlpp _limit(std::move(limit)), _offset(std::move(offset)) { - _set_parameter_index(0); } select_t(const Flags& flags, const ExpressionList& expression_list, const From& from, @@ -169,7 +167,6 @@ namespace sqlpp _limit(limit), _offset(offset) { - _set_parameter_index(0); } auto dynamic_columns() @@ -443,23 +440,24 @@ namespace sqlpp return *this; } - auto limit(std::size_t limit) - -> set_limit_t - { - static_assert(not is_noop::value, "cannot call limit() without a from()"); - static_assert(is_noop::value, "cannot call limit() twice for a single select"); - return { + template + auto limit(Expr limit) + -> set_limit_t::type>> + { + static_assert(not is_noop::value, "cannot call limit() without a from()"); + static_assert(is_noop::value, "cannot call limit() twice for a single select"); + return { _flags, - _expression_list, - _from, - _where, - _group_by, - _having, - _order_by, - {limit}, - _offset, - }; - } + _expression_list, + _from, + _where, + _group_by, + _having, + _order_by, + {limit}, + _offset, + }; + } auto dynamic_limit(std::size_t limit = 0) ->set_limit_t @@ -488,8 +486,9 @@ namespace sqlpp return *this; } - auto offset(std::size_t offset) - -> set_offset_t + template + auto offset(Expr offset) + -> set_offset_t::type>> { static_assert(not is_noop::value, "cannot call offset() without a limit"); static_assert(is_noop::value, "cannot call offset() twice for a single select"); @@ -602,21 +601,29 @@ namespace sqlpp return {db.select(*this), get_dynamic_names()}; } + // Prepare template - prepared_select_t::type, select_t> prepare(Db& db) const + auto prepare(Db& db) + -> prepared_select_t::type, select_t> { static_assert(not is_noop::value, "cannot run select without having selected anything"); static_assert(is_from_t::value, "cannot run select without a from()"); // FIXME: Check for missing aliases (if references are used) // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. + _set_parameter_index(0); return {{}, get_dynamic_names(), db.prepare_select(*this)}; } size_t _set_parameter_index(size_t index) { + index = set_parameter_index(_expression_list, index); index = set_parameter_index(_where, index); + index = set_parameter_index(_group_by, index); index = set_parameter_index(_having, index); + index = set_parameter_index(_order_by, index); + index = set_parameter_index(_limit, index); + index = set_parameter_index(_offset, index); return index; } diff --git a/include/sqlpp11/select_expression_list.h b/include/sqlpp11/select_expression_list.h index 3fb6e0f5..cb1b25c3 100644 --- a/include/sqlpp11/select_expression_list.h +++ b/include/sqlpp11/select_expression_list.h @@ -107,6 +107,7 @@ namespace sqlpp { using _is_select_expression_list = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; // check for duplicate select expressions static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected"); @@ -160,7 +161,13 @@ namespace sqlpp _dynamic_expressions.serialize(os, db, sizeof...(NamedExpr) == 0); } - std::tuple _expressions; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_expressions, index); + return index; + } + + _parameter_tuple_t _expressions; detail::dynamic_select_expression_list _dynamic_expressions; }; diff --git a/include/sqlpp11/select_fwd.h b/include/sqlpp11/select_fwd.h index 57486a06..ec50ce1d 100644 --- a/include/sqlpp11/select_fwd.h +++ b/include/sqlpp11/select_fwd.h @@ -50,8 +50,10 @@ namespace sqlpp template struct order_by_t; + template struct limit_t; + template struct offset_t; template< From 3f519d6fcea2f49d6502ea8b5baf2c71a80b12aa Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 8 Jan 2014 21:31:29 +0100 Subject: [PATCH 24/26] Started to add prepared statement support for insert, update and remove --- include/sqlpp11/insert.h | 36 +++++++++++++++++-- include/sqlpp11/insert_list.h | 9 ++++- include/sqlpp11/prepared_insert.h | 58 +++++++++++++++++++++++++++++++ include/sqlpp11/prepared_remove.h | 58 +++++++++++++++++++++++++++++++ include/sqlpp11/prepared_select.h | 2 +- include/sqlpp11/prepared_update.h | 58 +++++++++++++++++++++++++++++++ include/sqlpp11/select.h | 4 +-- 7 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 include/sqlpp11/prepared_insert.h create mode 100644 include/sqlpp11/prepared_remove.h create mode 100644 include/sqlpp11/prepared_update.h diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index 498e3dc1..6dd0fc8e 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -32,6 +32,9 @@ #include #include #include +#include +#include + #include namespace sqlpp @@ -56,6 +59,9 @@ namespace sqlpp template using set_insert_list_t = insert_t; + using _parameter_tuple_t = std::tuple; + using _parameter_list_t = typename make_parameter_list_t::type; + template auto set(Assignment&&... assignment) -> set_insert_list_t::type...>> @@ -105,6 +111,11 @@ namespace sqlpp return *this; } + static constexpr size_t _get_static_no_of_parameters() + { + return _parameter_list_t::size::value; + } + template insert_t& serialize(std::ostream& os, Db& db) { @@ -118,11 +129,30 @@ namespace sqlpp constexpr bool calledSet = not is_noop::value; constexpr bool requireSet = Table::_required_insert_columns::size::value > 0; static_assert(calledSet or not requireSet, "calling set() required for given table"); - std::ostringstream oss; - serialize(oss, db); - return db.insert(oss.str()); + static_assert(_get_static_no_of_parameters() == 0, "cannot run insert directly with parameters, use prepare instead"); + return db.insert(*this); } + template + auto prepare(Db& db) + -> prepared_insert_t::type, insert_t> + { + constexpr bool calledSet = not is_noop::value; + constexpr bool requireSet = Table::_required_insert_columns::size::value > 0; + static_assert(calledSet or not requireSet, "calling set() required for given table"); + + _set_parameter_index(0); + return {{}, db.prepare_insert(*this)}; + } + + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_table, index); + index = set_parameter_index(_insert_list, index); + return index; + } + + Table _table; InsertList _insert_list; }; diff --git a/include/sqlpp11/insert_list.h b/include/sqlpp11/insert_list.h index e7e02270..d19bc892 100644 --- a/include/sqlpp11/insert_list.h +++ b/include/sqlpp11/insert_list.h @@ -63,6 +63,7 @@ namespace sqlpp { using _is_insert_list = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; // check for at least one order expression static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one select expression required in set()"); @@ -119,8 +120,14 @@ namespace sqlpp } } + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_values, index); + return index; + } + std::tuple...> _columns; - std::tuple _values; + _parameter_tuple_t _values; typename detail::serializable_list _dynamic_columns; typename detail::serializable_list _dynamic_values; }; diff --git a/include/sqlpp11/prepared_insert.h b/include/sqlpp11/prepared_insert.h new file mode 100644 index 00000000..3895084e --- /dev/null +++ b/include/sqlpp11/prepared_insert.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_PREPARED_INSERT_H +#define SQLPP_PREPARED_INSERT_H + +#include +#include + +namespace sqlpp +{ + template + struct prepared_insert_t + { + using _parameter_list_t = typename Insert::_parameter_list_t; + using _prepared_query_t = typename Db::_prepared_query_t; + + auto run(Db& db) const + -> size_t + { + return db.run_prepared_insert(*this); + } + + void _bind_params() const + { + params._bind(_prepared_query); + } + + _parameter_list_t params; + mutable _prepared_query_t _prepared_query; + }; + +} + +#endif diff --git a/include/sqlpp11/prepared_remove.h b/include/sqlpp11/prepared_remove.h new file mode 100644 index 00000000..0dcd2b30 --- /dev/null +++ b/include/sqlpp11/prepared_remove.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_PREPARED_REMOVE_H +#define SQLPP_PREPARED_REMOVE_H + +#include +#include + +namespace sqlpp +{ + template + struct prepared_select_t + { + using _parameter_list_t = typename Remove::_parameter_list_t; + using _prepared_query_t = typename Db::_prepared_query_t; + + auto run(Db& db) const + -> size_t + { + return db.run_prepared_insert(*this); + } + + void _bind_params() const + { + params._bind(_prepared_query); + } + + _parameter_list_t params; + mutable _prepared_query_t _prepared_query; + }; + +} + +#endif diff --git a/include/sqlpp11/prepared_select.h b/include/sqlpp11/prepared_select.h index 6553aa4e..4654cc4e 100644 --- a/include/sqlpp11/prepared_select.h +++ b/include/sqlpp11/prepared_select.h @@ -46,7 +46,7 @@ namespace sqlpp return {db.run_prepared_select(*this), _dynamic_names}; } - void bind_params() const + void _bind_params() const { params._bind(_prepared_query); } diff --git a/include/sqlpp11/prepared_update.h b/include/sqlpp11/prepared_update.h new file mode 100644 index 00000000..aadb94ae --- /dev/null +++ b/include/sqlpp11/prepared_update.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_PREPARED_UPDATE_H +#define SQLPP_PREPARED_UPDATE_H + +#include +#include + +namespace sqlpp +{ + template + struct prepared_select_t + { + using _parameter_list_t = typename Update::_parameter_list_t; + using _prepared_query_t = typename Db::_prepared_query_t; + + auto run(Db& db) const + -> size_t + { + return db.run_prepared_insert(*this); + } + + void _bind_params() const + { + params._bind(_prepared_query); + } + + _parameter_list_t params; + mutable _prepared_query_t _prepared_query; + }; + +} + +#endif diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 7f549c69..bfab925b 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -577,7 +577,7 @@ namespace sqlpp return _expression_list._dynamic_expressions._dynamic_expression_names; } - static constexpr size_t get_no_of_parameters() + static constexpr size_t _get_static_no_of_parameters() { return _parameter_list_t::size::value; } @@ -594,7 +594,7 @@ namespace sqlpp { static_assert(not is_noop::value, "cannot run select without having selected anything"); static_assert(is_from_t::value, "cannot run select without a from()"); - static_assert(get_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead"); + static_assert(_get_static_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead"); // FIXME: Check for missing aliases (if references are used) // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. From 121f56549bea33c9884182a0b3f4f58f233ba98f Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 8 Jan 2014 22:14:16 +0100 Subject: [PATCH 25/26] Added prepared statement support to insert, update and remove (untested yet) --- include/sqlpp11/assignment_list.h | 9 ++++++++- include/sqlpp11/insert.h | 10 +++++----- include/sqlpp11/prepared_remove.h | 2 +- include/sqlpp11/prepared_update.h | 2 +- include/sqlpp11/remove.h | 32 +++++++++++++++++++++++++++--- include/sqlpp11/update.h | 33 ++++++++++++++++++++++++++++--- include/sqlpp11/using.h | 9 ++++++++- 7 files changed, 82 insertions(+), 15 deletions(-) diff --git a/include/sqlpp11/assignment_list.h b/include/sqlpp11/assignment_list.h index 3cf598fd..e55e8ab5 100644 --- a/include/sqlpp11/assignment_list.h +++ b/include/sqlpp11/assignment_list.h @@ -39,6 +39,7 @@ namespace sqlpp { using _is_assignment_list = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; // check for at least one order expression static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one assignment expression required in set()"); @@ -70,7 +71,13 @@ namespace sqlpp _dynamic_assignments.serialize(os, db, sizeof...(Assignments) == 0); } - std::tuple::type...> _assignments; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_assignments, index); + return index; + } + + _parameter_tuple_t _assignments; typename detail::serializable_list _dynamic_assignments; }; diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index 6dd0fc8e..a2b33d4b 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -111,11 +111,6 @@ namespace sqlpp return *this; } - static constexpr size_t _get_static_no_of_parameters() - { - return _parameter_list_t::size::value; - } - template insert_t& serialize(std::ostream& os, Db& db) { @@ -123,6 +118,11 @@ namespace sqlpp return *this; } + static constexpr size_t _get_static_no_of_parameters() + { + return _parameter_list_t::size::value; + } + template std::size_t run(Db& db) const { diff --git a/include/sqlpp11/prepared_remove.h b/include/sqlpp11/prepared_remove.h index 0dcd2b30..b8adcfbe 100644 --- a/include/sqlpp11/prepared_remove.h +++ b/include/sqlpp11/prepared_remove.h @@ -33,7 +33,7 @@ namespace sqlpp { template - struct prepared_select_t + struct prepared_remove_t { using _parameter_list_t = typename Remove::_parameter_list_t; using _prepared_query_t = typename Db::_prepared_query_t; diff --git a/include/sqlpp11/prepared_update.h b/include/sqlpp11/prepared_update.h index aadb94ae..35d13d95 100644 --- a/include/sqlpp11/prepared_update.h +++ b/include/sqlpp11/prepared_update.h @@ -33,7 +33,7 @@ namespace sqlpp { template - struct prepared_select_t + struct prepared_update_t { using _parameter_list_t = typename Update::_parameter_list_t; using _prepared_query_t = typename Db::_prepared_query_t; diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index e657f87a..856145c8 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -32,6 +32,8 @@ #include #include #include +#include +#include namespace sqlpp { @@ -60,6 +62,9 @@ namespace sqlpp template using set_where_t = remove_t; + using _parameter_tuple_t = std::tuple; + using _parameter_list_t = typename make_parameter_list_t::type; + template auto using_(Tab&&... tab) -> set_using_t::type...>> @@ -147,14 +152,35 @@ namespace sqlpp return *this; } + static constexpr size_t _get_static_no_of_parameters() + { + return _parameter_list_t::size::value; + } + template std::size_t run(Db& db) const { - std::ostringstream oss; - serialize(oss, db); - return db.remove(oss.str()); + static_assert(_get_static_no_of_parameters() == 0, "cannot run remove directly with parameters, use prepare instead"); + return db.remove(*this); } + template + auto prepare(Db& db) + -> prepared_remove_t::type, remove_t> + { + _set_parameter_index(0); + return {{}, db.prepare_remove(*this)}; + } + + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_table, index); + index = set_parameter_index(_using, index); + index = set_parameter_index(_where, index); + return index; + } + + Table _table; Using _using; Where _where; diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index 60cc9fec..3f245c11 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -32,6 +32,8 @@ #include #include #include +#include +#include namespace sqlpp { @@ -60,6 +62,9 @@ namespace sqlpp template using set_where_t = update_t; + using _parameter_tuple_t = std::tuple; + using _parameter_list_t = typename make_parameter_list_t::type; + template auto set(Assignment&&... assignment) -> set_assignments_t::type...>> @@ -147,14 +152,36 @@ namespace sqlpp return *this; } + static constexpr size_t _get_static_no_of_parameters() + { + return _parameter_list_t::size::value; + } + template std::size_t run(Db& db) const { - std::ostringstream oss; - serialize(oss, db); - return db.update(oss.str()); + static_assert(not is_noop::value, "calling set() required before running update"); + static_assert(_get_static_no_of_parameters() == 0, "cannot run update directly with parameters, use prepare instead"); + return db.update(*this); } + template + auto prepare(Db& db) + -> prepared_update_t::type, update_t> + { + static_assert(not is_noop::value, "calling set() required before running update"); + + _set_parameter_index(0); + return {{}, db.prepare_update(*this)}; + } + + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_table, index); + index = set_parameter_index(_assignments, index); + return index; + } + Table _table; Assignments _assignments; Where _where; diff --git a/include/sqlpp11/using.h b/include/sqlpp11/using.h index 9af96bd2..8bc7f3d1 100644 --- a/include/sqlpp11/using.h +++ b/include/sqlpp11/using.h @@ -40,6 +40,7 @@ namespace sqlpp { using _is_using = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; static_assert(_is_dynamic::value or sizeof...(Table), "at least one table argument required in using()"); @@ -68,7 +69,13 @@ namespace sqlpp _dynamic_tables.serialize(os, db, sizeof...(Table) == 0); } - std::tuple _tables; + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_tables, index); + return index; + } + + _parameter_tuple_t _tables; detail::serializable_list _dynamic_tables; }; From a68d6fb8283df1473b2451d628870b3e1bb6e487 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 9 Jan 2014 22:33:23 +0100 Subject: [PATCH 26/26] Prepared insert/update/delete now work with the mysql connector --- include/sqlpp11/insert.h | 5 +++++ include/sqlpp11/remove.h | 5 +++++ include/sqlpp11/select.h | 5 +++++ include/sqlpp11/update.h | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index a2b33d4b..a616fd0a 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -123,6 +123,11 @@ namespace sqlpp return _parameter_list_t::size::value; } + size_t _get_no_of_parameters() + { + return _parameter_list_t::size::value; // FIXME: Need to add dynamic parameters here + } + template std::size_t run(Db& db) const { diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index 856145c8..91b3ce2f 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -157,6 +157,11 @@ namespace sqlpp return _parameter_list_t::size::value; } + size_t _get_no_of_parameters() + { + return _parameter_list_t::size::value; // FIXME: Need to add dynamic parameters here + } + template std::size_t run(Db& db) const { diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index bfab925b..f384c6fe 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -582,6 +582,11 @@ namespace sqlpp return _parameter_list_t::size::value; } + size_t _get_no_of_parameters() + { + return _parameter_list_t::size::value; // FIXME: Need to add dynamic parameters here + } + size_t get_no_of_result_columns() const { return _result_row_t::static_size(); // FIXME: Need to add the size of dynamic columns diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index 3f245c11..ac21cfd4 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -157,6 +157,11 @@ namespace sqlpp return _parameter_list_t::size::value; } + size_t _get_no_of_parameters() + { + return _parameter_list_t::size::value; // FIXME: Need to add dynamic parameters here + } + template std::size_t run(Db& db) const {