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/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/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/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/boolean.h b/include/sqlpp11/boolean.h index 00ffbc3a..fa86f3c6 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -30,7 +30,6 @@ #include #include #include -#include #include namespace sqlpp @@ -50,12 +49,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 { @@ -63,30 +56,108 @@ 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_ + struct _parameter_t { using _value_type = boolean; - static constexpr const char* _name = "+"; - }; - 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)) + _parameter_t(const std::true_type&): + _trivial_value_is_null(true), + _value(false), + _is_null(_trivial_value_is_null and _is_trivial()) {} - _result_entry_t& operator=(const raw_result_row_t& row) + _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(_trivial_value_is_null and _is_trivial()) + {} + + _parameter_t& operator=(const _cpp_value_type& value) { - _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); + _value = value; + _is_null = (_trivial_value_is_null 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(); } + + 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; + bool _is_null; + }; + + struct _result_entry_t + { + _result_entry_t(): + _is_valid(false), + _is_null(true), + _value(false) + {} + + _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 = true; + _is_null = data == nullptr; + _value = _is_null ? false : (data[0] == 't' or data[0] == '1'); + } + + void validate() + { + _is_valid = true; + } + + void invalidate() + { + _is_valid = false; + _is_null = true; + _value = 0; + } + template void serialize(std::ostream& os, Db& db) const { @@ -102,19 +173,25 @@ 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(); } + + template + void bind(Target& target, size_t i) + { + target.bind_boolean_result(i, &_value, &_is_null); + } private: bool _is_valid; bool _is_null; - bool _value; + signed char _value; }; template @@ -145,8 +222,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/raw_result_row.h b/include/sqlpp11/char_result_row.h similarity index 88% rename from include/sqlpp11/raw_result_row.h rename to include/sqlpp11/char_result_row.h index 0baaf9ff..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 { - const char** data; - const size_t* len; + 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/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/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/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/expression.h b/include/sqlpp11/expression.h index 9a5b2288..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 { @@ -40,6 +41,14 @@ namespace sqlpp using _is_assignment = std::true_type; using column_type = Lhs; using value_type = Rhs; + using _parameter_tuple_t = std::tuple; + + size_t _set_parameter_index(size_t index) + { + index = set_parameter_index(_lhs, index); + index = set_parameter_index(_rhs, index); + return index; + } template void serialize(std::ostream& os, Db& db) const @@ -64,6 +73,13 @@ namespace sqlpp struct equal_t: public ValueType::template operators> { using _value_type = ValueType; + using _parameter_tuple_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): @@ -103,6 +119,13 @@ namespace sqlpp struct not_equal_t: public ValueType::template operators> { using _value_type = ValueType; + using _parameter_tuple_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): @@ -142,10 +165,15 @@ namespace sqlpp struct not_t: public ValueType::template operators> { using _value_type = ValueType; + using _parameter_tuple_t = std::tuple; - template - not_t(L&& l): - _lhs(std::forward(l)) + size_t _set_parameter_index(size_t index) + { + return set_parameter_index(_lhs, index); + } + + not_t(Lhs l): + _lhs(l) {} not_t(const not_t&) = default; @@ -179,6 +207,13 @@ namespace sqlpp struct binary_expression_t: public O::_value_type::template operators> { using _value_type = typename O::_value_type; + using _parameter_tuple_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)), diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 65215ac5..b5236ab3 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 @@ -46,25 +46,110 @@ 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 + struct _parameter_t { - using _value_type = floating_point; - _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::strtod(row.data[index], nullptr)) + using _value_type = integral; + + _parameter_t(const std::true_type&): + _trivial_value_is_null(true), + _value(0), + _is_null(_trivial_value_is_null and _is_trivial()) {} - _result_entry_t& operator=(const raw_result_row_t& row) + _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(_trivial_value_is_null and _is_trivial()) + {} + + _parameter_t& operator=(const _cpp_value_type& value) { - _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); + _value = value; + _is_null = (_trivial_value_is_null 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; + } + + const _cpp_value_type& value() 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; + }; + + struct _result_entry_t + { + using _value_type = integral; + + _result_entry_t(): + _is_valid(false), + _is_null(true), + _value(0) + {} + + _result_entry_t(const char* data, size_t): + _is_valid(true), + _is_null(data == nullptr), + _value(_is_null ? 0 : std::strtoll(data, nullptr, 10)) + {} + + void assign(const char* data, size_t) + { + _is_valid = true; + _is_null = data == nullptr; + _value = _is_null ? 0 : std::strtoll(data, nullptr, 10); + } + + void validate() + { + _is_valid = true; + } + + void invalidate() + { + _is_valid = false; + _is_null = true; + _value = 0; + } + template void serialize(std::ostream& os, Db& db) const { @@ -80,19 +165,25 @@ 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(); } + + template + void bind(Target& target, size_t i) + { + target.bind_floating_point_result(i, &_value, &_is_null); + } private: bool _is_valid; bool _is_null; - double _value; + _cpp_value_type _value; }; struct plus_ @@ -181,8 +272,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/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/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/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/having.h b/include/sqlpp11/having.h index 0547a969..fe9927e3 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) { @@ -65,7 +69,13 @@ namespace sqlpp _dynamic_expressions.serialize(os, db, " AND ", 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/insert.h b/include/sqlpp11/insert.h index 498e3dc1..a616fd0a 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...>> @@ -112,17 +118,46 @@ namespace sqlpp return *this; } + static constexpr size_t _get_static_no_of_parameters() + { + 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 { 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/integral.h b/include/sqlpp11/integral.h index cbf0b298..ac2e6b82 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -30,7 +30,6 @@ #include #include #include -#include #include namespace sqlpp @@ -46,23 +45,107 @@ 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 _parameter_t + { + using _value_type = integral; + + _parameter_t(const std::true_type&): + _trivial_value_is_null(true), + _value(0), + _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()) + {} + + explicit _parameter_t(const _cpp_value_type& value): + _value(value), + _is_null(_trivial_value_is_null and _is_trivial()) + {} + + _parameter_t& operator=(const _cpp_value_type& value) + { + _value = value; + _is_null = (_trivial_value_is_null and _is_trivial()); + return *this; + } + + void set_null() + { + _value = 0; + _is_null = true; + } + + 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; + } + + const _cpp_value_type& value() const + { + 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; + }; + struct _result_entry_t { using _value_type = integral; - _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(): + _is_valid(false), + _is_null(true), + _value(0) {} - _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 ? 0 : std::strtoll(data, nullptr, 10)) + {} + + 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; + } + + void validate() + { + _is_valid = true; } template @@ -80,19 +163,25 @@ 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(); } + + template + void bind(Target& target, size_t i) + { + target.bind_integral_result(i, &_value, &_is_null); + } private: bool _is_valid; bool _is_null; - int64_t _value; + _cpp_value_type _value; }; template @@ -184,8 +273,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/like.h b/include/sqlpp11/like.h index 51e7698c..1043d4d6 100644 --- a/include/sqlpp11/like.h +++ b/include/sqlpp11/like.h @@ -41,8 +41,9 @@ 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_tuple_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; }; @@ -73,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/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/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/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/parameter.h b/include/sqlpp11/parameter.h new file mode 100644 index 00000000..eaa8b72f --- /dev/null +++ b/include/sqlpp11/parameter.h @@ -0,0 +1,88 @@ +/* + * 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 _value_type = ValueType; + 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_t = 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 + { + 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; + } + + constexpr bool _is_trivial() const + { + return false; + } + + size_t _set_parameter_index(size_t index) + { + _index = index; + return index + 1; + } + + size_t _index; + }; + + template::type>> + auto parameter(NamedExpr&& namedExpr) + -> parameter_t::type::_value_type, typename std::decay::type, TrivialValueIsNull> + { + 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 new file mode 100644 index 00000000..c2bf0b68 --- /dev/null +++ b/include/sqlpp11/parameter_list.h @@ -0,0 +1,195 @@ +/* + * 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_LIST_H +#define SQLPP_PARAMETER_LIST_H + +#include +#include + +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 + { + static_assert(detail::wrong::value, "Template parameter for parameter_list_t has to be a tuple"); + }; + + template + struct parameter_list_t>: public Parameter::_instance_t... + { + 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_t()})... + {} + + template + void _bind(Target& target) const + { + _bind_impl(target, index_t<0>()); + } + + private: + template struct index_t {}; // this is just for overloading + + template + void _bind_impl(Target& target, const index_t&) const + { + const auto& parameter = static_cast::type&>(*this)(); + parameter.bind(target, index); + _bind_impl(target, index_t()); + } + + template + void _bind_impl(Target& target, const index_t&) const + { + } + }; + + 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; + }; + + } + + template + struct make_parameter_list_t + { + 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/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..b8adcfbe --- /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_remove_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 new file mode 100644 index 00000000..4654cc4e --- /dev/null +++ b/include/sqlpp11/prepared_select.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_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; + using _dynamic_names_t = typename Select::_dynamic_names_t; + using _prepared_query_t = typename Db::_prepared_query_t; + + auto run(Db& db) const + -> result_t + { + return {db.run_prepared_select(*this), _dynamic_names}; + } + + void _bind_params() const + { + params._bind(_prepared_query); + } + + _parameter_list_t params; + _dynamic_names_t _dynamic_names; + mutable _prepared_query_t _prepared_query; + }; + +} + +#endif diff --git a/include/sqlpp11/prepared_update.h b/include/sqlpp11/prepared_update.h new file mode 100644 index 00000000..35d13d95 --- /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_update_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/remove.h b/include/sqlpp11/remove.h index e657f87a..91b3ce2f 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,40 @@ namespace sqlpp return *this; } + static constexpr size_t _get_static_no_of_parameters() + { + 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 { - 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/result.h b/include/sqlpp11/result.h index 3acf6de4..f27f3937 100644 --- a/include/sqlpp11/result.h +++ b/include/sqlpp11/result.h @@ -27,38 +27,31 @@ #ifndef SQLPP_RESULT_H #define SQLPP_RESULT_H -#include - #include namespace sqlpp { - template + template class result_t { - using db_result_t = typename Db::_result_t; + using db_result_t = DbResult; + using result_row_t = ResultRow; 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; + result_row_t _result_row; + db_result_t _end; + result_row_t _end_row; public: - result_t(): - _raw_result_row({}), - _end({}), - _dynamic_columns(), - _result_row(_raw_result_row, _dynamic_columns) - {} + result_t() = default; - result_t(db_result_t&& result, DynamicNames dynamic_columns): + template + result_t(db_result_t&& result, const DynamicNames& dynamic_names): _result(std::move(result)), - _raw_result_row(_result.next()), - _end({}), - _dynamic_columns(dynamic_columns), - _result_row(_raw_result_row, _dynamic_columns) - {} + _result_row(dynamic_names) + { + _result.next(_result_row); + } result_t(const result_t&) = delete; result_t(result_t&&) = default; @@ -69,26 +62,25 @@ namespace sqlpp class iterator { public: - iterator(result_t& result, raw_result_row_t& raw_result_row): + iterator(db_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(); + return _result_row; } - const ResultRow* operator->() const + const result_row_t* operator->() const { - return &_result.front(); + return &_result_row; } 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 @@ -98,37 +90,36 @@ namespace sqlpp void operator++() { - _result.pop_front(); + _result.next(_result_row); } - result_t& _result; - raw_result_row_t& _raw_result_row; + db_result_t& _result; + result_row_t& _result_row; }; iterator begin() { - return iterator(*this, _raw_result_row); + return iterator(_result, _result_row); } iterator end() { - return iterator(*this, _end); + return iterator(_end, _end_row); } - 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_row; } void pop_front() { - _raw_result_row = _result.next(); - _result_row = _raw_result_row; + _result.next(_result_row); } }; diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 827dad68..32518e12 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 @@ -37,64 +37,123 @@ namespace sqlpp { namespace detail { + template struct index_t {}; // this is just for overloading + template struct result_row_impl; 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(const raw_result_row_t& raw_result_row): - _field({raw_result_row}), - _rest(raw_result_row) - {} - - result_row_impl& operator=(const raw_result_row_t& raw_result_row) + result_row_impl() = default; + 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) { - _field::operator=({raw_result_row}); - _rest::operator=(raw_result_row); + } + + result_row_impl& operator=(const char_result_row_t& char_result_row_t) + { + _field::operator()().assign(char_result_row_t.data[index], char_result_row_t.len[index]); + _rest::operator=(char_result_row_t); return *this; } + + void validate() + { + _field::operator()().validate(); + _rest::validate(); + } + + void invalidate() + { + _field::operator()().invalidate(); + _rest::invalidate(); + } + + 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; - result_row_impl(const raw_result_row_t& raw_result_row): - _multi_field({raw_result_row}), - _rest(raw_result_row) + result_row_impl() = default; + 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; } + + void validate() + { + _multi_field::operator()().validate(); + _rest::validate(); + } + + void invalidate() + { + _multi_field::operator()().invalidate(); + _rest::invalidate(); + } + + template + void _bind(const Target& target) + { + _multi_field::_bind(target); + _rest::_bind(target); + } }; template struct result_row_impl { static constexpr size_t _last_index = index; - result_row_impl(const raw_result_row_t& raw_result_row) - {} + result_row_impl() = default; + 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; } + + void validate() + { + } + + void invalidate() + { + } + + template + void _bind(Target& target) + { + } }; } @@ -102,93 +161,130 @@ 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; + bool _is_valid; + static constexpr size_t _last_static_index = _impl::_last_index; - 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) + result_row_t(): + _impl(), + _is_valid(false) { } - result_row_t& operator=(const raw_result_row_t& raw_result_row) + template + result_row_t(const DynamicNames&): + _impl(), + _is_valid(false) { - _impl::operator=(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 char_result_row_t& char_result_row_t) + { + _impl::operator=(char_result_row_t); + _is_valid = true; return *this; } + void validate() + { + _impl::validate(); + _is_valid = true; + } + + void invalidate() + { + _impl::invalidate(); + _is_valid = false; + } + + bool operator==(const result_row_t& rhs) const + { + return _is_valid == rhs._is_valid; + } + explicit operator bool() const { - return _is_row; + return _is_valid; } + + static constexpr size_t static_size() + { + return _last_static_index; + } + + template + void bind_result(Target& target) + { + _impl::_bind(target); + } }; template 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; - bool _is_row; + bool _is_valid; std::vector _dynamic_columns; std::map _dynamic_fields; - 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), - _is_row(raw_result_row.data != nullptr) + dynamic_result_row_t(): + _impl(), + _is_valid(false) { - 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.insert(std::make_pair(column, _field_type(dynamic_row))); - ++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& operator=(const raw_result_row_t& raw_result_row) + dynamic_result_row_t(const std::vector& dynamic_columns): + _impl(), + _is_valid(false), + _dynamic_columns(dynamic_columns) { - detail::result_row_impl<0, 0, NamedExpr...>::operator=(raw_result_row); - _is_row = raw_result_row.data != nullptr; + } - 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_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 char_result_row_t& char_result_row) + { + _impl::operator=(char_result_row); + _is_valid = true; + + char_result_row_t dynamic_row = char_result_row; + + dynamic_row.data += _last_static_index; + dynamic_row.len += _last_static_index; + for (const auto& column : _dynamic_columns) + { + _dynamic_fields[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 _is_valid == rhs._is_valid; + } + const _field_type& at(const std::string& field_name) const { return _dynamic_fields.at(field_name); @@ -196,7 +292,7 @@ namespace sqlpp explicit operator bool() const { - return _is_row; + return _is_valid; } }; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 82fb0869..f384c6fe 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include @@ -109,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< @@ -135,7 +139,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,7 +154,7 @@ namespace sqlpp { } - 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), @@ -436,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 @@ -481,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"); @@ -566,20 +572,66 @@ namespace sqlpp return *this; } + const typename ExpressionList::_dynamic_names_t& get_dynamic_names() const + { + return _expression_list._dynamic_expressions._dynamic_expression_names; + } + + static constexpr size_t _get_static_no_of_parameters() + { + 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 + } + // 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(_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. + + return {db.select(*this), get_dynamic_names()}; + } + + // Prepare + template + 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. - std::ostringstream oss; - serialize(oss, db); - return {db.select(oss.str()), _expression_list._dynamic_expressions._dynamic_expression_names}; + _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; + } + Flags _flags; ExpressionList _expression_list; From _from; 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< 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; } }; }; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 8ba3d6b7..f003c115 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -46,21 +45,40 @@ 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 + struct _parameter_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 ? "" : std::string(row.data[index], row.data[index] + row.len[index])) + using _value_type = integral; + + _parameter_t(const std::true_type&): + _trivial_value_is_null(true), + _value(""), + _is_null(_trivial_value_is_null and _is_trivial()) {} - _result_entry_t& operator=(const raw_result_row_t& row) + _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(_trivial_value_is_null and _is_trivial()) + {} + + _parameter_t& operator=(const _cpp_value_type& value) { - _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 = value; + _is_null = (_trivial_value_is_null and _is_trivial()); + return *this; + } + + _parameter_t& operator=(const std::nullptr_t&) + { + _value = ""; + _is_null = true; return *this; } @@ -70,31 +88,105 @@ namespace sqlpp os << value(); } - bool _is_trivial() const { return value().empty(); } + bool _is_trivial() const { return value() == ""; } - bool operator==(const std::string& rhs) const { return value() == rhs; } - bool operator!=(const std::string& rhs) const { return not operator==(rhs); } + bool is_null() const + { + return _is_null; + } + + _cpp_value_type value() const + { + return _value; + } + + 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; + bool _is_null; + }; + + struct _result_entry_t + { + _result_entry_t(): + _is_valid(false), + _value_ptr(nullptr), + _len(0) + {} + + _result_entry_t(char* data, size_t len): + _is_valid(true), + _value_ptr(data), + _len(_value_ptr ? 0 : len) + {} + + void assign(char* data, size_t len) + { + _is_valid = true; + _value_ptr = data; + _len = _value_ptr ? 0 : len; + } + + void validate() + { + _is_valid = true; + } + + void invalidate() + { + _is_valid = false; + _value_ptr = nullptr; + _len = 0; + } + + template + void serialize(std::ostream& os, Db& db) const + { + os << value(); + } + + 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); } bool is_null() const { if (not _is_valid) throw exception("accessing is_null in non-existing row"); - return _is_null; + return _value_ptr == nullptr; } - std::string value() const + _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 std::string() const { return value(); } + 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; - std::string _value; + char* _value_ptr; + size_t _len; }; template @@ -120,8 +212,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(); } diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index ef495acf..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\ @@ -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/include/sqlpp11/update.h b/include/sqlpp11/update.h index 60cc9fec..ac21cfd4 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,41 @@ namespace sqlpp return *this; } + static constexpr size_t _get_static_no_of_parameters() + { + 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 { - 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; }; diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 56d517a3..782f1ac4 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) { @@ -64,7 +69,13 @@ namespace sqlpp _dynamic_expressions.serialize(os, db, " AND ", 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/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/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 new file mode 100644 index 00000000..627bcf3a --- /dev/null +++ b/tests/PreparedTest.cpp @@ -0,0 +1,108 @@ +/* + * 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 + +#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"); + } + + // OK, fine, now create a named parameter list from an expression + { + 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"); + } + + // Wonderful, now take a look at the parameter list of a select + { + 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; + + 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; + std::cerr << x.alpha << std::endl; + x = decltype(npl)(); + std::cerr << x.alpha << std::endl; + } + + + return 0; +} 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"); } { diff --git a/tests/TabSample.h b/tests/TabSample.h index 903bf62d..4c1de4d3 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; @@ -83,6 +87,8 @@ struct TabFoo: sqlpp::table_base_t< struct _member_t { T tabFoo; + T& operator()() { return tabFoo; } + const T& operator()() const { return tabFoo; } }; template void serialize_impl(std::ostream& os, Db& db) const @@ -102,6 +108,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 +132,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 +154,8 @@ namespace TabSample_ struct _member_t { T gamma; + T& operator()() { return gamma; } + const T& operator()() const { return gamma; } }; }; using _value_type = sqlpp::boolean; @@ -169,6 +181,8 @@ struct TabSample: sqlpp::table_base_t< struct _member_t { T tabSample; + T& operator()() { return tabSample; } + const T& operator()() const { return tabSample; } }; }; template