diff --git a/.clang-format b/.clang-format index 1d9d0f26..c0ffae25 100644 --- a/.clang-format +++ b/.clang-format @@ -51,3 +51,4 @@ CommentPragmas: '^ IWYU pragma:' ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] SpaceBeforeParens: ControlStatements DisableFormat: false +SortIncludes: false diff --git a/.travis.yml b/.travis.yml index c9d8325d..222c4842 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,8 @@ os: - linux - osx -osx_image: xcode7 +dist: trusty +sudo: required compiler: - clang @@ -12,7 +13,7 @@ compiler: env: - CONFIG=Release - - CONFIG=Debug + #- CONFIG=Debug notifications: email: @@ -20,29 +21,12 @@ notifications: on_failure: always install: - - CMAKE_VERSION_MM=3.2 - - CMAKE_VERSION_FULL=$CMAKE_VERSION_MM.2 + - g++ --version + - cmake --version - git clone https://github.com/HowardHinnant/date - cd date - git checkout tags/v1.0.0 - cd .. - - if [ "$TRAVIS_OS_NAME" == "linux" ]; then - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - && sudo add-apt-repository -y ppa:apokluda/boost1.53 - && sudo apt-get update -qq - && sudo apt-get install -qq g++-4.8 libboost1.53-dev --no-install-recommends - && sudo update-alternatives --quiet --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.6 --slave /usr/bin/gcov gcov /usr/bin/gcov-4.6 - && sudo update-alternatives --quiet --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 40 --slave /usr/bin/g++ g++ /usr/bin/g++-4.8 --slave /usr/bin/gcov gcov /usr/bin/gcov-4.8 - && sudo update-alternatives --quiet --set gcc /usr/bin/gcc-4.8 - && wget --no-check-certificate http://www.cmake.org/files/v${CMAKE_VERSION_MM}/cmake-${CMAKE_VERSION_FULL}-Linux-x86_64.sh - && sudo sh cmake-${CMAKE_VERSION_FULL}-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir; - fi - - if [ "$TRAVIS_OS_NAME" = "osx" ]; then - brew update - && ((brew list -1 | grep -q "^$cmake\$") || brew install cmake) - && (brew outdated cmake || brew upgrade cmake) - && cmake --version; - fi before_script: - mkdir build diff --git a/include/sqlpp11/alias_provider.h b/include/sqlpp11/alias_provider.h index 38bbf528..3c1abbd4 100644 --- a/include/sqlpp11/alias_provider.h +++ b/include/sqlpp11/alias_provider.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Roland Bock + * Copyright (c) 2013-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -89,6 +89,7 @@ namespace sqlpp SQLPP_ALIAS_PROVIDER(o) SQLPP_ALIAS_PROVIDER(p) SQLPP_ALIAS_PROVIDER(q) + SQLPP_ALIAS_PROVIDER(r) SQLPP_ALIAS_PROVIDER(s) SQLPP_ALIAS_PROVIDER(t) SQLPP_ALIAS_PROVIDER(u) diff --git a/include/sqlpp11/basic_expression_operators.h b/include/sqlpp11/basic_expression_operators.h index 98e9bae2..ffa56525 100644 --- a/include/sqlpp11/basic_expression_operators.h +++ b/include/sqlpp11/basic_expression_operators.h @@ -187,14 +187,19 @@ namespace sqlpp return {*static_cast(this)}; } - auto asc() const -> sort_order_t + auto asc() const -> sort_order_t { - return {*static_cast(this)}; + return {*static_cast(this), sort_type::asc}; } - auto desc() const -> sort_order_t + auto desc() const -> sort_order_t { - return {*static_cast(this)}; + return {*static_cast(this), sort_type::desc}; + } + + auto order(sort_type s) const -> sort_order_t + { + return {*static_cast(this), s}; } template diff --git a/include/sqlpp11/data_types/integral/expression_operators.h b/include/sqlpp11/data_types/integral/expression_operators.h index 445703b5..71e7a876 100644 --- a/include/sqlpp11/data_types/integral/expression_operators.h +++ b/include/sqlpp11/data_types/integral/expression_operators.h @@ -53,7 +53,7 @@ namespace sqlpp struct return_type_plus> { using check = consistent_t; - using type = integral; + using type = plus_t, integral, wrap_operand_t>; }; template @@ -67,7 +67,7 @@ namespace sqlpp struct return_type_minus> { using check = consistent_t; - using type = integral; + using type = minus_t, integral, wrap_operand_t>; }; template @@ -81,7 +81,7 @@ namespace sqlpp struct return_type_multiplies> { using check = consistent_t; - using type = integral; + using type = multiplies_t, integral, wrap_operand_t>; }; template @@ -95,7 +95,7 @@ namespace sqlpp struct return_type_divides> { using check = consistent_t; - using type = integral; + using type = divides_t, wrap_operand_t>; }; template diff --git a/include/sqlpp11/data_types/unsigned_integral/expression_operators.h b/include/sqlpp11/data_types/unsigned_integral/expression_operators.h index 1c016102..bb5730b7 100644 --- a/include/sqlpp11/data_types/unsigned_integral/expression_operators.h +++ b/include/sqlpp11/data_types/unsigned_integral/expression_operators.h @@ -38,7 +38,7 @@ namespace sqlpp { struct integral; - + template struct expression_operators : public basic_expression_operators { diff --git a/include/sqlpp11/field_spec.h b/include/sqlpp11/field_spec.h index ac862b58..53d6189f 100644 --- a/include/sqlpp11/field_spec.h +++ b/include/sqlpp11/field_spec.h @@ -46,6 +46,46 @@ namespace sqlpp template struct multi_field_spec_t { + static_assert(wrong_t::value, + "multi_field_spec_t needs to be specialized with a tuple"); + }; + + template + struct multi_field_spec_t> + { + }; + + template + struct is_field_compatible + { + static constexpr auto value = false; + }; + + template + struct is_field_compatible, + field_spec_t> + { + static constexpr auto value = + std::is_same::value and + std::is_same::value and // Same value type + (LeftCanBeNull or !RightCanBeNull) and // The left hand side determines the result row and therefore must allow + // NULL if the right hand side allows it + (LeftNullIsTrivial or !RightNullIsTrivial); // as above + }; + + template + struct is_field_compatible>, + multi_field_spec_t>, + typename std::enable_if::type> + { + static constexpr auto value = logic::all_t::value...>::value; }; namespace detail diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 59397496..8c620322 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -251,6 +251,20 @@ namespace sqlpp } }; + template + struct is_result_compatible + { + static constexpr auto value = false; + }; + + template + struct is_result_compatible, + result_row_t, + typename std::enable_if::type> + { + static constexpr auto value = logic::all_t::value...>::value; + }; + template struct dynamic_result_row_t : public detail::result_row_impl, FieldSpecs...> diff --git a/include/sqlpp11/select_column_list.h b/include/sqlpp11/select_column_list.h index 8059eef6..ae29d52f 100644 --- a/include/sqlpp11/select_column_list.h +++ b/include/sqlpp11/select_column_list.h @@ -376,7 +376,7 @@ namespace sqlpp template static constexpr auto _check_args(T... args) -> decltype(_check_tuple(detail::column_tuple_merge(args...))) { - return {}; + return _check_tuple(detail::column_tuple_merge(args...)); } template diff --git a/include/sqlpp11/sort_order.h b/include/sqlpp11/sort_order.h index 391898dd..4ef59e5e 100644 --- a/include/sqlpp11/sort_order.h +++ b/include/sqlpp11/sort_order.h @@ -39,25 +39,26 @@ namespace sqlpp desc }; - template + template struct sort_order_t { using _traits = make_traits; using _nodes = detail::type_vector; Expression _expression; + sort_type _sort_type; }; - template - struct serializer_t> + template + struct serializer_t> { using _serialize_check = serialize_check_of; - using T = sort_order_t; + using T = sort_order_t; static Context& _(const T& t, Context& context) { serialize_operand(t._expression, context); - switch (SortType) + switch (t._sort_type) { case sort_type::asc: context << " ASC"; diff --git a/include/sqlpp11/union.h b/include/sqlpp11/union.h index e113ea16..dd15400d 100644 --- a/include/sqlpp11/union.h +++ b/include/sqlpp11/union.h @@ -213,10 +213,10 @@ namespace sqlpp static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a complete select statement or union"); - using _result_row_t = get_result_row_t; - static_assert(std::is_same>, _result_row_t>::value, + using lhs_result_row_t = get_result_row_t>; + using rhs_result_row_t = get_result_row_t; + static_assert(is_result_compatible::value, "both arguments in a union have to have the same result columns (type and name)"); - static_assert(is_static_result_row_t<_result_row_t>::value, "unions must not have dynamically added columns"); return _union_impl(check_union_t, Rhs>{}, rhs); } @@ -231,10 +231,10 @@ namespace sqlpp static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a (complete) select statement"); - using _result_row_t = get_result_row_t; - static_assert(std::is_same>, _result_row_t>::value, + using lhs_result_row_t = get_result_row_t>; + using rhs_result_row_t = get_result_row_t; + static_assert(is_result_compatible::value, "both arguments in a union have to have the same result columns (type and name)"); - static_assert(is_static_result_row_t<_result_row_t>::value, "unions must not have dynamically added columns"); return _union_impl(check_union_t, Rhs>{}, rhs); } @@ -253,6 +253,7 @@ namespace sqlpp }; }; + /* template auto union_all(T&& t) -> decltype(statement_t().union_all(std::forward(t))) { @@ -264,6 +265,7 @@ namespace sqlpp { return statement_t().union_distinct(std::forward(t)); } + */ } #endif diff --git a/test_serializer/As.cpp b/test_serializer/As.cpp new file mode 100644 index 00000000..76c4dcfa --- /dev/null +++ b/test_serializer/As.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016-2016, 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 "compare.h" +#include "Sample.h" +#include + +#include + +SQLPP_ALIAS_PROVIDER(cheese); + +int As(int, char* []) +{ + const auto foo = test::TabFoo{}; + const auto bar = test::TabBar{}; + + compare(__LINE__, foo.omega.as(cheese), "tab_foo.omega AS cheese"); + compare(__LINE__, (foo.omega + 17).as(cheese), "(tab_foo.omega+17) AS cheese"); + compare(__LINE__, (foo.omega - 17).as(cheese), "(tab_foo.omega-17) AS cheese"); + compare(__LINE__, (foo.omega - uint32_t(17)).as(cheese), "(tab_foo.omega-17) AS cheese"); + compare(__LINE__, (foo.omega - bar.alpha).as(cheese), "(tab_foo.omega-tab_bar.alpha) AS cheese"); + compare(__LINE__, (count(foo.omega) - bar.alpha).as(cheese), "(COUNT(tab_foo.omega)-tab_bar.alpha) AS cheese"); + compare(__LINE__, (count(foo.omega) - uint32_t(17)).as(cheese), "(COUNT(tab_foo.omega)-17) AS cheese"); + + return 0; +} diff --git a/test_serializer/CMakeLists.txt b/test_serializer/CMakeLists.txt index b00c6860..07add5a0 100644 --- a/test_serializer/CMakeLists.txt +++ b/test_serializer/CMakeLists.txt @@ -24,11 +24,12 @@ set(test_serializer_names CustomQuery + As From In Insert - Where TableAlias + Where ) create_test_sourcelist(test_serializer_sources test_serializer_main.cpp ${test_serializer_names}) diff --git a/test_serializer/CustomQuery.cpp b/test_serializer/CustomQuery.cpp index e4afaeb2..4c00aec5 100644 --- a/test_serializer/CustomQuery.cpp +++ b/test_serializer/CustomQuery.cpp @@ -57,9 +57,11 @@ int CustomQuery(int, char* []) custom_query(sqlpp::select(), dynamic_select_flags(db, sqlpp::distinct), dynamic_select_columns(db, foo.omega), dynamic_from(db, foo.join(bar).on(foo.omega == bar.alpha)), dynamic_where(db, bar.alpha > 17), dynamic_group_by(db, foo.omega), dynamic_having(db, avg(bar.alpha) > 19), - dynamic_order_by(db, foo.omega.asc()), sqlpp::dynamic_limit(db), sqlpp::dynamic_offset(db)), + dynamic_order_by(db, foo.omega.asc(), foo.psi.order(sqlpp::sort_type::desc)), + sqlpp::dynamic_limit(db), sqlpp::dynamic_offset(db)), "SELECT DISTINCT tab_foo.omega FROM tab_foo INNER JOIN tab_bar ON (tab_foo.omega=tab_bar.alpha) WHERE " - "(tab_bar.alpha>17) GROUP BY tab_foo.omega HAVING (AVG(tab_bar.alpha)>19) ORDER BY tab_foo.omega ASC "); + "(tab_bar.alpha>17) GROUP BY tab_foo.omega HAVING (AVG(tab_bar.alpha)>19) ORDER BY tab_foo.omega " + "ASC,tab_foo.psi DESC "); // A pragma query for sqlite compare(__LINE__, diff --git a/tests/Select.cpp b/tests/Select.cpp index 4b99b3a7..268488f2 100644 --- a/tests/Select.cpp +++ b/tests/Select.cpp @@ -160,6 +160,7 @@ int Select(int, char* []) s.offset.set(3u); s.group_by.add(t.beta); s.order_by.add(t.beta.asc()); + s.order_by.add(t.delta.order(sqlpp::sort_type::desc)); for (const auto& row : db(s)) { int64_t a = row.alpha; diff --git a/tests/SelectType.cpp b/tests/SelectType.cpp index 9dc7d845..f0781007 100644 --- a/tests/SelectType.cpp +++ b/tests/SelectType.cpp @@ -167,7 +167,8 @@ int SelectType(int, char* []) static_assert(sqlpp::is_integral_t>::value, "type requirement"); static_assert(sqlpp::is_integral_t>::value, "type requirement"); static_assert(sqlpp::is_integral_t>::value, "type requirement"); - static_assert(sqlpp::is_integral_t>::value, "type requirement"); + static_assert(sqlpp::is_floating_point_t>::value, + "type requirement"); static_assert(sqlpp::is_integral_t>::value, "type requirement"); } diff --git a/tests/Union.cpp b/tests/Union.cpp index b896cf94..d4eb541e 100644 --- a/tests/Union.cpp +++ b/tests/Union.cpp @@ -29,6 +29,12 @@ #include #include +namespace greek +{ + SQLPP_ALIAS_PROVIDER(alpha) + SQLPP_ALIAS_PROVIDER(beta) +} + int Union(int, char* []) { MockDb db; @@ -40,6 +46,15 @@ int Union(int, char* []) db(select(t.alpha).from(t).unconditionally().union_distinct(select(f.epsilon.as(t.alpha)).from(f).unconditionally())); db(select(t.alpha).from(t).unconditionally().union_all(select(f.epsilon.as(t.alpha)).from(f).unconditionally())); + // t.alpha can be null, a given value cannot + db(select(t.alpha).from(t).unconditionally().union_all(select(sqlpp::value(1).as(t.alpha)))); + db(select(t.alpha).from(t).unconditionally().union_all(select(sqlpp::value(1).as(greek::alpha)))); + + // t.beta can be null, f.delta cannot + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(!sqlpp::can_be_null_t::value, ""); + db(select(t.beta).from(t).unconditionally().union_all(select(f.delta.as(greek::beta)).from(f).unconditionally())); + auto u = select(t.alpha) .from(t) .unconditionally()