diff --git a/README.md b/README.md index e26f2912..1254f173 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ This results in several benefits, e.g. The library supports both static and dynamic queries. The former offers greater benefit in terms of type and consistency checking. The latter makes it easier to construct queries on the flight. +Specific traits of databases (e.g. unsupported or non-standard features) are known at compile time as well. This way, the compiler can tell the developer at compile time if a query is not accepted by the database (e.g. if a feature is missing). And the library can form the query in the correct manner, for instance if the engine uses concat instead of operator|| to concatenate strings. + Your help is needed: -------------------- diff --git a/include/sqlpp11/column_types.h b/include/sqlpp11/column_types.h index 87943d5c..7c358dc5 100644 --- a/include/sqlpp11/column_types.h +++ b/include/sqlpp11/column_types.h @@ -28,7 +28,8 @@ #define SQLPP_COLUMN_TYPES_H #include -#include +#include +#include #include #endif diff --git a/include/sqlpp11/count.h b/include/sqlpp11/count.h index 5b88d864..f1b4d187 100644 --- a/include/sqlpp11/count.h +++ b/include/sqlpp11/count.h @@ -28,18 +28,18 @@ #define SQLPP_COUNT_H #include -#include +#include namespace sqlpp { namespace detail { template - struct count_t: public numeric::template operators> + struct count_t: public integral::template operators> { static_assert(is_value_t::value, "count() requires a sql value as argument"); - struct _value_type: public numeric + struct _value_type: public integral { using _is_named_expression = std::true_type; }; diff --git a/include/sqlpp11/detail/wrap_operand.h b/include/sqlpp11/detail/wrap_operand.h index d5ebfd94..1fb24dca 100644 --- a/include/sqlpp11/detail/wrap_operand.h +++ b/include/sqlpp11/detail/wrap_operand.h @@ -35,7 +35,8 @@ namespace sqlpp namespace detail { struct boolean; - struct numeric; + struct integral; + struct floating_point; struct text; struct bool_operand @@ -62,17 +63,41 @@ namespace sqlpp }; template - struct numeric_operand + struct integral_operand { static constexpr bool _is_expression = true; - using _value_type = numeric; + using _value_type = integral; - numeric_operand(T t): _t(t) {} - numeric_operand(const numeric_operand&) = default; - numeric_operand(numeric_operand&&) = default; - numeric_operand& operator=(const numeric_operand&) = default; - numeric_operand& operator=(numeric_operand&&) = default; - ~numeric_operand() = default; + integral_operand(T t): _t(t) {} + integral_operand(const integral_operand&) = default; + integral_operand(integral_operand&&) = default; + integral_operand& operator=(const integral_operand&) = default; + integral_operand& operator=(integral_operand&&) = default; + ~integral_operand() = default; + + template + void serialize(std::ostream& os, Db& db) const + { + os << _t; + } + + bool _is_trivial() const { return _t == 0; } + + T _t; + }; + + template + struct floating_point_operand + { + static constexpr bool _is_expression = true; + using _value_type = floating_point; + + floating_point_operand(T t): _t(t) {} + floating_point_operand(const floating_point_operand&) = default; + floating_point_operand(floating_point_operand&&) = default; + floating_point_operand& operator=(const floating_point_operand&) = default; + floating_point_operand& operator=(floating_point_operand&&) = default; + ~floating_point_operand() = default; template void serialize(std::ostream& os, Db& db) const @@ -124,7 +149,13 @@ namespace sqlpp template struct wrap_operand::value>::type> { - using type = numeric_operand; + using type = integral_operand; + }; + + template + struct wrap_operand::value>::type> + { + using type = floating_point_operand; }; template diff --git a/include/sqlpp11/numeric.h b/include/sqlpp11/floating_point.h similarity index 86% rename from include/sqlpp11/numeric.h rename to include/sqlpp11/floating_point.h index 9aabe223..b4319127 100644 --- a/include/sqlpp11/numeric.h +++ b/include/sqlpp11/floating_point.h @@ -24,8 +24,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_NUMERIC_H -#define SQLPP_NUMERIC_H +#ifndef SQLPP_FLOATING_POINT_H +#define SQLPP_FLOATING_POINT_H #include #include @@ -38,29 +38,30 @@ namespace sqlpp namespace detail { - // numeric value type - struct numeric + // floating_point value type + struct floating_point { - using _base_value_type = numeric; + using _base_value_type = floating_point; using _is_numeric = std::true_type; + using _is_floating_point = std::true_type; using _is_value = std::true_type; using _is_expression = std::true_type; template struct _result_entry_t { - using _value_type = numeric; + 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::strtoll(row.data[index], nullptr, 10)) + _value(_is_null ? 0 : std::strtod(row.data[index], nullptr)) {} _result_entry_t& operator=(const raw_result_row_t& row) { _is_valid = (row.data != nullptr); _is_null = row.data == nullptr or row.data[index] == nullptr; - _value = _is_null ? 0 : std::strtoll(row.data[index], nullptr, 10); + _value = _is_null ? 0 : std::strtod(row.data[index], nullptr); return *this; } @@ -79,42 +80,42 @@ namespace sqlpp return _is_null; } - int64_t value() const + double value() const { if (not _is_valid) throw exception("accessing value in non-existing row"); return _value; } - operator int64_t() const { return value(); } + operator double() const { return value(); } private: bool _is_valid; bool _is_null; - int64_t _value; + double _value; }; struct plus_ { - using _value_type = numeric; + using _value_type = floating_point; static constexpr const char* _name = "+"; }; struct minus_ { - using _value_type = numeric; + using _value_type = floating_point; static constexpr const char* _name = "-"; }; struct multiplies_ { - using _value_type = numeric; + using _value_type = floating_point; static constexpr const char* _name = "*"; }; struct divides_ { - using _value_type = numeric; + using _value_type = floating_point; static constexpr const char* _name = "/"; }; @@ -177,16 +178,13 @@ namespace sqlpp }; template - std::ostream& operator<<(std::ostream& os, const numeric::_result_entry_t& e) + std::ostream& operator<<(std::ostream& os, const floating_point::_result_entry_t& e) { return os << e.value(); } } - using tinyint = detail::numeric; - using smallint = detail::numeric; - using integer = detail::numeric; - using bigint = detail::numeric; + using floating_point = detail::floating_point; } #endif diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h new file mode 100644 index 00000000..33292995 --- /dev/null +++ b/include/sqlpp11/integral.h @@ -0,0 +1,196 @@ +/* + * 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_INTEGRAL_H +#define SQLPP_INTEGRAL_H + +#include +#include +#include +#include +#include + +namespace sqlpp +{ + namespace detail + { + + // integral value type + struct integral + { + using _base_value_type = integral; + using _is_numeric = std::true_type; + using _is_floating_point = std::true_type; + using _is_value = std::true_type; + using _is_expression = std::true_type; + + template + 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& operator=(const raw_result_row_t& row) + { + _is_valid = (row.data != nullptr); + _is_null = row.data == nullptr or row.data[index] == nullptr; + _value = _is_null ? 0 : std::strtoll(row.data[index], nullptr, 10); + return *this; + } + + template + void serialize(std::ostream& os, Db& db) const + { + os << value(); + } + + bool _is_trivial() const { return value() == 0; } + + bool is_null() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + return _is_null; + } + + int64_t value() const + { + if (not _is_valid) + throw exception("accessing value in non-existing row"); + return _value; + } + + operator int64_t() const { return value(); } + + private: + bool _is_valid; + bool _is_null; + int64_t _value; + }; + + template + struct plus_ + { + using _value_type = typename wrap_operand::type>::type::_value_type; + static constexpr const char* _name = "+"; + }; + + template + struct minus_ + { + using _value_type = typename wrap_operand::type>::type::_value_type; + static constexpr const char* _name = "-"; + }; + + template + struct multiplies_ + { + using _value_type = typename wrap_operand::type>::type::_value_type; + static constexpr const char* _name = "*"; + }; + + struct divides_ + { + using _value_type = floating_point; + static constexpr const char* _name = "/"; + }; + + template + using _constraint = operand_t; + + template + struct operators: public basic_operators + { + template + binary_expression_t, typename _constraint::type> operator +(T&& t) const + { + return { *static_cast(this), std::forward(t) }; + } + + template + binary_expression_t, typename _constraint::type> operator -(T&& t) const + { + return { *static_cast(this), std::forward(t) }; + } + + template + binary_expression_t, typename _constraint::type> operator *(T&& t) const + { + return { *static_cast(this), std::forward(t) }; + } + + template + binary_expression_t::type> operator /(T&& t) const + { + return { *static_cast(this), std::forward(t) }; + } + + template + auto operator +=(T&& t) const -> decltype(std::declval() = std::declval() + std::forward(t)) + { + return *static_cast(this) = operator +(std::forward(t)); + } + + template + auto operator -=(T&& t) const -> decltype(std::declval() = std::declval() - std::forward(t)) + { + return *static_cast(this) = operator -(std::forward(t)); + } + + template + auto operator /=(T&& t) const -> decltype(std::declval() = std::declval() / std::forward(t)) + { + return *static_cast(this) = operator /(std::forward(t)); + } + + template + auto operator *=(T&& t) const -> decltype(std::declval() = std::declval() * std::forward(t)) + { + return *static_cast(this) = operator *(std::forward(t)); + } + + + }; + }; + + template + std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t& e) + { + return os << e.value(); + } + } + + using tinyint = detail::integral; + using smallint = detail::integral; + using integer = detail::integral; + using bigint = detail::integral; + +} +#endif