0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

Merge branch 'feature/prepared_statements' into develop

This commit is contained in:
rbock 2014-01-10 08:18:52 +01:00
commit 46b4ac349e
48 changed files with 1645 additions and 278 deletions

View File

@ -41,13 +41,9 @@ namespace sqlpp
template<typename T>\
struct _member_t\
{\
template<typename... TT>\
_member_t(TT&&... t): name(std::forward<TT>(t)...) {}\
\
template<typename TT>\
_member_t& operator=(TT&& t) { name = std::forward<TT>(t); return *this; }\
\
T name;\
T& operator()() { return name; }\
const T& operator()() const { return name; }\
};\
};\
};\

View File

@ -52,6 +52,8 @@ namespace sqlpp
struct _member_t
{
T any;
T& operator()() { return any; }
const T& operator()() const { return any; }
};
};

View File

@ -39,6 +39,7 @@ namespace sqlpp
{
using _is_assignment_list = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Assignments...>;
// 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<typename std::decay<Assignments>::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<Database> _dynamic_assignments;
};

View File

@ -51,6 +51,8 @@ namespace sqlpp
struct _member_t
{
T avg;
T& operator()() { return avg; }
const T& operator()() const { return avg; }
};
};

View File

@ -30,7 +30,6 @@
#include <cstdlib>
#include <sqlpp11/detail/basic_operators.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/raw_result_row.h>
#include <sqlpp11/exception.h>
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<size_t index>
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<typename Db>
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<typename Target>
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<typename Db>
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<typename Target>
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<typename T>
@ -145,8 +222,7 @@ namespace sqlpp
};
};
template<size_t index>
std::ostream& operator<<(std::ostream& os, const boolean::_result_entry_t<index>& e)
inline std::ostream& operator<<(std::ostream& os, const boolean::_result_entry_t& e)
{
return os << e.value();
}

View File

@ -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;
}

View File

@ -51,6 +51,8 @@ namespace sqlpp
struct _member_t
{
T count;
T& operator()() { return count; }
const T& operator()() const { return count; }
};
};

View File

