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

Merge branch 'release/0.20'

This commit is contained in:
rbock 2014-08-08 10:04:07 +02:00
commit b48014d1dc
43 changed files with 1529 additions and 969 deletions

View File

@ -37,6 +37,7 @@ set(include_dir "${PROJECT_SOURCE_DIR}/include")
file(GLOB_RECURSE sqlpp_headers ${include_dir}/*.h)
include_directories(${include_dir})
add_subdirectory(tests)
add_subdirectory(test_constraints)
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/sqlpp11" DESTINATION include)

View File

@ -58,7 +58,7 @@ namespace sqlpp
static Context& _(const T& t, const Context&)
{
static_assert(wrong_t<T>::value, "all_of(table) does not seem to be used in select");
static_assert(wrong_t<serializer_t>::value, "all_of(table) does not seem to be used in select");
}
};

View File

@ -31,6 +31,7 @@
#include <sqlpp11/null.h>
#include <sqlpp11/tvin.h>
#include <sqlpp11/rhs_is_null.h>
#include <sqlpp11/rhs_is_trivial.h>
#include <sqlpp11/serialize.h>
#include <sqlpp11/serializer.h>
#include <sqlpp11/simple_column.h>
@ -70,9 +71,8 @@ namespace sqlpp
static Context& _(const T& t, Context& context)
{
if (((trivial_value_is_null_t<typename T::_lhs_t>::value or is_tvin_t<typename T::_rhs_t>::value)
and is_trivial(t._rhs))
or (std::is_same<Rhs, null_t>::value))
if ((trivial_value_is_null_t<typename T::_lhs_t>::value and rhs_is_trivial(t))
or rhs_is_null(t))
{
serialize(simple_column(t._lhs), context);
context << "=NULL";

View File

@ -32,215 +32,185 @@
#include <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/result_field.h>
namespace sqlpp
{
// boolean operators
namespace detail
// boolean value type
struct boolean
{
// boolean value type
struct boolean
using _traits = make_traits<boolean, ::sqlpp::tag::is_boolean, ::sqlpp::tag::is_value_type>;
using _tag = ::sqlpp::tag::is_boolean;
using _cpp_value_type = bool;
struct _parameter_t
{
using _traits = make_traits<boolean, ::sqlpp::tag::is_boolean, ::sqlpp::tag::is_expression>;
using _tag = ::sqlpp::tag::is_boolean;
using _cpp_value_type = bool;
using _value_type = boolean; // FIXME
struct _parameter_t
_parameter_t():
_value(false),
_is_null(true)
{}
_parameter_t(const _cpp_value_type& value):
_value(value),
_is_null(false)
{}
_parameter_t& operator=(const _cpp_value_type& value)
{
using _value_type = boolean; // FIXME
_value = value;
_is_null = (false);
return *this;
}
_parameter_t():
_value(false),
_is_null(true)
{}
_parameter_t(const _cpp_value_type& value):
_value(value),
_is_null(false)
{}
_parameter_t& operator=(const _cpp_value_type& value)
{
_value = value;
_is_null = (false);
return *this;
}
_parameter_t& operator=(const std::nullptr_t&)
{
_value = false;
_is_null = true;
return *this;
}
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:
signed char _value;
bool _is_null;
};
template<typename Db, typename FieldSpec>
struct _result_field_t;
// I am SO waiting for concepts lite!
template<typename Field, typename Enable = void>
struct field_methods_t
{
static constexpr bool _null_is_trivial = true;
operator _cpp_value_type() const { return static_cast<const Field&>(*this).value(); }
};
template<typename Db, typename FieldSpec>
struct field_methods_t<
_result_field_t<Db, FieldSpec>,
typename std::enable_if<enforce_null_result_treatment_t<Db>::value
and column_spec_can_be_null_t<FieldSpec>::value
and not null_is_trivial_value_t<FieldSpec>::value>::type>
{
static constexpr bool _null_is_trivial = false;
};
template<typename Db, typename FieldSpec>
struct _result_field_t: public field_methods_t<_result_field_t<Db, FieldSpec>>
{
using _field_methods_t = field_methods_t<_result_field_t<Db, FieldSpec>>;
using _traits = make_traits<integral,
tag_if<tag::null_is_trivial_value, _field_methods_t::_null_is_trivial>>;
struct _recursive_traits
{
using _parameters = std::tuple<>;
using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
using _can_be_null = column_spec_can_be_null_t<FieldSpec>;
};
_result_field_t():
_is_valid(false),
_is_null(true),
_value(false)
{}
void _validate()
{
_is_valid = true;
}
void _invalidate()
{
_is_valid = false;
_is_null = true;
_value = 0;
}
bool is_null() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return _is_null;
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (_is_null)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return false;
}
}
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;
signed char _value;
};
template<typename T>
struct _is_valid_operand
{
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and is_boolean_t<T>::value // the correct value type is required, of course
;
};
template<typename Base>
struct expression_operators: public basic_expression_operators<Base, is_boolean_t>
_parameter_t& operator=(const std::nullptr_t&)
{
template<typename T>
logical_and_t<Base, wrap_operand_t<T>> operator and(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
_value = false;
_is_null = true;
return *this;
}
return { *static_cast<const Base*>(this), rhs{t} };
}
bool is_null() const
{
return _is_null;
}
template<typename T>
logical_or_t<Base, wrap_operand_t<T>> operator or(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
_cpp_value_type value() const
{
return _value;
}
return { *static_cast<const Base*>(this), rhs{t} };
}
operator _cpp_value_type() const { return value(); }
logical_not_t<Base> operator not() const
template<typename Target>
void _bind(Target& target, size_t index) const
{
return { *static_cast<const Base*>(this) };
target._bind_boolean_parameter(index, &_value, _is_null);
}
};
template<typename Base>
struct column_operators
{
};
private:
signed char _value;
bool _is_null;
};
template<typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const boolean::_result_field_t<Db, FieldSpec>& e)
template<typename T>
struct _is_valid_operand
{
return os << e.value();
}
}
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and is_boolean_t<T>::value // the correct value type is required, of course
;
};
using boolean = detail::boolean;
template<typename Base>
struct expression_operators: public basic_expression_operators<Base, is_boolean_t>
{
template<typename T>
logical_and_t<Base, wrap_operand_t<T>> operator and(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), rhs{t} };
}
template<typename T>
logical_or_t<Base, wrap_operand_t<T>> operator or(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), rhs{t} };
}
logical_not_t<Base> operator not() const
{
return { *static_cast<const Base*>(this) };
}
};
template<typename Base>
struct column_operators
{
};
};
template<typename Db, typename FieldSpec>
struct result_field_t<boolean, Db, FieldSpec>: public result_field_methods_t<result_field_t<boolean, Db, FieldSpec>>
{
static_assert(std::is_same<value_type_of<FieldSpec>, boolean>::value, "field type mismatch");
using _cpp_value_type = typename boolean::_cpp_value_type;
result_field_t():
_is_valid(false),
_is_null(true),
_value(false)
{}
void _validate()
{
_is_valid = true;
}
void _invalidate()
{
_is_valid = false;
_is_null = true;
_value = 0;
}
bool is_null() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return _is_null;
}
bool _is_trivial() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return value() == false;
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (_is_null)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return false;
}
}
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;
signed char _value;
};
template<typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const result_field_t<boolean, Db, FieldSpec>& e)
{
return serialize(e, os);
}
}
#endif

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2013-2014, 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_BOOLEAN_EXPRESSION_H
#define SQLPP_BOOLEAN_EXPRESSION_H
#include <sqlpp11/type_traits.h>
#include <sqlpp11/interpretable.h>
namespace sqlpp
{
template<typename Database>
struct boolean_expression_t
{
using _traits = make_traits<boolean, tag::is_expression>;
using _recursive_traits = make_recursive_traits<>;
template<typename Expression>
boolean_expression_t(Expression expression):
_expression(expression)
{
static_assert(is_expression_t<Expression>::value, "boolean_expression requires a boolean expression argument");
static_assert(is_boolean_t<Expression>::value, "boolean_expression requires a boolean expression argument");
}
boolean_expression_t(const boolean_expression_t&) = default;
boolean_expression_t(boolean_expression_t&&) = default;
boolean_expression_t& operator=(const boolean_expression_t&) = default;
boolean_expression_t& operator=(boolean_expression_t&&) = default;
~boolean_expression_t() = default;
interpretable_t<Database> _expression;
};
template<typename Database, typename T>
boolean_expression_t<Database> boolean_expression(const Database&, T t)
{
return {t};
}
template<typename Database, typename T>
boolean_expression_t<Database> boolean_expression(T t)
{
return {t};
}
template<typename Context, typename Database>
struct serializer_t<Context, boolean_expression_t<Database>>
{
using T = boolean_expression_t<Database>;
static Context& _(const T& t, Context& context)
{
return serialize(t._expression);
}
};
}
#endif

View File

@ -33,10 +33,10 @@
namespace sqlpp
{
template<typename Flag, typename Expr>
struct count_t: public sqlpp::detail::integral::template expression_operators<count_t<Flag, Expr>>,
struct count_t: public sqlpp::integral::template expression_operators<count_t<Flag, Expr>>,
public alias_operators<count_t<Flag, Expr>>
{
using _traits = make_traits<::sqlpp::detail::integral, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_named_expression>;
using _traits = make_traits<::sqlpp::integral, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_named_expression>;
using _recursive_traits = make_recursive_traits<Expr>;
static_assert(is_noop<Flag>::value or std::is_same<sqlpp::distinct_t, Flag>::value, "count() used with flag other than 'distinct'");

View File

@ -57,7 +57,7 @@ namespace sqlpp
template<template<typename, typename...> class Target, typename First, typename T>
struct copy_tuple_args_impl
{
static_assert(wrong_t<T>::value, "copy_tuple_args must be called with a tuple");
static_assert(wrong_t<copy_tuple_args_impl>::value, "copy_tuple_args must be called with a tuple");
};
template<template<typename First, typename...> class Target, typename First, typename... Args>

View File

@ -73,7 +73,7 @@ namespace sqlpp
template<typename E, typename SET>
struct is_element_of
{
static_assert(::sqlpp::wrong_t<E, SET>::value, "SET has to be a type set");
static_assert(::sqlpp::wrong_t<is_element_of>::value, "SET has to be a type set");
};
template<typename E, typename... Elements>
@ -85,7 +85,7 @@ namespace sqlpp
template<typename L, typename R>
struct joined_set
{
static_assert(::sqlpp::wrong_t<L, R>::value, "L and R have to be type sets");
static_assert(::sqlpp::wrong_t<joined_set>::value, "L and R have to be type sets");
};
template<typename... LElements, typename... RElements>
@ -100,7 +100,7 @@ namespace sqlpp
template<typename L, typename R>
struct is_superset_of
{
static_assert(::sqlpp::wrong_t<L, R>::value, "L and R have to be type sets");
static_assert(::sqlpp::wrong_t<is_superset_of>::value, "L and R have to be type sets");
};
template<typename... LElements, typename... RElements>
@ -118,7 +118,7 @@ namespace sqlpp
template<typename L, typename R>
struct is_disjunct_from
{
static_assert(::sqlpp::wrong_t<L, R>::value, "invalid argument for is_disjunct_from");
static_assert(::sqlpp::wrong_t<is_disjunct_from>::value, "invalid argument for is_disjunct_from");
};
template<typename... LElements, typename... RElements>
@ -174,7 +174,7 @@ namespace sqlpp
template<typename... T>
struct make_joined_set
{
static_assert(::sqlpp::wrong_t<T...>::value, "invalid argument for joined set");
static_assert(::sqlpp::wrong_t<make_joined_set>::value, "invalid argument for joined set");
};
template<>
@ -197,7 +197,7 @@ namespace sqlpp
template<typename Minuend, typename Subtrahend>
struct make_difference_set
{
static_assert(::sqlpp::wrong_t<Minuend, Subtrahend>::value, "invalid argument for difference set");
static_assert(::sqlpp::wrong_t<make_difference_set>::value, "invalid argument for difference set");
};
template<typename... Minuends, typename... Subtrahends>
@ -214,14 +214,14 @@ namespace sqlpp
template<typename Lhs, typename Rhs>
struct make_intersect_set
{
static_assert(::sqlpp::wrong_t<Lhs, Rhs>::value, "invalid argument for intersect set");
static_assert(::sqlpp::wrong_t<make_intersect_set>::value, "invalid argument for intersect set");
};
template<typename... LhsElements, typename... RhsElements>
struct make_intersect_set<type_set<LhsElements...>, type_set<RhsElements...>>
{
template<typename E>
using is_in_both = is_element_of<E, make_type_set_t<LhsElements..., RhsElements...>>;
using is_in_both = all_t<is_element_of<E, type_set<LhsElements...>>::value, is_element_of<E, type_set<RhsElements...>>::value>;
using type = typename make_type_set_if<is_in_both, LhsElements...>::type;
};
@ -232,7 +232,7 @@ namespace sqlpp
template<template<typename> class Transformation, typename T>
struct transform_set
{
static_assert(::sqlpp::wrong_t<T>::value, "invalid argument for transform_set");
static_assert(::sqlpp::wrong_t<transform_set>::value, "invalid argument for transform_set");
};
template<template<typename> class Transformation, typename... E>

View File

@ -30,6 +30,8 @@
#include <sqlpp11/alias.h>
#include <sqlpp11/boolean.h>
#include <sqlpp11/tvin.h>
#include <sqlpp11/rhs_is_null.h>
#include <sqlpp11/rhs_is_trivial.h>
#include <sqlpp11/noop.h>
#include <sqlpp11/expression_fwd.h>
#include <sqlpp11/serializer.h>
@ -38,7 +40,7 @@
namespace sqlpp
{
template<typename Lhs, typename Rhs>
struct binary_expression_t<Lhs, op::equal_to, Rhs>: public ::sqlpp::detail::boolean::template expression_operators<binary_expression_t<Lhs, op::equal_to, Rhs>>,
struct binary_expression_t<Lhs, op::equal_to, Rhs>: public ::sqlpp::boolean::template expression_operators<binary_expression_t<Lhs, op::equal_to, Rhs>>,
public alias_operators<binary_expression_t<Lhs, op::equal_to, Rhs>>
{
using _traits = make_traits<boolean, sqlpp::tag::is_expression>;
@ -70,7 +72,8 @@ namespace sqlpp
{
context << "(";
serialize(t._lhs, context);
if (rhs_is_null(t))
if ((trivial_value_is_null_t<typename T::_lhs_t>::value and rhs_is_trivial(t))
or rhs_is_null(t))
{
context << " IS NULL";
}
@ -85,7 +88,7 @@ namespace sqlpp
};
template<typename Lhs, typename Rhs>
struct binary_expression_t<Lhs, op::not_equal_to, Rhs>: public ::sqlpp::detail::boolean::template expression_operators<binary_expression_t<Lhs, op::not_equal_to, Rhs>>,
struct binary_expression_t<Lhs, op::not_equal_to, Rhs>: public ::sqlpp::boolean::template expression_operators<binary_expression_t<Lhs, op::not_equal_to, Rhs>>,
public alias_operators<binary_expression_t<Lhs, op::not_equal_to, Rhs>>
{
using _traits = make_traits<boolean, sqlpp::tag::is_expression>;
@ -117,7 +120,8 @@ namespace sqlpp
{
context << "(";
serialize(t._lhs, context);
if (rhs_is_null(t))
if ((trivial_value_is_null_t<typename T::_lhs_t>::value and rhs_is_trivial(t))
or rhs_is_null(t))
{
context << " IS NOT NULL";
}
@ -132,7 +136,7 @@ namespace sqlpp
};
template<typename Rhs>
struct unary_expression_t<op::logical_not, Rhs>: public ::sqlpp::detail::boolean::template expression_operators<unary_expression_t<op::logical_not, Rhs>>,
struct unary_expression_t<op::logical_not, Rhs>: public ::sqlpp::boolean::template expression_operators<unary_expression_t<op::logical_not, Rhs>>,
public alias_operators<unary_expression_t<op::logical_not, Rhs>>
{
using _traits = make_traits<boolean, sqlpp::tag::is_expression>;
@ -161,7 +165,7 @@ namespace sqlpp
context << "(";
if (trivial_value_is_null_t<Rhs>::value)
{
serialize(t._lhs, context);
serialize(t._rhs, context);
context << " IS NULL ";
}
else
@ -170,6 +174,8 @@ namespace sqlpp
serialize(t._rhs, context);
}
context << ")";
return context;
}
};

View File

@ -29,64 +29,61 @@
namespace sqlpp
{
namespace detail
{
struct boolean;
struct integral;
struct floating_point;
}
struct boolean;
struct integral;
struct floating_point;
namespace op
{
struct less
{
using _traits = make_traits<::sqlpp::detail::boolean>;
using _traits = make_traits<::sqlpp::boolean>;
static constexpr const char* _name = "<";
};
struct less_equal
{
using _traits = make_traits<::sqlpp::detail::boolean>;
using _traits = make_traits<::sqlpp::boolean>;
static constexpr const char* _name = "<=";
};
struct equal_to
{
using _traits = make_traits<::sqlpp::detail::boolean>;
using _traits = make_traits<::sqlpp::boolean>;
};
struct not_equal_to
{
using _traits = make_traits<::sqlpp::detail::boolean>;
using _traits = make_traits<::sqlpp::boolean>;
};
struct greater_equal
{
using _traits = make_traits<::sqlpp::detail::boolean>;
using _traits = make_traits<::sqlpp::boolean>;
static constexpr const char* _name = ">=";
};
struct greater
{
using _traits = make_traits<::sqlpp::detail::boolean>;
using _traits = make_traits<::sqlpp::boolean>;
static constexpr const char* _name = ">";
};
struct logical_or
{
using _traits = make_traits<::sqlpp::detail::boolean>;
using _traits = make_traits<::sqlpp::boolean>;
static constexpr const char* _name = " OR ";
};
struct logical_and
{
using _traits = make_traits<::sqlpp::detail::boolean>;
using _traits = make_traits<::sqlpp::boolean>;
static constexpr const char* _name = " AND ";
};
struct logical_not
{
using _traits = make_traits<::sqlpp::detail::boolean>;
using _traits = make_traits<::sqlpp::boolean>;
};
template<typename ValueType>
@ -112,13 +109,13 @@ namespace sqlpp
struct divides
{
using _traits = make_traits<::sqlpp::detail::floating_point>;
using _traits = make_traits<::sqlpp::floating_point>;
static constexpr const char* _name = "/";
};
struct modulus
{
using _traits = make_traits<::sqlpp::detail::integral>;
using _traits = make_traits<::sqlpp::integral>;
static constexpr const char* _name = "%";
};

View File

@ -31,271 +31,241 @@
#include <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/result_field.h>
namespace sqlpp
{
namespace detail
// floating_point value type
struct floating_point
{
using _traits = make_traits<floating_point, ::sqlpp::tag::is_floating_point, ::sqlpp::tag::is_value_type>;
using _tag = ::sqlpp::tag::is_floating_point;
using _cpp_value_type = double;
// floating_point value type
struct floating_point
struct _parameter_t
{
using _traits = make_traits<floating_point, ::sqlpp::tag::is_floating_point, ::sqlpp::tag::is_expression>;
using _tag = ::sqlpp::tag::is_floating_point;
using _cpp_value_type = double;
using _value_type = floating_point;
struct _parameter_t
_parameter_t():
_value(0),
_is_null(true)
{}
_parameter_t(const _cpp_value_type& value):
_value(value),
_is_null(false)
{}
_parameter_t& operator=(const _cpp_value_type& value)
{
using _value_type = floating_point;
_value = value;
_is_null = false;
return *this;
}
_parameter_t():
_value(0),
_is_null(true)
{}
_parameter_t(const _cpp_value_type& value):
_value(value),
_is_null(false)
{}
_parameter_t& operator=(const _cpp_value_type& value)
{
_value = value;
_is_null = false;
return *this;
}
_parameter_t& operator=(const std::nullptr_t&)
{
_value = 0;
_is_null = true;
return *this;
}
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:
_cpp_value_type _value;
bool _is_null;
};
template<typename Db, typename FieldSpec>
struct _result_field_t;
// I am SO waiting for concepts lite!
template<typename Field, typename Enable = void>
struct field_methods_t
{
static constexpr bool _null_is_trivial = true;
operator _cpp_value_type() const { return static_cast<const Field&>(*this).value(); }
};
template<typename Db, typename FieldSpec>
struct field_methods_t<
_result_field_t<Db, FieldSpec>,
typename std::enable_if<enforce_null_result_treatment_t<Db>::value
and column_spec_can_be_null_t<FieldSpec>::value
and not null_is_trivial_value_t<FieldSpec>::value>::type>
{
static constexpr bool _null_is_trivial = false;
};
template<typename Db, typename FieldSpec>
struct _result_field_t: public field_methods_t<_result_field_t<Db, FieldSpec>>
{
using _field_methods_t = field_methods_t<_result_field_t<Db, FieldSpec>>;
using _traits = make_traits<integral,
tag_if<tag::null_is_trivial_value, _field_methods_t::_null_is_trivial>>;
struct _recursive_traits
{
using _parameters = std::tuple<>;
using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
using _can_be_null = column_spec_can_be_null_t<FieldSpec>;
};
_result_field_t():
_is_valid(false),
_is_null(true),
_value(0)
{}
void _validate()
{
_is_valid = true;
}
void _invalidate()
{
_is_valid = false;
_is_null = true;
_value = 0;
}
bool is_null() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return _is_null;
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (_is_null)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return 0;
}
}
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;
_cpp_value_type _value;
};
template<typename T>
struct _is_valid_operand
{
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and is_numeric_t<T>::value // the correct value type is required, of course
;
};
template<typename Base>
struct expression_operators: public basic_expression_operators<Base, is_numeric_t>
_parameter_t& operator=(const std::nullptr_t&)
{
template<typename T>
plus_t<Base, floating_point, wrap_operand_t<T>> operator +(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
_value = 0;
_is_null = true;
return *this;
}
return { *static_cast<const Base*>(this), rhs{t} };
}
bool is_null() const
{
return _is_null;
}
template<typename T>
minus_t<Base, floating_point, wrap_operand_t<T>> operator -(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
const _cpp_value_type& value() const
{
return _value;
}
return { *static_cast<const Base*>(this), rhs{t} };
}
operator _cpp_value_type() const { return _value; }
template<typename T>
multiplies_t<Base, floating_point, wrap_operand_t<T>> operator *(T t) const
{
using rhs = wrap_operand_t<T>;
return { *static_cast<const Base*>(this), rhs{t} };
}
template<typename T>
divides_t<Base, wrap_operand_t<T>> operator /(T t) const
{
using rhs = wrap_operand_t<T>;
return { *static_cast<const Base*>(this), rhs{t} };
}
unary_plus_t<floating_point, Base> operator +() const
template<typename Target>
void _bind(Target& target, size_t index) const
{
return { *static_cast<const Base*>(this) };
target._bind_floating_point_parameter(index, &_value, _is_null);
}
unary_minus_t<floating_point, Base> operator -() const
{
return { *static_cast<const Base*>(this) };
}
};
template<typename Base>
struct column_operators
{
template<typename T>
auto operator +=(T t) const -> assignment_t<Base, plus_t<Base, floating_point, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator -=(T t) const -> assignment_t<Base, minus_t<Base, floating_point, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator /=(T t) const -> assignment_t<Base, divides_t<Base, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator *=(T t) const -> assignment_t<Base, multiplies_t<Base, floating_point, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
};
private:
_cpp_value_type _value;
bool _is_null;
};
template<typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const floating_point::_result_field_t<Db, FieldSpec>& e)
template<typename T>
struct _is_valid_operand
{
return os << e.value();
}
}
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and is_numeric_t<T>::value // the correct value type is required, of course
;
};
using floating_point = detail::floating_point;
template<typename Base>
struct expression_operators: public basic_expression_operators<Base, is_numeric_t>
{
template<typename T>
plus_t<Base, floating_point, wrap_operand_t<T>> operator +(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), rhs{t} };
}
template<typename T>
minus_t<Base, floating_point, wrap_operand_t<T>> operator -(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), rhs{t} };
}
template<typename T>
multiplies_t<Base, floating_point, wrap_operand_t<T>> operator *(T t) const
{
using rhs = wrap_operand_t<T>;
return { *static_cast<const Base*>(this), rhs{t} };
}
template<typename T>
divides_t<Base, wrap_operand_t<T>> operator /(T t) const
{
using rhs = wrap_operand_t<T>;
return { *static_cast<const Base*>(this), rhs{t} };
}
unary_plus_t<floating_point, Base> operator +() const
{
return { *static_cast<const Base*>(this) };
}
unary_minus_t<floating_point, Base> operator -() const
{
return { *static_cast<const Base*>(this) };
}
};
template<typename Base>
struct column_operators
{
template<typename T>
auto operator +=(T t) const -> assignment_t<Base, plus_t<Base, floating_point, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator -=(T t) const -> assignment_t<Base, minus_t<Base, floating_point, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator /=(T t) const -> assignment_t<Base, divides_t<Base, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator *=(T t) const -> assignment_t<Base, multiplies_t<Base, floating_point, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
};
};
template<typename Db, typename FieldSpec>
struct result_field_t<floating_point, Db, FieldSpec>: public result_field_methods_t<result_field_t<floating_point, Db, FieldSpec>>
{
static_assert(std::is_same<value_type_of<FieldSpec>, floating_point>::value, "field type mismatch");
using _cpp_value_type = typename floating_point::_cpp_value_type;
result_field_t():
_is_valid(false),
_is_null(true),
_value(0)
{}
void _validate()
{
_is_valid = true;
}
void _invalidate()
{
_is_valid = false;
_is_null = true;
_value = 0;
}
bool is_null() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return _is_null;
}
bool _is_trivial() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return value() == 0;
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (_is_null)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return 0;
}
}
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;
_cpp_value_type _value;
};
template<typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const result_field_t<floating_point, Db, FieldSpec>& e)
{
return serialize(e, os);
}
}
#endif

View File

@ -42,6 +42,7 @@
#include <sqlpp11/avg.h>
#include <sqlpp11/sum.h>
#include <sqlpp11/verbatim_table.h> // Csaba Csoma suggests: unsafe_sql instead of verbatim
#include <sqlpp11/value_or_null.h>
namespace sqlpp
{
@ -99,6 +100,18 @@ namespace sqlpp
return { context.str() };
}
template<typename Expression>
auto is_null(Expression e) -> decltype(e.is_null())
{
return e.is_null();
}
template<typename Expression>
auto is_not_null(Expression e) -> decltype(e.is_not_null())
{
return e.is_not_null();
}
template<typename Container>
struct value_list_t // to be used in .in() method
{

View File

@ -33,284 +33,257 @@
#include <sqlpp11/exception.h>
#include <sqlpp11/value_type.h>
#include <sqlpp11/assignment.h>
#include <sqlpp11/result_field.h>
namespace sqlpp
{
namespace detail
// integral value type
struct integral
{
using _traits = make_traits<integral, ::sqlpp::tag::is_integral, ::sqlpp::tag::is_value_type>;
using _tag = ::sqlpp::tag::is_integral;
using _cpp_value_type = int64_t;
// integral value type
struct integral
struct _parameter_t
{
using _traits = make_traits<integral, ::sqlpp::tag::is_integral, ::sqlpp::tag::is_expression>;
using _tag = ::sqlpp::tag::is_integral;
using _cpp_value_type = int64_t;
using _value_type = integral;
struct _parameter_t
_parameter_t():
_value(0),
_is_null(true)
{}
explicit _parameter_t(const _cpp_value_type& value):
_value(value),
_is_null(false)
{}
_parameter_t& operator=(const _cpp_value_type& value)
{
using _value_type = integral;
_value = value;
_is_null = false;
return *this;
}
_parameter_t():
_value(0),
_is_null(true)
{}
explicit _parameter_t(const _cpp_value_type& value):
_value(value),
_is_null(false)
{}
_parameter_t& operator=(const _cpp_value_type& value)
{
_value = value;
_is_null = false;
return *this;
}
void set_null()
{
_value = 0;
_is_null = true;
}
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:
_cpp_value_type _value;
bool _is_null;
};
template<typename Db, typename FieldSpec>
struct _result_field_t;
// I am SO waiting for concepts lite!
template<typename Field, typename Enable = void>
struct field_methods_t
{
static constexpr bool _null_is_trivial = true;
operator _cpp_value_type() const { return static_cast<const Field&>(*this).value(); }
};
template<typename Db, typename FieldSpec>
struct field_methods_t<
_result_field_t<Db, FieldSpec>,
typename std::enable_if<enforce_null_result_treatment_t<Db>::value
and column_spec_can_be_null_t<FieldSpec>::value
and not null_is_trivial_value_t<FieldSpec>::value>::type>
{
static constexpr bool _null_is_trivial = false;
};
template<typename Db, typename FieldSpec>
struct _result_field_t: public field_methods_t<_result_field_t<Db, FieldSpec>>
{
using _field_methods_t = field_methods_t<_result_field_t<Db, FieldSpec>>;
using _traits = make_traits<integral,
tag_if<tag::null_is_trivial_value, _field_methods_t::_null_is_trivial>>;
struct _recursive_traits
{
using _parameters = std::tuple<>;
using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
using _can_be_null = column_spec_can_be_null_t<FieldSpec>;
};
_result_field_t():
_is_valid(false),
_is_null(true),
_value(0)
{}
void _invalidate()
{
_is_valid = false;
_is_null = true;
_value = 0;
}
void _validate()
{
_is_valid = true;
}
bool is_null() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return _is_null;
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (_is_null)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return 0;
}
}
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;
_cpp_value_type _value;
};
template<typename T>
struct _is_valid_operand
{
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and is_numeric_t<T>::value // the correct value type is required, of course
;
};
template<typename Base>
struct expression_operators: public basic_expression_operators<Base, is_numeric_t>
void set_null()
{
template<typename T>
plus_t<Base, value_type_t<T>, wrap_operand_t<T>> operator +(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
_value = 0;
_is_null = true;
}
return { *static_cast<const Base*>(this), {t} };
}
bool is_null() const
{
return _is_null;
}
template<typename T>
minus_t<Base, value_type_t<T>, wrap_operand_t<T>> operator -(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
const _cpp_value_type& value() const
{
return _value;
}
return { *static_cast<const Base*>(this), {t} };
}
operator _cpp_value_type() const { return _value; }
template<typename T>
multiplies_t<Base, value_type_t<T>, wrap_operand_t<T>> operator *(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), {t} };
}
template<typename T>
divides_t<Base, wrap_operand_t<T>> operator /(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), {t} };
}
template<typename T>
modulus_t<Base, wrap_operand_t<T>> operator %(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), {t} };
}
unary_plus_t<integral, Base> operator +() const
template<typename Target>
void _bind(Target& target, size_t index) const
{
return { *static_cast<const Base*>(this) };
target._bind_integral_parameter(index, &_value, _is_null);
}
unary_minus_t<integral, Base> operator -() const
{
return { *static_cast<const Base*>(this) };
}
};
template<typename Base>
struct column_operators
{
template<typename T>
auto operator +=(T t) const -> assignment_t<Base, plus_t<Base, value_type_t<T>, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator -=(T t) const -> assignment_t<Base, minus_t<Base, value_type_t<T>, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator /=(T t) const -> assignment_t<Base, divides_t<Base, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator *=(T t) const -> assignment_t<Base, multiplies_t<Base, value_type_t<T>, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
};
private:
_cpp_value_type _value;
bool _is_null;
};
template<typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const integral::_result_field_t<Db, FieldSpec>& e)
template<typename T>
struct _is_valid_operand
{
return os << e.value();
}
}
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and is_numeric_t<T>::value // the correct value type is required, of course
;
};
using tinyint = detail::integral;
using smallint = detail::integral;
using integer = detail::integral;
using bigint = detail::integral;
template<typename Base>
struct expression_operators: public basic_expression_operators<Base, is_numeric_t>
{
template<typename T>
plus_t<Base, value_type_t<T>, wrap_operand_t<T>> operator +(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), {t} };
}
template<typename T>
minus_t<Base, value_type_t<T>, wrap_operand_t<T>> operator -(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), {t} };
}
template<typename T>
multiplies_t<Base, value_type_t<T>, wrap_operand_t<T>> operator *(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), {t} };
}
template<typename T>
divides_t<Base, wrap_operand_t<T>> operator /(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), {t} };
}
template<typename T>
modulus_t<Base, wrap_operand_t<T>> operator %(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), {t} };
}
unary_plus_t<integral, Base> operator +() const
{
return { *static_cast<const Base*>(this) };
}
unary_minus_t<integral, Base> operator -() const
{
return { *static_cast<const Base*>(this) };
}
};
template<typename Base>
struct column_operators
{
template<typename T>
auto operator +=(T t) const -> assignment_t<Base, plus_t<Base, value_type_t<T>, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator -=(T t) const -> assignment_t<Base, minus_t<Base, value_type_t<T>, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator /=(T t) const -> assignment_t<Base, divides_t<Base, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
template<typename T>
auto operator *=(T t) const -> assignment_t<Base, multiplies_t<Base, value_type_t<T>, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
};
};
template<typename Db, typename FieldSpec>
struct result_field_t<integral, Db, FieldSpec>: public result_field_methods_t<result_field_t<integral, Db, FieldSpec>>
{
static_assert(std::is_same<value_type_of<FieldSpec>, integral>::value, "field type mismatch");
using _cpp_value_type = typename integral::_cpp_value_type;
result_field_t():
_is_valid(false),
_is_null(true),
_value(0)
{}
void _invalidate()
{
_is_valid = false;
_is_null = true;
_value = 0;
}
void _validate()
{
_is_valid = true;
}
bool is_null() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return _is_null;
}
bool _is_trivial() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return value() == 0;
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (_is_null)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return 0;
}
}
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;
_cpp_value_type _value;
};
template<typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const result_field_t<integral, Db, FieldSpec>& e)
{
return serialize(e, os);
}
using tinyint = integral;
using smallint = integral;
using integer = integral;
using bigint = integral;
}
#endif

View File

@ -36,7 +36,7 @@ namespace sqlpp
{
static void _(const T& t, Context& context)
{
static_assert(wrong_t<Context, T>::value, "missing interpreter specialization");
static_assert(wrong_t<interpreter_t>::value, "missing interpreter specialization");
}
};

View File

@ -140,10 +140,10 @@ namespace sqlpp
template<typename T>
using _new_statement_t = typename Policies::template _new_statement_t<no_into_t, T>;
static void _check_consistency()
{
static_assert(wrong_t<Policies>::value, "into() required");
}
static void _check_consistency()
{
static_assert(wrong_t<_methods_t>::value, "into() required");
}
template<typename... Args>
auto into(Args... args)

View File

@ -50,14 +50,14 @@ namespace sqlpp
struct left_outer_join_t
{
template<typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Lhs>, provided_tables_of<Rhs>>;
using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of<Lhs>, provided_outer_tables_of<Rhs>>;
static constexpr const char* _name = " LEFT OUTER ";
};
struct right_outer_join_t
{
template<typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of<Lhs>, provided_outer_tables_of<Rhs>>;
using _provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Lhs>, provided_tables_of<Rhs>>;
static constexpr const char* _name = " RIGHT OUTER ";
};

View File

@ -117,7 +117,7 @@ namespace sqlpp
static void _(const T& t, Context& context)
{
static_assert(wrong_t<Columns...>::value, "multi_column must be used with an alias");
static_assert(wrong_t<serializer_t>::value, "multi_column must be used with an alias");
}
};

View File

@ -33,7 +33,7 @@ namespace sqlpp
{
struct null_t
{
using _traits = make_traits<no_value_t, tag::is_expression>;
using _traits = make_traits<no_value_t, tag::is_expression, tag::is_sql_null>;
using _recursive_traits = make_recursive_traits<>;
};

View File

@ -83,7 +83,7 @@ namespace sqlpp
auto parameter(const ValueType&, const AliasProvider&)
-> parameter_t<wrap_operand_t<ValueType>, AliasProvider>
{
static_assert(is_expression_t<ValueType>::value, "first argument is not a value type");
static_assert(is_value_type_t<ValueType>::value, "first argument is not a value type");
static_assert(is_alias_provider_t<AliasProvider>::value, "second argument is not an alias provider");
return {};
}

View File

@ -37,7 +37,7 @@ namespace sqlpp
template<typename T>
struct parameter_list_t
{
static_assert(wrong_t<T>::value, "Template parameter for parameter_list_t has to be a tuple");
static_assert(wrong_t<parameter_list_t>::value, "Template parameter for parameter_list_t has to be a tuple");
};
template<typename... Parameter>

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2013-2014, 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_RESULT_FIELD_H
#define SQLPP_RESULT_FIELD_H
#include <sqlpp11/wrong.h>
#include <sqlpp11/result_field_methods.h>
namespace sqlpp
{
template<typename ValueType, typename Db, typename Field>
struct result_field_t
{
static_assert(wrong_t<result_field_t>::value, "Missing specialization for result_field_t");
};
template<typename Context, typename ValueType, typename Db, typename FieldSpec>
struct serializer_t<Context, result_field_t<ValueType, Db, FieldSpec>>
{
using T = result_field_t<ValueType, Db, FieldSpec>;
static Context& _(const T& t, Context& context)
{
if (t.is_null() and not null_is_trivial_value_t<T>::value)
{
context << "NULL";
}
else
{
context << t.value();
}
return context;
}
};
}
#endif

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2013-2014, 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_RESULT_FIELD_METHODS_H
#define SQLPP_RESULT_FIELD_METHODS_H
#include <utility>
#include <sqlpp11/basic_expression_operators.h>
namespace sqlpp
{
namespace detail
{
template<typename Field>
struct get_field_spec_impl
{
static_assert(wrong_t<get_field_spec_impl>::value, "Invalid argument for get_field_spec");
};
template<template<typename, typename, typename> class Field, typename ValueType, typename Db, typename FieldSpec>
struct get_field_spec_impl<Field<ValueType, Db, FieldSpec>>
{
using type = FieldSpec;
};
template<typename Field>
using get_field_spec_t = typename get_field_spec_impl<Field>::type;
}
template<typename Field, typename Enable = void>
struct result_field_methods_base_t
{
using _field_spec_t = detail::get_field_spec_t<Field>;
static constexpr bool _null_is_trivial = true;
operator cpp_value_type_of<_field_spec_t>() const { return static_cast<const Field&>(*this).value(); }
};
template<template<typename, typename, typename> class Field, typename ValueType, typename Db, typename FieldSpec>
struct result_field_methods_base_t<
Field<ValueType, Db, FieldSpec>,
typename std::enable_if<enforce_null_result_treatment_t<Db>::value
and column_spec_can_be_null_t<FieldSpec>::value
and not null_is_trivial_value_t<FieldSpec>::value>::type>
{
using _field_spec_t = FieldSpec;
static constexpr bool _null_is_trivial = false;
};
template<typename Field>
struct result_field_methods_t: public result_field_methods_base_t<Field>,
public alias_operators<Field>
{
using _base_t = result_field_methods_base_t<Field>;
using _field_spec_t = typename _base_t::_field_spec_t;
using _traits = make_traits<value_type_of<_field_spec_t>,
tag::is_result_field,
tag::is_expression,
tag_if<tag::null_is_trivial_value, _base_t::_null_is_trivial>>;
struct _recursive_traits
{
using _parameters = std::tuple<>;
using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
using _can_be_null = column_spec_can_be_null_t<_field_spec_t>;
};
};
}
#endif

View File

@ -41,9 +41,9 @@ namespace sqlpp
template<typename Db, std::size_t index, typename FieldSpec>
struct result_field:
public FieldSpec::_name_t::template _member_t<typename value_type_of<FieldSpec>::template _result_field_t<Db, FieldSpec>>
public FieldSpec::_name_t::template _member_t<result_field_t<value_type_of<FieldSpec>, Db, FieldSpec>>
{
using _field = typename FieldSpec::_name_t::template _member_t<typename value_type_of<FieldSpec>::template _result_field_t<Db, FieldSpec>>;
using _field = typename FieldSpec::_name_t::template _member_t<result_field_t<value_type_of<FieldSpec>, Db, FieldSpec>>;
result_field() = default;
@ -184,12 +184,12 @@ namespace sqlpp
using _impl = detail::result_row_impl<Db, detail::make_column_index_sequence<0, FieldSpecs...>, FieldSpecs...>;
struct _field_spec_t
{
using _traits = make_traits<detail::text, tag::is_noop, tag::can_be_null, tag::null_is_trivial_value>;
using _traits = make_traits<text, tag::is_noop, tag::can_be_null, tag::null_is_trivial_value>;
using _recursive_traits = make_recursive_traits<>;
struct _name_t {};
};
using _field_type = detail::text::_result_field_t<Db, _field_spec_t>;
using _field_type = result_field_t<text, Db, _field_spec_t>;
static constexpr size_t _last_static_index = _impl::_last_index;
bool _is_valid;

View File

@ -32,7 +32,7 @@
namespace sqlpp
{
template<typename T, typename Enable = void>
struct is_trivial_t
struct rhs_is_null_t
{
static constexpr bool _(const T&)
{
@ -41,27 +41,29 @@ namespace sqlpp
};
template<typename T>
struct is_trivial_t<T, typename std::enable_if<std::is_member_function_pointer<decltype(&T::_is_trivial)>::value, void>::type>
struct rhs_is_null_t<T, typename std::enable_if<is_tvin_t<T>::value, void>::type>
{
static bool _(const T& t)
{
return t._is_trivial();
return t._is_null();
}
};
template<typename T>
bool is_trivial(const T& t)
struct rhs_is_null_t<T, typename std::enable_if<is_result_field_t<T>::value, void>::type>
{
return is_trivial_t<T>::_(t);
}
static bool _(const T& t)
{
return t.is_null();
}
};
template<typename Expression>
constexpr bool rhs_is_null(const Expression& e)
{
return (((trivial_value_is_null_t<typename Expression::_lhs_t>::value or is_tvin_t<typename Expression::_rhs_t>::value)
and is_trivial(e._rhs))
or (std::is_same<typename Expression::_rhs_t, null_t>::value));
return rhs_is_null_t<typename std::decay<Expression>::type::_rhs_t>::_(e._rhs);
}
}
#endif

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2013-2014, 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_RHS_IS_TRIVIAL_H
#define SQLPP_RHS_IS_TRIVIAL_H
#include <sqlpp11/tvin.h>
namespace sqlpp
{
template<typename T, typename Enable = void>
struct rhs_is_trivial_t
{
static constexpr bool _(const T&)
{
return false;
}
};
template<typename T>
struct rhs_is_trivial_t<T, typename std::enable_if<is_wrapped_value_t<T>::value, void>::type>
{
static bool _(const T& t)
{
return t._is_trivial();
}
};
template<typename T>
struct rhs_is_trivial_t<T, typename std::enable_if<is_tvin_t<T>::value, void>::type>
{
static bool _(const T& t)
{
return t._is_trivial();
}
};
template<typename T>
struct rhs_is_trivial_t<T, typename std::enable_if<is_result_field_t<T>::value, void>::type>
{
static bool _(const T& t)
{
if (null_is_trivial_value_t<T>::value)
{
return t._is_trivial();
}
else
{
if (t.is_null())
{
return false;
}
else
{
return t._is_trivial();
}
}
}
};
template<typename Expression>
constexpr bool rhs_is_trivial(const Expression& e)
{
return rhs_is_trivial_t<typename std::decay<Expression>::type::_rhs_t>::_(e._rhs);
}
}
#endif

View File

@ -36,7 +36,7 @@ namespace sqlpp
{
static void _(const T& t, Context& context)
{
static_assert(wrong_t<Context, T>::value, "missing serializer specialization");
static_assert(wrong_t<serializer_t>::value, "missing serializer specialization");
}
};

View File

@ -35,6 +35,7 @@
#include <sqlpp11/select.h>
#include <sqlpp11/functions.h>
#include <sqlpp11/transaction.h>
#include <sqlpp11/boolean_expression.h>
#endif

View File

@ -112,7 +112,7 @@ namespace sqlpp
::sqlpp::detail::make_intersect_set_t<
required_tables_of<_result_type_provider>,
provided_outer_tables_of<statement_policies_t>
>::size::value>;
>::size::value != 0>;
};
};
}

View File

@ -32,223 +32,222 @@
#include <sqlpp11/exception.h>
#include <sqlpp11/concat.h>
#include <sqlpp11/like.h>
#include <sqlpp11/result_field.h>
namespace sqlpp
{
namespace detail
// text value type
struct text
{
// text value type
struct text
using _traits = make_traits<text, ::sqlpp::tag::is_text, ::sqlpp::tag::is_value_type>;
using _tag = ::sqlpp::tag::is_text;
using _cpp_value_type = std::string;
struct _parameter_t
{
using _traits = make_traits<text, ::sqlpp::tag::is_text, ::sqlpp::tag::is_expression>;
using _tag = ::sqlpp::tag::is_text;
using _cpp_value_type = std::string;
using _value_type = text;
struct _parameter_t
_parameter_t():
_value(""),
_is_null(true)
{}
_parameter_t(const _cpp_value_type& value):
_value(value),
_is_null(false)
{}
_parameter_t& operator=(const _cpp_value_type& value)
{
using _value_type = integral;
_value = value;
_is_null = false;
return *this;
}
_parameter_t():
_value(""),
_is_null(true)
{}
_parameter_t(const _cpp_value_type& value):
_value(value),
_is_null(false)
{}
_parameter_t& operator=(const _cpp_value_type& value)
{
_value = value;
_is_null = false;
return *this;
}
_parameter_t& operator=(const std::nullptr_t&)
{
_value = "";
_is_null = true;
return *this;
}
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:
_cpp_value_type _value;
bool _is_null;
};
template<typename Db, typename FieldSpec>
struct _result_field_t;
// I am SO waiting for concepts lite!
template<typename Field, typename Enable = void>
struct field_methods_t
{
static constexpr bool _null_is_trivial = true;
operator _cpp_value_type() const { return static_cast<const Field&>(*this).value(); }
};
template<typename Db, typename FieldSpec>
struct field_methods_t<
_result_field_t<Db, FieldSpec>,
typename std::enable_if<enforce_null_result_treatment_t<Db>::value
and column_spec_can_be_null_t<FieldSpec>::value
and not null_is_trivial_value_t<FieldSpec>::value>::type>
{
static constexpr bool _null_is_trivial = false;
};
template<typename Db, typename FieldSpec>
struct _result_field_t: public field_methods_t<_result_field_t<Db, FieldSpec>>
{
using _field_methods_t = field_methods_t<_result_field_t<Db, FieldSpec>>;
using _traits = make_traits<integral,
tag_if<tag::null_is_trivial_value, _field_methods_t::_null_is_trivial>>;
struct _recursive_traits
{
using _parameters = std::tuple<>;
using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
using _can_be_null = column_spec_can_be_null_t<FieldSpec>;
};
_result_field_t():
_is_valid(false),
_value_ptr(nullptr),
_len(0)
{}
void _validate()
{
_is_valid = true;
}
void _invalidate()
{
_is_valid = false;
_value_ptr = nullptr;
_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 _value_ptr == nullptr;
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (not _value_ptr)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return "";
}
}
return std::string(_value_ptr, _value_ptr + _len);
}
template<typename Target>
void _bind(Target& target, size_t i)
{
target._bind_text_result(i, &_value_ptr, &_len);
}
private:
bool _is_valid;
const char* _value_ptr;
size_t _len;
};
template<typename T>
struct _is_valid_operand
{
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and is_text_t<T>::value // the correct value type is required, of course
;
};
template<typename Base>
struct expression_operators: public basic_expression_operators<Base, is_text_t>
_parameter_t& operator=(const std::nullptr_t&)
{
template<typename T>
concat_t<Base, wrap_operand_t<T>> operator+(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
_value = "";
_is_null = true;
return *this;
}
return { *static_cast<const Base*>(this), {t} };
}
bool is_null() const
{
return _is_null;
}
template<typename T>
like_t<Base, wrap_operand_t<T>> like(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid argument for like()");
_cpp_value_type value() const
{
return _value;
}
return { *static_cast<const Base*>(this), {t} };
}
};
operator _cpp_value_type() const { return value(); }
template<typename Base>
struct column_operators
template<typename Target>
void _bind(Target& target, size_t index) const
{
template<typename T>
auto operator +=(T t) const -> assignment_t<Base, concat_t<Base, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
target._bind_text_parameter(index, &_value, _is_null);
}
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
};
private:
_cpp_value_type _value;
bool _is_null;
};
template<typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const text::_result_field_t<Db, FieldSpec>& e)
template<typename T>
struct _is_valid_operand
{
static constexpr bool value =
is_expression_t<T>::value // expressions are OK
and is_text_t<T>::value // the correct value type is required, of course
;
};
template<typename Base>
struct expression_operators: public basic_expression_operators<Base, is_text_t>
{
template<typename T>
concat_t<Base, wrap_operand_t<T>> operator+(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs operand");
return { *static_cast<const Base*>(this), {t} };
}
template<typename T>
like_t<Base, wrap_operand_t<T>> like(T t) const
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid argument for like()");
return { *static_cast<const Base*>(this), {t} };
}
};
template<typename Base>
struct column_operators
{
template<typename T>
auto operator +=(T t) const -> assignment_t<Base, concat_t<Base, wrap_operand_t<T>>>
{
using rhs = wrap_operand_t<T>;
static_assert(_is_valid_operand<rhs>::value, "invalid rhs assignment operand");
return { *static_cast<const Base*>(this), { *static_cast<const Base*>(this), rhs{t} } };
}
};
};
template<typename Db, typename FieldSpec>
struct result_field_t<text, Db, FieldSpec>: public result_field_methods_t<result_field_t<text, Db, FieldSpec>>
{
static_assert(std::is_same<value_type_of<FieldSpec>, text>::value, "field type mismatch");
using _cpp_value_type = typename text::_cpp_value_type;
result_field_t():
_is_valid(false),
_value_ptr(nullptr),
_len(0)
{}
void _validate()
{
_is_valid = true;
}
void _invalidate()
{
_is_valid = false;
_value_ptr = nullptr;
_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 _value_ptr == nullptr;
}
bool _is_trivial() const
{
if (not _is_valid)
throw exception("accessing is_null in non-existing row");
return value() == "";
}
_cpp_value_type value() const
{
if (not _is_valid)
throw exception("accessing value in non-existing row");
if (not _value_ptr)
{
if (enforce_null_result_treatment_t<Db>::value and not null_is_trivial_value_t<FieldSpec>::value)
{
throw exception("accessing value of NULL field");
}
else
{
return "";
}
}
return std::string(_value_ptr, _value_ptr + _len);
}
template<typename Target>
void _bind(Target& target, size_t i)
{
target._bind_text_result(i, &_value_ptr, &_len);
}
private:
bool _is_valid;
const char* _value_ptr;
size_t _len;
};
template<typename Context, typename Db, typename FieldSpec>
struct serializer_t<Context, result_field_t<text, Db, FieldSpec>>
{
using T = result_field_t<text, Db, FieldSpec>;
static Context& _(const T& t, Context& context)
{
if (t.is_null() and not null_is_trivial_value_t<T>::value)
{
context << "NULL";
}
else
{
context << '\'' << context.escape(t.value()) << '\'';
}
return context;
}
};
template<typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const result_field_t<text, Db, FieldSpec>& e)
{
if (e.is_null() and not null_is_trivial_value_t<FieldSpec>::value)
{
return os << "NULL";
}
else
{
return os << e.value();
}
}
}
using text = detail::text;
using blob = detail::text;
using varchar = detail::text;
using char_ = detail::text;
using blob = text;
using varchar = text;
using char_ = text;
}
#endif

View File

@ -63,7 +63,7 @@ namespace sqlpp
static Context& _(const T& t, Context& context)
{
static_assert(wrong_t<Context, Operand>::value, "tvin may only be used with operators =, == and !=");
static_assert(wrong_t<serializer_t>::value, "tvin may only be used with operators =, == and !=");
}
};
@ -108,6 +108,11 @@ namespace sqlpp
return _value._is_trivial();
}
bool _is_null() const
{
return _value._is_trivial();
}
_operand_t _value;
};
@ -150,8 +155,7 @@ namespace sqlpp
auto tvin(Operand operand) -> tvin_arg_t<typename wrap_operand<Operand>::type>
{
using _operand_t = typename wrap_operand<Operand>::type;
static_assert(std::is_same<_operand_t, text_operand>::value
or not std::is_same<_operand_t, Operand>::value, "tvin() used with invalid type (only string and primitive types allowed)");
static_assert(not std::is_same<_operand_t, Operand>::value or is_result_field_t<Operand>::value, "tvin() used with invalid type (only string and primitive types allowed)");
return {{operand}};
}

View File

@ -71,6 +71,8 @@ namespace sqlpp
template<typename T>\
using name##_t = typename detail::name##_impl<T>::type;
SQLPP_VALUE_TRAIT_GENERATOR(is_value_type);
SQLPP_VALUE_TRAIT_GENERATOR(is_sql_null);
SQLPP_VALUE_TRAIT_GENERATOR(is_boolean);
SQLPP_VALUE_TRAIT_GENERATOR(is_integral);
SQLPP_VALUE_TRAIT_GENERATOR(is_floating_point);
@ -85,6 +87,7 @@ namespace sqlpp
SQLPP_VALUE_TRAIT_GENERATOR(is_multi_expression);
SQLPP_VALUE_TRAIT_GENERATOR(is_alias);
SQLPP_VALUE_TRAIT_GENERATOR(is_select_flag);
SQLPP_VALUE_TRAIT_GENERATOR(is_result_field);
SQLPP_VALUE_TRAIT_GENERATOR(must_not_insert);
SQLPP_VALUE_TRAIT_GENERATOR(must_not_update);
@ -191,6 +194,9 @@ namespace sqlpp
template<typename T>
using value_type_of = typename detail::value_type_of_impl<T>::type;
template<typename T>
using cpp_value_type_of = typename value_type_of<T>::_cpp_value_type;
template<typename T>
using required_tables_of = typename detail::required_table_of_impl<T>::type;

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2013-2014, 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_VALUE_OR_NULL_H
#define SQLPP_VALUE_OR_NULL_H
#include <sqlpp11/parameter.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/column_types.h>
#include <sqlpp11/in.h>
#include <sqlpp11/value_type.h>
#include <sqlpp11/exists.h>
#include <sqlpp11/any.h>
#include <sqlpp11/some.h>
#include <sqlpp11/count.h>
#include <sqlpp11/min.h>
#include <sqlpp11/max.h>
#include <sqlpp11/avg.h>
#include <sqlpp11/sum.h>
#include <sqlpp11/verbatim_table.h> // Csaba Csoma suggests: unsafe_sql instead of verbatim
#include <sqlpp11/value_or_null.h>
namespace sqlpp
{
template<typename ValueType>
struct value_or_null_t
{
using _cpp_value_type = typename ValueType::_cpp_value_type;
using _traits = make_traits<ValueType, tag::is_expression>;
using _recursive_traits = make_recursive_traits<>;
value_or_null_t(_cpp_value_type value):
_value(value),
_is_null(false)
{}
value_or_null_t(const null_t&):
_value(),
_is_null(true)
{}
typename ValueType::_cpp_value_type _value;
bool _is_null;
};
template<typename T>
auto value_or_null(T t) -> value_or_null_t<value_type_of<wrap_operand_t<T>>>
{
static_assert(is_wrapped_value_t<wrap_operand_t<T>>::value, "value_or_null() is to be called with non-sql-type like int, or string or null");
return { t };
}
template<typename ValueType>
auto value_or_null(null_t t) -> value_or_null_t<ValueType>
{
static_assert(is_value_type_t<ValueType>::value, "value_or_null() is to be called with non-sql-type like int, or string");
return { t };
}
}
#endif

View File

@ -224,7 +224,7 @@ namespace sqlpp
static void _check_consistency()
{
static_assert(Required ? wrong_t<Policies>::value : true, "where expression required, e.g. where(true)");
static_assert(Required ? wrong_t<_methods_t>::value : true, "where expression required, e.g. where(true)");
}
template<typename... Args>

View File

@ -33,17 +33,14 @@
namespace sqlpp
{
namespace detail
{
struct boolean;
struct integral;
struct floating_point;
struct text;
}
struct boolean;
struct integral;
struct floating_point;
struct text;
struct boolean_operand
{
using _traits = make_traits<::sqlpp::detail::boolean, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>;
using _traits = make_traits<::sqlpp::boolean, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>;
using _recursive_traits = make_recursive_traits<>;
using _value_t = bool;
@ -81,7 +78,7 @@ namespace sqlpp
struct integral_operand
{
using _traits = make_traits<::sqlpp::detail::integral, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>;
using _traits = make_traits<::sqlpp::integral, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>;
using _recursive_traits = make_recursive_traits<>;
using _value_t = int64_t;
@ -120,7 +117,7 @@ namespace sqlpp
struct floating_point_operand
{
using _traits = make_traits<::sqlpp::detail::floating_point, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>;
using _traits = make_traits<::sqlpp::floating_point, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>;
using _recursive_traits = make_recursive_traits<>;
using _value_t = double;
@ -158,7 +155,7 @@ namespace sqlpp
struct text_operand
{
using _traits = make_traits<::sqlpp::detail::text, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>;
using _traits = make_traits<::sqlpp::text, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>;
using _recursive_traits = make_recursive_traits<>;
using _value_t = std::string;
@ -219,7 +216,7 @@ namespace sqlpp
};
template<typename T>
struct wrap_operand<T, typename std::enable_if<std::is_convertible<T, std::string>::value>::type>
struct wrap_operand<T, typename std::enable_if<std::is_convertible<T, std::string>::value and not is_result_field_t<T>::value>::type>
{
using type = text_operand;
};

View File

@ -0,0 +1,17 @@
include_directories(${CMAKE_BINARY_DIR}/tests)
add_executable(
no_conversion_operator_if_null_not_trivial
EXCLUDE_FROM_ALL
no_conversion_operator_if_null_not_trivial.cpp
)
add_custom_command(OUTPUT no_conversion_operator_if_null_not_trivial.out
COMMAND ${CMAKE_MAKE_PROGRAM} no_conversion_operator_if_null_not_trivial > ${CMAKE_CURRENT_BINARY_DIR}/no_conversion_operator_if_null_not_trivial.out 2>&1 || true
COMMAND grep "int i = row.alpha" ${CMAKE_CURRENT_BINARY_DIR}/no_conversion_operator_if_null_not_trivial.out > /dev/null
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/no_conversion_operator_if_null_not_trivial.cpp
COMMENT "no_conversion_operator_if_null_not_trivial"
)
add_custom_target(test_constraints DEPENDS no_conversion_operator_if_null_not_trivial.out COMMAND true)

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2013-2014, 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 "Sample.h"
#include "MockDb.h"
#include <sqlpp11/sqlpp11.h>
EnforceDb edb {};
int main()
{
test::TabBar t;
static_assert(sqlpp::can_be_null_t<decltype(t.alpha)>::value, "t.alpha can be null");
static_assert(not sqlpp::null_is_trivial_value_t<decltype(t.alpha)>::value, "t.alpha does not say null_is_trivial");
for (const auto& row : edb(select(all_of(t)).from(t).where(true)))
{
static_assert(sqlpp::can_be_null_t<decltype(row.alpha)>::value, "row.alpha can be null");
static_assert(not sqlpp::null_is_trivial_value_t<decltype(row.alpha)>::value, "row.alpha does not interpret null_is_trivial");
int i = row.alpha;
}
return 0;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2013-2014, 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 <iostream>
#include "Sample.h"
#include "MockDb.h"
#include <sqlpp11/sqlpp11.h>
MockDb db = {};
int main()
{
test::TabBar t;
auto x = boolean_expression(db, t.alpha == 7);
x = boolean_expression(db, t.gamma);
x = sqlpp::boolean_expression<MockDb>(t.beta.like("%cheesecake"));
return 0;
}

View File

@ -6,6 +6,7 @@ macro (build_and_run arg)
add_test(${arg} ${arg})
endmacro ()
build_and_run(BooleanExpressionTest)
build_and_run(InterpretTest)
build_and_run(InsertTest)
build_and_run(RemoveTest)

View File

@ -135,6 +135,12 @@ int main()
using TI = decltype(t.alpha.is_null());
using TF = decltype(f.omega.is_null());
using TT = decltype(t.beta.is_null());
using TTI = decltype(is_null(t.alpha));
using TTF = decltype(is_null(f.omega));
using TTT = decltype(is_null(t.beta));
static_assert(std::is_same<TI, TTI>::value, "type requirement");
static_assert(std::is_same<TF, TTF>::value, "type requirement");
static_assert(std::is_same<TT, TTT>::value, "type requirement");
static_assert(sqlpp::is_named_expression_t<TI>::value, "type requirement");
static_assert(sqlpp::is_boolean_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_numeric_t<TI>::value, "type requirement");
@ -154,6 +160,12 @@ int main()
using TI = decltype(t.alpha.is_not_null());
using TF = decltype(f.omega.is_not_null());
using TT = decltype(t.beta.is_not_null());
using TTI = decltype(is_not_null(t.alpha));
using TTF = decltype(is_not_null(f.omega));
using TTT = decltype(is_not_null(t.beta));
static_assert(std::is_same<TI, TTI>::value, "type requirement");
static_assert(std::is_same<TF, TTF>::value, "type requirement");
static_assert(std::is_same<TT, TTT>::value, "type requirement");
static_assert(sqlpp::is_named_expression_t<TI>::value, "type requirement");
static_assert(sqlpp::is_boolean_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_numeric_t<TI>::value, "type requirement");
@ -356,6 +368,30 @@ int main()
static_assert(sqlpp::is_text_t<TT>::value, "type requirement");
}
// test value_or_null
{
using TB = decltype(sqlpp::value_or_null(true));
using TI = decltype(sqlpp::value_or_null(7));
using TF = decltype(sqlpp::value_or_null(5.6));
using TT = decltype(sqlpp::value_or_null("hallo"));
using TBN = decltype(sqlpp::value_or_null<sqlpp::boolean>(sqlpp::null));
using TIN = decltype(sqlpp::value_or_null<sqlpp::integral>(sqlpp::null));
using TFN = decltype(sqlpp::value_or_null<sqlpp::floating_point>(sqlpp::null));
using TTN = decltype(sqlpp::value_or_null<sqlpp::text>(sqlpp::null));
static_assert(std::is_same<TB, TBN>::value, "type_requirement");
static_assert(std::is_same<TI, TIN>::value, "type_requirement");
static_assert(std::is_same<TF, TFN>::value, "type_requirement");
static_assert(std::is_same<TT, TTN>::value, "type_requirement");
static_assert(not sqlpp::is_named_expression_t<TB>::value, "type requirement");
static_assert(sqlpp::is_boolean_t<TB>::value, "type requirement");
static_assert(not sqlpp::is_named_expression_t<TB>::value, "type requirement");
static_assert(sqlpp::is_integral_t<TI>::value, "type requirement");
static_assert(not sqlpp::is_named_expression_t<TI>::value, "type requirement");
static_assert(sqlpp::is_floating_point_t<TF>::value, "type requirement");
static_assert(not sqlpp::is_named_expression_t<TT>::value, "type requirement");
static_assert(sqlpp::is_text_t<TT>::value, "type requirement");
}
// test verbatim
{
using TB = decltype(sqlpp::verbatim<sqlpp::boolean>("1"));
@ -389,5 +425,20 @@ int main()
static_assert(sqlpp::is_alias_t<T>::value, "type requirement");
}
// test tvin
{
static_assert(std::is_same<decltype(sqlpp::tvin(1)), sqlpp::tvin_arg_t<sqlpp::integral_operand>>::value, "integral values are accepted and wrapped") ;
static_assert(std::is_same<decltype(sqlpp::tvin(false)), sqlpp::tvin_arg_t<sqlpp::boolean_operand>>::value, "bool values are accepted and wrapped") ;
static_assert(std::is_same<decltype(sqlpp::tvin(0.17)), sqlpp::tvin_arg_t<sqlpp::floating_point_operand>>::value, "float values are accepted and wrapped") ;
static_assert(std::is_same<decltype(sqlpp::tvin("test")), sqlpp::tvin_arg_t<sqlpp::text_operand>>::value, "text values are accepted and wrapped") ;
for (const auto& row : db(select(all_of(t)).from(t).where(true)))
{
static_assert(std::is_same<decltype(sqlpp::tvin(row.alpha)), sqlpp::tvin_arg_t<decltype(row.alpha)>>::value, "result fields are accepted and not wrapped") ;
static_assert(std::is_same<decltype(sqlpp::tvin(row.beta)), sqlpp::tvin_arg_t<decltype(row.beta)>>::value, "result fields are accepted and not wrapped") ;
static_assert(std::is_same<decltype(sqlpp::tvin(row.gamma)), sqlpp::tvin_arg_t<decltype(row.gamma)>>::value, "result fields are accepted and not wrapped") ;
}
}
return 0;
}

View File

@ -101,7 +101,7 @@ int main()
// functions
serialize(sqlpp::value(7), printer).str();
serialize(sqlpp::verbatim<sqlpp::detail::integral>("irgendwas integrales"), printer).str();
serialize(sqlpp::verbatim<sqlpp::integral>("irgendwas integrales"), printer).str();
serialize(sqlpp::value_list(std::vector<int>({1,2,3,4,5,6,8})), printer).str();
serialize(exists(select(t.alpha).from(t)), printer).str();
serialize(any(select(t.alpha).from(t)), printer).str();
@ -156,6 +156,7 @@ int main()
serialize(s, printer).str();
}
// distinct aggregate
serialize(count(sqlpp::distinct, t.alpha % 7), printer).str();
serialize(avg(sqlpp::distinct, t.alpha - 7), printer).str();
@ -164,5 +165,12 @@ int main()
serialize(select(all_of(t)).from(t).where(true), printer).str();
serialize(select(all_of(t)).from(t).where(false), printer).str();
for (const auto& row : db(select(all_of(t)).from(t).where(true)))
{
serialize(row.alpha, printer);
serialize(row.beta, printer);
serialize(row.gamma, printer);
}
return 0;
}

View File

@ -104,24 +104,32 @@ struct MockDbT: public sqlpp::connection
template<typename Insert>
size_t insert(const Insert& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return 0;
}
template<typename Update>
size_t update(const Update& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return 0;
}
template<typename Remove>
size_t remove(const Remove& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return 0;
}
template<typename Select>
result_t select(const Select& s)
result_t select(const Select& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return {};
}
@ -138,24 +146,32 @@ struct MockDbT: public sqlpp::connection
template<typename Insert>
_prepared_statement_t prepare_insert(Insert& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return nullptr;
}
template<typename PreparedInsert>
size_t run_prepared_insert(const PreparedInsert& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return 0;
}
template<typename Select>
_prepared_statement_t prepare_select(Select& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return nullptr;
}
template<typename PreparedSelect>
result_t run_prepared_select(PreparedSelect& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return {};
}

View File

@ -47,6 +47,20 @@ int main()
{
static_assert(sqlpp::can_be_null_t<decltype(row.alpha)>::value, "row.alpha can be null");
static_assert(sqlpp::null_is_trivial_value_t<decltype(row.alpha)>::value, "row.alpha interprets null_is_trivial");
static_assert(std::is_member_function_pointer<decltype(&decltype(row.alpha)::is_null)>::value, "Yikes");
using T = sqlpp::wrap_operand_t<decltype(row.alpha)>;
static_assert(sqlpp::can_be_null_t<T>::value, "row.alpha can be null");
static_assert(sqlpp::is_result_field_t<T>::value, "result_fields are not wrapped");
bool x = sqlpp::rhs_is_null(t.alpha == row.alpha);
bool y = sqlpp::rhs_is_trivial(t.alpha == row.alpha);
std::cerr << x << std::endl;
std::cerr << y << std::endl;
for (const auto& sub : db(select(all_of(t)).from(t).where(t.alpha == row.alpha)))
{
std::cerr << sub.alpha << std::endl;
}
}
sqlpp::select((t.alpha + 1).as(t.alpha)).flags(sqlpp::all).from(t);

View File

@ -64,6 +64,11 @@ int main()
std::cout << a << ", " << b << ", " << g << std::endl;
}
for (const auto& row : db(select(all_of(t), all_of(f)).from(t.join(f).on(t.alpha > f.omega and not t.gamma)).where(true)))
{
std::cout << row.alpha << std::endl;
}
auto stat = sqlpp::select().columns(all_of(t)).flags(sqlpp::all).from(t).extra_tables(f,t).where(t.alpha > 0).group_by(t.alpha).order_by(t.gamma.asc()).having(t.gamma).limit(7).offset(19);
auto s = dynamic_select(db).dynamic_columns(all_of(t)).dynamic_flags().dynamic_from(t).extra_tables(f,t).dynamic_where().dynamic_group_by(t.alpha).dynamic_order_by().dynamic_having(t.gamma).dynamic_limit().dynamic_offset();