@ -30,6 +30,7 @@
#include <ostream>
#include <vector>
#include <memory>
#include <sqlpp11/parameter_list.h>
namespace sqlpp
{
@ -65,6 +66,7 @@ namespace sqlpp
template<typename T>
struct _impl_t: public _impl_base
{
static_assert(not make_parameter_list_t<T>::type::size::value, "parameters not supported in dynamic query parts");
_impl_t(const T& t):
_t(t)
{}

View File

@ -51,6 +51,8 @@ namespace sqlpp
struct _member_t
{
T exists;
T& operator()() { return exists; }
const T& operator()() const { return exists; }
};
};

View File

@ -31,6 +31,7 @@
#include <sqlpp11/detail/serialize_tuple.h>
#include <sqlpp11/alias.h>
#include <sqlpp11/noop.h>
#include <sqlpp11/parameter_list.h> // 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<Lhs, Rhs>;
size_t _set_parameter_index(size_t index)
{
index = set_parameter_index(_lhs, index);
index = set_parameter_index(_rhs, index);
return index;
}
template<typename Db>
void serialize(std::ostream& os, Db& db) const
@ -64,6 +73,13 @@ namespace sqlpp
struct equal_t: public ValueType::template operators<equal_t<Lhs, Rhs>>
{
using _value_type = ValueType;
using _parameter_tuple_t = std::tuple<Lhs, Rhs>;
size_t _set_parameter_index(size_t index)
{
index = set_parameter_index(_lhs, index);
return set_parameter_index(_rhs, index);
}
template<typename L, typename R>
equal_t(L&& l, R&& r):
@ -103,6 +119,13 @@ namespace sqlpp
struct not_equal_t: public ValueType::template operators<not_equal_t<Lhs, Rhs>>
{
using _value_type = ValueType;
using _parameter_tuple_t = std::tuple<Lhs, Rhs>;
size_t _set_parameter_index(size_t index)
{
index = set_parameter_index(_lhs, index);
return set_parameter_index(_rhs, index);
}
template<typename L, typename R>
not_equal_t(L&& l, R&& r):
@ -142,10 +165,15 @@ namespace sqlpp
struct not_t: public ValueType::template operators<not_t<Lhs>>
{
using _value_type = ValueType;
using _parameter_tuple_t = std::tuple<Lhs>;
template<typename L>
not_t(L&& l):
_lhs(std::forward<L>(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<binary_expression_t<Lhs, O, Rhs>>
{
using _value_type = typename O::_value_type;
using _parameter_tuple_t = std::tuple<Lhs, Rhs>;
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)),

View File

@ -30,7 +30,7 @@
#include <cstdlib>
#include <sqlpp11/detail/basic_operators.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/raw_result_row.h>
#include <sqlpp11/char_result_row.h> // FIXME: Need to update floating_point
#include <sqlpp11/exception.h>
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<size_t index>
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<typename Db>
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<typename Target>
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<typename Db>
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<typename Target>
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<size_t index>
std::ostream& operator<<(std::ostream& os, const floating_point::_result_entry_t<index>& e)
inline std::ostream& operator<<(std::ostream& os, const floating_point::_result_entry_t& e)
{
return os << e.value();
}

View File

@ -51,7 +51,7 @@ namespace sqlpp
using _valid_expressions = typename detail::make_set_if<is_table_t, TableOrJoin...>::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<typename Table>

View File

@ -28,6 +28,8 @@
#define SQLPP_FUNCTIONS_H
#include <sstream>
#include <sqlpp11/parameter.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/column_types.h>
#include <sqlpp11/exists.h>

View File

@ -43,6 +43,7 @@ namespace sqlpp
{
using _is_group_by = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Expr...>;
// 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<Expr...> _expressions;
size_t _set_parameter_index(size_t index)
{
index = set_parameter_index(_expressions, index);
return index;
}
_parameter_tuple_t _expressions;
detail::serializable_list<Database> _dynamic_expressions;
};

View File

@ -41,11 +41,15 @@ namespace sqlpp
{
using _is_having = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Expr...>;
static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in having()");
using _valid_expressions = typename detail::make_set_if<is_expression_t, Expr...>::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<typename E>
void add(E&& expr)
{
@ -65,7 +69,13 @@ namespace sqlpp
_dynamic_expressions.serialize(os, db, " AND ", sizeof...(Expr) == 0);
}
std::tuple<Expr...> _expressions;
size_t _set_parameter_index(size_t index)
{
index = set_parameter_index(_expressions, index);
return index;
}
_parameter_tuple_t _expressions;
detail::serializable_list<Database> _dynamic_expressions;
};

View File

@ -32,6 +32,9 @@
#include <sqlpp11/select_fwd.h>
#include <sqlpp11/insert_list.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_insert.h>
#include <sqlpp11/detail/serialize_tuple.h>
namespace sqlpp
@ -56,6 +59,9 @@ namespace sqlpp
template<typename AssignmentT>
using set_insert_list_t = insert_t<Database, Table, AssignmentT>;
using _parameter_tuple_t = std::tuple<Table, InsertList>;
using _parameter_list_t = typename make_parameter_list_t<insert_t>::type;
template<typename... Assignment>
auto set(Assignment&&... assignment)
-> set_insert_list_t<insert_list_t<void, must_not_insert_t, typename std::decay<Assignment>::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<typename Db>
std::size_t run(Db& db) const
{
constexpr bool calledSet = not is_noop<InsertList>::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<typename Db>
auto prepare(Db& db)
-> prepared_insert_t<typename std::decay<Db>::type, insert_t>
{
constexpr bool calledSet = not is_noop<InsertList>::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;
};

View File

@ -63,6 +63,7 @@ namespace sqlpp
{
using _is_insert_list = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<typename Assignments::value_type...>;
// 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<detail::insert_column<typename Assignments::column_type>...> _columns;
std::tuple<typename Assignments::value_type...> _values;
_parameter_tuple_t _values;
typename detail::serializable_list<Database> _dynamic_columns;
typename detail::serializable_list<Database> _dynamic_values;
};

View File

@ -30,7 +30,6 @@
#include <cstdlib>
#include <sqlpp11/detail/basic_operators.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/raw_result_row.h>
#include <sqlpp11/exception.h>
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<size_t index>
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<typename Db>
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<typename Target>
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<typename Db>
@ -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<typename Target>
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<typename T>
@ -184,8 +273,7 @@ namespace sqlpp
};
};
template<size_t index>
std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t<index>& e)
inline std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t& e)
{
return os << e.value();
}

View File

@ -41,8 +41,9 @@ namespace sqlpp
{
static_assert(is_text_t<Operand>::value, "Operand for like() has to be a text");
static_assert(is_text_t<Pattern>::value, "Pattern for like() has to be a text");
using _parameter_tuple_t = std::tuple<ValueType, Pattern>;
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<typename Db>
void serialize(std::ostream& os, Db& db) const
{

View File

@ -33,19 +33,29 @@
namespace sqlpp
{
struct limit_t
{
using _is_limit = std::true_type;
template<typename Limit>
struct limit_t
{
using _is_limit = std::true_type;
using _parameter_tuple_t = std::tuple<Limit>;
static_assert(std::is_integral<Limit>::value
or (is_parameter_t<Limit>::value and is_numeric_t<Limit>::value), "limit requires an integral value or integral parameter");
template<typename Db>
void serialize(std::ostream& os, Db& db) const
template<typename Db>
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
{

View File

@ -51,6 +51,8 @@ namespace sqlpp
struct _member_t
{
T max;
T& operator()() { return max; }
const T& operator()() const { return max; }
};
};

View File

@ -51,6 +51,8 @@ namespace sqlpp
struct _member_t
{
T min;
T& operator()() { return min; }
const T& operator()() const { return min; }
};
};

View File

@ -33,18 +33,29 @@
namespace sqlpp
{
struct offset_t
{
using _is_offset = std::true_type;
template<typename Offset>
struct offset_t
{
using _is_offset = std::true_type;
using _parameter_tuple_t = std::tuple<Offset>;
static_assert(std::is_integral<Offset>::value
or (is_parameter_t<Offset>::value and is_numeric_t<Offset>::value), "offset requires an integral value or integral parameter");
template<typename Db>
void serialize(std::ostream& os, Db& db) const
template<typename Db>
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
{

View File

@ -41,6 +41,7 @@ namespace sqlpp
{
using _is_order_by = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Expr...>;
// 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<Expr...> _expressions;
size_t _set_parameter_index(size_t index)
{
index = set_parameter_index(_expressions, index);
return index;
}
_parameter_tuple_t _expressions;
detail::serializable_list<Database> _dynamic_expressions;
};

View File

@ -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 <ostream>
#include <sqlpp11/select_fwd.h>
#include <sqlpp11/type_traits.h>
namespace sqlpp
{
template<typename ValueType, typename NameType, typename TrivialValueIsNull>
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<typename ValueType::_parameter_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<typename Db>
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<typename NamedExpr, typename TrivialValueIsNull = trivial_value_is_null_t<typename std::decay<NamedExpr>::type>>
auto parameter(NamedExpr&& namedExpr)
-> parameter_t<typename std::decay<NamedExpr>::type::_value_type, typename std::decay<NamedExpr>::type, TrivialValueIsNull>
{
return {};
}
template<typename NamedExpr>
auto where_parameter(NamedExpr&& namedExpr)
-> parameter_t<typename std::decay<NamedExpr>::type::_value_type, typename std::decay<NamedExpr>::type, std::false_type>
{
return {};
}
}
#endif

View File

@ -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 <sqlpp11/detail/wrong.h>
#include <tuple>
namespace sqlpp
{
namespace detail
{
template<typename... T>
struct or_t;
template<typename T, typename... Rest>
struct or_t<T, Rest...>
{
static constexpr bool value = T::value or or_t<Rest...>::value;
};
template<>
struct or_t<>
{
static constexpr bool value = false;
};
}
template<typename T>
struct parameter_list_t
{
static_assert(detail::wrong<T>::value, "Template parameter for parameter_list_t has to be a tuple");
};
template<typename... Parameter>
struct parameter_list_t<std::tuple<Parameter...>>: public Parameter::_instance_t...
{
using _member_tuple_t = std::tuple<typename Parameter::_instance_t...>;
using size = std::integral_constant<std::size_t, sizeof...(Parameter)>;
using _contains_trivial_value_is_null_t = detail::or_t<typename Parameter::_trivial_value_is_null_t...>;
parameter_list_t():
Parameter::_instance_t({typename Parameter::_trivial_value_is_null_t()})...
{}
template<typename Target>
void _bind(Target& target) const
{
_bind_impl(target, index_t<0>());
}
private:
template<size_t> struct index_t {}; // this is just for overloading
template<typename Target, size_t index>
void _bind_impl(Target& target, const index_t<index>&) const
{
const auto& parameter = static_cast<typename std::tuple_element<index, const _member_tuple_t>::type&>(*this)();
parameter.bind(target, index);
_bind_impl(target, index_t<index + 1>());
}
template<typename Target>
void _bind_impl(Target& target, const index_t<size::value>&) const
{
}
};
namespace detail
{
template<typename Exp, typename Enable = void>
struct get_parameter_tuple
{
using type = std::tuple<>;
};
template<typename Exp>
struct get_parameter_tuple<Exp, typename std::enable_if<is_parameter_t<Exp>::value, void>::type>
{
using type = std::tuple<Exp>;
};
template<typename... Param>
struct get_parameter_tuple<std::tuple<Param...>, void>
{
// cat together parameter tuples
using type = decltype(std::tuple_cat(std::declval<typename get_parameter_tuple<Param>::type>()...));
};
template<typename Exp>
struct get_parameter_tuple<Exp, typename std::enable_if<not std::is_same<typename Exp::_parameter_tuple_t, void>::value, void>::type>
{
using type = typename get_parameter_tuple<typename Exp::_parameter_tuple_t>::type;
};
}
template<typename Exp>
struct make_parameter_list_t
{
using type = parameter_list_t<typename detail::get_parameter_tuple<typename std::decay<Exp>::type>::type>;
};
template<typename T>
size_t set_parameter_index(T& t, size_t index);
namespace detail
{
template<typename Exp, typename Enable = void>
struct set_parameter_index_t
{
size_t operator()(Exp& e, size_t index)
{
return index;
}
};
template<typename Exp>
struct set_parameter_index_t<Exp, typename std::enable_if<is_parameter_t<Exp>::value, void>::type>
{
size_t operator()(Exp& e, size_t index)
{
return e._set_parameter_index(index);
}
};
template<typename... Param>
struct set_parameter_index_t<std::tuple<Param...>, void>
{
template<size_t> struct type{};
size_t operator()(std::tuple<Param...>& t, size_t index)
{
return impl(t, index, type<0>());
}
private:
template<size_t pos>
size_t impl(std::tuple<Param...>& t, size_t index, const type<pos>&)
{
index = sqlpp::set_parameter_index(std::get<pos>(t), index);
return impl(t, index, type<pos + 1>());
}
size_t impl(std::tuple<Param...>& t, size_t index, const type<sizeof...(Param)>&)
{
return index;
}
};
template<typename Exp>
struct set_parameter_index_t<Exp, typename std::enable_if<not std::is_same<typename Exp::_parameter_tuple_t, void>::value, void>::type>
{
size_t operator()(Exp& e, size_t index)
{
return e._set_parameter_index(index);
}
};
}
template<typename T>
size_t set_parameter_index(T& t, size_t index)
{
return detail::set_parameter_index_t<T>()(t, index);
}
}
#endif

View File

@ -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 <sqlpp11/parameter_list.h>
#include <sqlpp11/result.h>
namespace sqlpp
{
template<typename Db, typename Insert>
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

View File

@ -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 <sqlpp11/parameter_list.h>
#include <sqlpp11/result.h>
namespace sqlpp
{
template<typename Db, typename Remove>
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

View File

@ -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 <sqlpp11/parameter_list.h>
#include <sqlpp11/result.h>
namespace sqlpp
{
template<typename Db, typename Select>
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<decltype(db.run_prepared_select(*this)), _result_row_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

View File

@ -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 <sqlpp11/parameter_list.h>
#include <sqlpp11/result.h>
namespace sqlpp
{
template<typename Db, typename Update>
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

View File

@ -32,6 +32,8 @@
#include <sqlpp11/using.h>
#include <sqlpp11/where.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_remove.h>
namespace sqlpp
{
@ -60,6 +62,9 @@ namespace sqlpp
template<typename WhereT>
using set_where_t = remove_t<Database, Table, Using, WhereT>;
using _parameter_tuple_t = std::tuple<Table, Using, Where>;
using _parameter_list_t = typename make_parameter_list_t<remove_t>::type;
template<typename... Tab>
auto using_(Tab&&... tab)
-> set_using_t<using_t<void, typename std::decay<Tab>::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<typename Db>
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<typename Db>
auto prepare(Db& db)
-> prepared_remove_t<typename std::decay<Db>::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;

View File

@ -27,38 +27,31 @@
#ifndef SQLPP_RESULT_H
#define SQLPP_RESULT_H
#include <sqlpp11/raw_result_row.h>
#include <iostream>
namespace sqlpp
{
template<typename Db, typename ResultRow, typename DynamicNames>
template<typename DbResult, typename ResultRow>
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<typename DynamicNames>
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);
}
};

View File

@ -27,7 +27,7 @@
#ifndef SQLPP_RESULT_ROW_H
#define SQLPP_RESULT_ROW_H
#include <sqlpp11/raw_result_row.h>
#include <sqlpp11/char_result_row.h>
#include <sqlpp11/field.h>
#include <sqlpp11/text.h>
#include <iostream>
@ -37,64 +37,123 @@ namespace sqlpp
{
namespace detail
{
template<size_t> struct index_t {}; // this is just for overloading
template<size_t level, size_t index, typename... NamedExpr>
struct result_row_impl;
template<size_t level, size_t index, typename NamedExpr, typename... Rest>
struct result_row_impl<level, index, NamedExpr, Rest...>:
public NamedExpr::_name_t::template _member_t<typename NamedExpr::_value_type::template _result_entry_t<index>>,
public NamedExpr::_name_t::template _member_t<typename NamedExpr::_value_type::_result_entry_t>,
public result_row_impl<level, index + 1, Rest...>
{
using _field = typename NamedExpr::_name_t::template _member_t<typename NamedExpr::_value_type::template _result_entry_t<index>>;
using _field = typename NamedExpr::_name_t::template _member_t<typename NamedExpr::_value_type::_result_entry_t>;
using _rest = result_row_impl<level, index + 1, Rest...>;
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<typename Target>
void _bind(Target& target)
{
_field::operator()().bind(target, index);
std::cerr << "binding result " << index << std::endl;
_rest::_bind(target);
}
};
template<size_t level, size_t index, typename AliasProvider, typename... Col, typename... Rest>
struct result_row_impl<level, index, multi_field_t<AliasProvider, std::tuple<Col...>>, Rest...>:
public AliasProvider::_name_t::template _member_t<result_row_impl<level + 1, index, Col...>>, // level prevents identical closures to be present twice in the inheritance tree
public AliasProvider::_name_t::template _member_t<result_row_impl<level, index, Col...>>, // level prevents identical closures to be present twice in the inheritance tree
public result_row_impl<level, index + sizeof...(Col), Rest...>
{
using _multi_field = typename AliasProvider::_name_t::template _member_t<result_row_impl<level + 1, index, Col...>>;
using _multi_field = typename AliasProvider::_name_t::template _member_t<result_row_impl<level, index, Col...>>;
using _rest = result_row_impl<level, index + sizeof...(Col), Rest...>;
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<typename Target>
void _bind(const Target& target)
{
_multi_field::_bind(target);
_rest::_bind(target);
}
};
template<size_t level, size_t index>
struct result_row_impl<level, index>
{
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<typename Target>
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<typename T>
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<typename DynamicNames>
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<typename Target>
void bind_result(Target& target)
{
_impl::_bind(target);
}
};
template<typename... NamedExpr>
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<std::string> _dynamic_columns;
std::map<std::string, _field_type> _dynamic_fields;
dynamic_result_row_t(const raw_result_row_t& raw_result_row, std::vector<std::string> 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<std::string>& 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;
}
};

View File

@ -40,6 +40,8 @@
#include <sqlpp11/limit.h>
#include <sqlpp11/offset.h>
#include <sqlpp11/expression.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_select.h>
#include <sqlpp11/detail/wrong.h>
#include <sqlpp11/detail/make_flag_tuple.h>
@ -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<ExpressionList, Where, GroupBy, Having, OrderBy, Limit, Offset>;
using _parameter_list_t = typename make_parameter_list_t<select_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<limit_t>
{
static_assert(not is_noop<From>::value, "cannot call limit() without a from()");
static_assert(is_noop<Limit>::value, "cannot call limit() twice for a single select");
return {
template<typename Expr>
auto limit(Expr limit)
-> set_limit_t<limit_t<typename std::decay<Expr>::type>>
{
static_assert(not is_noop<From>::value, "cannot call limit() without a from()");
static_assert(is_noop<Limit>::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<dynamic_limit_t>
@ -481,8 +486,9 @@ namespace sqlpp
return *this;
}
auto offset(std::size_t offset)
-> set_offset_t<offset_t>
template<typename Expr>
auto offset(Expr offset)
-> set_offset_t<offset_t<typename std::decay<Expr>::type>>
{
static_assert(not is_noop<Limit>::value, "cannot call offset() without a limit");
static_assert(is_noop<Offset>::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<typename Db>
result_t<Db, _result_row_t, _dynamic_names_t> run(Db& db) const
auto run(Db& db) const
-> result_t<decltype(db.select(*this)), _result_row_t>
{
static_assert(not is_noop<ExpressionList>::value, "cannot run select without having selected anything");
static_assert(is_from_t<From>::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<typename Db>
auto prepare(Db& db)
-> prepared_select_t<typename std::decay<Db>::type, select_t>
{
static_assert(not is_noop<ExpressionList>::value, "cannot run select without having selected anything");
static_assert(is_from_t<From>::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;

View File

@ -107,6 +107,7 @@ namespace sqlpp
{
using _is_select_expression_list = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<NamedExpr...>;
// check for duplicate select expressions
static_assert(not detail::has_duplicates<NamedExpr...>::value, "at least one duplicate argument detected");
@ -160,7 +161,13 @@ namespace sqlpp
_dynamic_expressions.serialize(os, db, sizeof...(NamedExpr) == 0);
}
std::tuple<NamedExpr...> _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<Database> _dynamic_expressions;
};

View File

@ -50,8 +50,10 @@ namespace sqlpp
template<typename Database, typename... Expr> struct order_by_t;
template<typename Limit>
struct limit_t;
template<typename Offset>
struct offset_t;
template<

View File

@ -52,6 +52,8 @@ namespace sqlpp
struct _member_t
{
T some;
T& operator()() { return some; }
const T& operator()() const { return some; }
};
};

View File

@ -51,6 +51,8 @@ namespace sqlpp
struct _member_t
{
T sum;
T& operator()() { return sum; }
const T& operator()() const { return sum; }
};
};

View File

@ -30,7 +30,6 @@
#include <cstdlib>
#include <sqlpp11/detail/basic_operators.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/raw_result_row.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/concat.h>
#include <sqlpp11/like.h>
@ -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<size_t index>
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<typename Target>
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<typename Db>
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<typename Target>
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<typename T>
@ -120,8 +212,7 @@ namespace sqlpp
};
};
template<size_t index>
std::ostream& operator<<(std::ostream& os, const text::_result_entry_t<index>& e)
inline std::ostream& operator<<(std::ostream& os, const text::_result_entry_t& e)
{
return os << e.value();
}

View File

@ -47,12 +47,12 @@ namespace sqlpp
namespace detail\
{\
template<typename T, typename Enable = void>\
struct name##_impl: std::false_type {};\
struct name##_impl { using type = std::false_type; };\
template<typename T>\
struct name##_impl<T, typename std::enable_if<std::is_same<typename T::_column_type::_##name, std::true_type>::value>::type>: std::true_type {};\
struct name##_impl<T, typename std::enable_if<std::is_same<typename T::_column_type::_##name, std::true_type>::value>::type> { using type = std::true_type; };\
}\
template<typename T>\
struct name##_t: detail::name##_impl<T> {};
using name##_t = typename detail::name##_impl<T>::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);

View File

@ -32,6 +32,8 @@
#include <sqlpp11/assignment_list.h>
#include <sqlpp11/where.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/prepared_update.h>
namespace sqlpp
{
@ -60,6 +62,9 @@ namespace sqlpp
template<typename WhereT>
using set_where_t = update_t<Database, Table, Assignments, WhereT>;
using _parameter_tuple_t = std::tuple<Table, Assignments, Where>;
using _parameter_list_t = typename make_parameter_list_t<update_t>::type;
template<typename... Assignment>
auto set(Assignment&&... assignment)
-> set_assignments_t<assignment_list_t<void, must_not_update_t, typename std::decay<Assignment>::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<typename Db>
std::size_t run(Db& db) const
{
std::ostringstream oss;
serialize(oss, db);
return db.update(oss.str());
static_assert(not is_noop<Assignments>::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<typename Db>
auto prepare(Db& db)
-> prepared_update_t<typename std::decay<Db>::type, update_t>
{
static_assert(not is_noop<Assignments>::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;

View File

@ -40,6 +40,7 @@ namespace sqlpp
{
using _is_using = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Table...>;
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<Table...> _tables;
size_t _set_parameter_index(size_t index)
{
index = set_parameter_index(_tables, index);
return index;
}
_parameter_tuple_t _tables;
detail::serializable_list<Database> _dynamic_tables;
};

View File

@ -34,6 +34,7 @@
#include <sqlpp11/detail/set.h>
#include <sqlpp11/detail/serialize_tuple.h>
#include <sqlpp11/detail/serializable_list.h>
#include <sqlpp11/parameter_list.h>
namespace sqlpp
{
@ -42,11 +43,15 @@ namespace sqlpp
{
using _is_where = std::true_type;
using _is_dynamic = typename std::conditional<std::is_same<Database, void>::value, std::false_type, std::true_type>::type;
using _parameter_tuple_t = std::tuple<Expr...>;
static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in where()");
using _valid_expressions = typename detail::make_set_if<is_expression_t, Expr...>::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<typename E>
void add(E&& expr)
{
@ -64,7 +69,13 @@ namespace sqlpp
_dynamic_expressions.serialize(os, db, " AND ", sizeof...(Expr) == 0);
}
std::tuple<Expr...> _expressions;
size_t _set_parameter_index(size_t index)
{
index = set_parameter_index(_expressions, index);
return index;
}
_parameter_tuple_t _expressions;
detail::serializable_list<Database> _dynamic_expressions;
};
}

View File

@ -8,4 +8,5 @@ build_and_run(RemoveTest)
build_and_run(UpdateTest)
build_and_run(SelectTest)
build_and_run(FunctionTest)
build_and_run(PreparedTest)

View File

@ -32,6 +32,7 @@
#include <iostream>
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<T>::value, "type requirement");
static_assert(not sqlpp::is_expression_t<T>::value, "type requirement");

108
tests/PreparedTest.cpp Normal file
View File

@ -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 <sqlpp11/functions.h>
#include <sqlpp11/select.h>
#include <iostream>
DbMock db = {};
int main()
{
TabSample t;
TabFoo f;
// empty parameter lists
{
using T = typename sqlpp::detail::get_parameter_tuple<decltype(t.alpha)>::type;
static_assert(std::is_same<T, std::tuple<>>::value, "type requirement");
}
// single parameter
{
using T = typename sqlpp::detail::get_parameter_tuple<decltype(parameter(t.alpha))>::type;
static_assert(std::is_same<T, std::tuple<decltype(parameter(t.alpha))>>::value, "type requirement");
}
// single parameter
{
using T = typename sqlpp::detail::get_parameter_tuple<decltype(parameter(t.alpha))>::type;
static_assert(std::is_same<T, std::tuple<decltype(parameter(t.alpha))>>::value, "type requirement");
}
// single parameter in expression
{
using T = typename sqlpp::detail::get_parameter_tuple<decltype(t.alpha == parameter(t.alpha))>::type;
static_assert(std::is_same<T, std::tuple<decltype(parameter(t.alpha))>>::value, "type requirement");
}
// single parameter in larger expression
{
using T = typename sqlpp::detail::get_parameter_tuple<decltype(t.beta.like("%") and t.alpha == parameter(t.alpha) or t.gamma != false)>::type;
static_assert(std::is_same<T, std::tuple<decltype(parameter(t.alpha))>>::value, "type requirement");
}
// three parameters in expression
{
using T = typename sqlpp::detail::get_parameter_tuple<decltype(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma))>::type;
static_assert(std::tuple_size<T>::value == 3, "type requirement");
static_assert(std::is_same<T, std::tuple<decltype(parameter(t.beta)), decltype(parameter(t.alpha)),decltype(parameter(t.gamma))>>::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<Exp>::type;
T npl;
static_assert(std::is_same<typename decltype(t.alpha)::_value_type::_parameter_t, decltype(npl.alpha)>::value, "type requirement");
static_assert(std::is_same<typename decltype(t.beta)::_value_type::_parameter_t, decltype(npl.beta)>::value, "type requirement");
static_assert(std::is_same<typename decltype(t.gamma)::_value_type::_parameter_t, decltype(npl.gamma)>::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<S>::type;
T npl;
static_assert(std::is_same<typename decltype(t.alpha)::_value_type::_parameter_t, decltype(npl.alpha)>::value, "type requirement");
static_assert(std::is_same<typename decltype(t.beta)::_value_type::_parameter_t, decltype(npl.beta)>::value, "type requirement");
static_assert(std::is_same<typename decltype(t.gamma)::_value_type::_parameter_t, decltype(npl.gamma)>::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;
}

View File

@ -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<A, B>::value, "select with identical columns(name/value_type) need to have identical result_types");
static_assert(sqlpp::is_regular<A>::value, "type requirement");
static_assert(sqlpp::is_regular<B>::value, "type requirement");
}
{

View File

@ -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<typename Db>
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<typename Db>