0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 04:47:18 +08:00

Fixed bug in field index calculation for multi_fields

This commit is contained in:
rbock 2014-08-09 20:46:40 +02:00
parent ce0c344d0a
commit a59d7ed381
4 changed files with 109 additions and 93 deletions

View File

@ -1,70 +0,0 @@
/*
* 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_DETAIL_COLUMN_INDEX_SEQUENCE_H
#define SQLPP_DETAIL_COLUMN_INDEX_SEQUENCE_H
#include <type_traits>
namespace sqlpp
{
namespace detail
{
template<std::size_t LastIndex, std::size_t... Ints>
struct column_index_sequence
{
static constexpr std::size_t last_index = LastIndex;
};
template<typename T, typename... Fields>
struct make_column_index_sequence_impl;
template<std::size_t LastIndex, std::size_t... Ints, typename Column, typename... Rest>
struct make_column_index_sequence_impl<column_index_sequence<LastIndex, Ints...>, Column, Rest...>
{
using type = typename make_column_index_sequence_impl<column_index_sequence<LastIndex + 1, Ints..., LastIndex + 1>, Rest...>::type;
};
template<std::size_t LastIndex, std::size_t... Ints, typename AliasProvider, typename... Fields, typename... Rest>
struct make_column_index_sequence_impl<column_index_sequence<LastIndex, Ints...>, multi_field_spec_t<AliasProvider, Fields...>, Rest...>
{
using type = typename make_column_index_sequence_impl<column_index_sequence<LastIndex + sizeof...(Fields), Ints..., LastIndex + sizeof...(Fields)>, Rest...>::type;
};
template<std::size_t LastIndex, std::size_t... Ints>
struct make_column_index_sequence_impl<column_index_sequence<LastIndex, Ints...>>
{
using type = column_index_sequence<LastIndex, Ints...>;
};
template<std::size_t StartIndex, typename... Fields>
using make_column_index_sequence = typename make_column_index_sequence_impl<column_index_sequence<StartIndex - 1>, Fields...>::type;
}
}
#endif

View File

@ -0,0 +1,74 @@
/*
* 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_DETAIL_FIELD_INDEX_SEQUENCE_H
#define SQLPP_DETAIL_FIELD_INDEX_SEQUENCE_H
#include <type_traits>
#include <sqlpp11/field_spec.h>
namespace sqlpp
{
namespace detail
{
template<std::size_t NextIndex, std::size_t... Ints>
struct field_index_sequence
{
static constexpr std::size_t _next_index = NextIndex;
};
template<typename T, typename... Fields>
struct make_field_index_sequence_impl
{
static_assert(wrong_t<make_field_index_sequence_impl>::value, "invalid field index sequence arguments");
};
template<std::size_t NextIndex, std::size_t... Ints, typename NameType, typename ValueType, bool CanBeNull, bool NullIsTrivialValue, typename... Rest>
struct make_field_index_sequence_impl<field_index_sequence<NextIndex, Ints...>, field_spec_t<NameType, ValueType, CanBeNull, NullIsTrivialValue>, Rest...>
{
using type = typename make_field_index_sequence_impl<field_index_sequence<NextIndex + 1, Ints..., NextIndex>, Rest...>::type;
};
template<std::size_t NextIndex, std::size_t... Ints, typename AliasProvider, typename FieldTuple, typename... Rest>
struct make_field_index_sequence_impl<field_index_sequence<NextIndex, Ints...>, multi_field_spec_t<AliasProvider, FieldTuple>, Rest...>
{
using type = typename make_field_index_sequence_impl<field_index_sequence<NextIndex + std::tuple_size<FieldTuple>::value, Ints..., NextIndex>, Rest...>::type;
};
template<std::size_t NextIndex, std::size_t... Ints>
struct make_field_index_sequence_impl<field_index_sequence<NextIndex, Ints...>>
{
using type = field_index_sequence<NextIndex, Ints...>;
};
template<std::size_t StartIndex, typename... Fields>
using make_field_index_sequence = typename make_field_index_sequence_impl<field_index_sequence<StartIndex>, Fields...>::type;
}
}
#endif

View File

@ -30,7 +30,7 @@
#include <map> #include <map>
#include <sqlpp11/field_spec.h> #include <sqlpp11/field_spec.h>
#include <sqlpp11/text.h> #include <sqlpp11/text.h>
#include <sqlpp11/detail/column_index_sequence.h> #include <sqlpp11/detail/field_index_sequence.h>
namespace sqlpp namespace sqlpp
{ {
@ -66,9 +66,9 @@ namespace sqlpp
template<std::size_t index, typename AliasProvider, typename Db, typename... FieldSpecs> template<std::size_t index, typename AliasProvider, typename Db, typename... FieldSpecs>
struct result_field<Db, index, multi_field_spec_t<AliasProvider, std::tuple<FieldSpecs...>>>: struct result_field<Db, index, multi_field_spec_t<AliasProvider, std::tuple<FieldSpecs...>>>:
public AliasProvider::_name_t::template _member_t<result_row_impl<Db, detail::make_column_index_sequence<index, FieldSpecs...>, FieldSpecs...>> public AliasProvider::_name_t::template _member_t<result_row_impl<Db, detail::make_field_index_sequence<index, FieldSpecs...>, FieldSpecs...>>
{ {
using _multi_field = typename AliasProvider::_name_t::template _member_t<result_row_impl<Db, detail::make_column_index_sequence<index, FieldSpecs...>, FieldSpecs...>>; using _multi_field = typename AliasProvider::_name_t::template _member_t<result_row_impl<Db, detail::make_field_index_sequence<index, FieldSpecs...>, FieldSpecs...>>;
result_field() = default; result_field() = default;
@ -89,12 +89,10 @@ namespace sqlpp
} }
}; };
template<typename Db, std::size_t LastIndex, std::size_t... Is, typename... FieldSpecs> template<typename Db, std::size_t NextIndex, std::size_t... Is, typename... FieldSpecs>
struct result_row_impl<Db, detail::column_index_sequence<LastIndex, Is...>, FieldSpecs...>: struct result_row_impl<Db, detail::field_index_sequence<NextIndex, Is...>, FieldSpecs...>:
public result_field<Db, Is, FieldSpecs>... public result_field<Db, Is, FieldSpecs>...
{ {
static constexpr std::size_t _last_index = LastIndex;
result_row_impl() = default; result_row_impl() = default;
void _validate() void _validate()
@ -120,11 +118,11 @@ namespace sqlpp
} }
template<typename Db, typename... FieldSpecs> template<typename Db, typename... FieldSpecs>
struct result_row_t: public detail::result_row_impl<Db, detail::make_column_index_sequence<0, FieldSpecs...>, FieldSpecs...> struct result_row_t: public detail::result_row_impl<Db, detail::make_field_index_sequence<0, FieldSpecs...>, FieldSpecs...>
{ {
using _impl = detail::result_row_impl<Db, detail::make_column_index_sequence<0, FieldSpecs...>, FieldSpecs...>; using _field_index_sequence = detail::make_field_index_sequence<0, FieldSpecs...>;
using _impl = detail::result_row_impl<Db, _field_index_sequence, FieldSpecs...>;
bool _is_valid; bool _is_valid;
static constexpr size_t _last_static_index = _impl::_last_index;
result_row_t(): result_row_t():
_impl(), _impl(),
@ -168,7 +166,7 @@ namespace sqlpp
static constexpr size_t static_size() static constexpr size_t static_size()
{ {
return _last_static_index; return _field_index_sequence::_next_index;
} }
template<typename Target> template<typename Target>
@ -179,9 +177,10 @@ namespace sqlpp
}; };
template<typename Db, typename... FieldSpecs> template<typename Db, typename... FieldSpecs>
struct dynamic_result_row_t: public detail::result_row_impl<Db, detail::make_column_index_sequence<0, FieldSpecs...>, FieldSpecs...> struct dynamic_result_row_t: public detail::result_row_impl<Db, detail::make_field_index_sequence<0, FieldSpecs...>, FieldSpecs...>
{ {
using _impl = detail::result_row_impl<Db, detail::make_column_index_sequence<0, FieldSpecs...>, FieldSpecs...>; using _field_index_sequence = detail::make_field_index_sequence<0, FieldSpecs...>;
using _impl = detail::result_row_impl<Db, _field_index_sequence, FieldSpecs...>;
struct _field_spec_t struct _field_spec_t
{ {
using _traits = make_traits<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>;
@ -190,10 +189,9 @@ namespace sqlpp
struct _name_t {}; struct _name_t {};
}; };
using _field_type = result_field_t<text, 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; bool _is_valid;
std::vector<std::string> _dynamic_columns; std::vector<std::string> _dynamic_field_names;
std::map<std::string, _field_type> _dynamic_fields; std::map<std::string, _field_type> _dynamic_fields;
dynamic_result_row_t(): dynamic_result_row_t():
@ -202,12 +200,12 @@ namespace sqlpp
{ {
} }
dynamic_result_row_t(const std::vector<std::string>& dynamic_columns): dynamic_result_row_t(const std::vector<std::string>& dynamic_field_names):
_impl(), _impl(),
_is_valid(false), _is_valid(false),
_dynamic_columns(dynamic_columns) _dynamic_field_names(dynamic_field_names)
{ {
for (auto name : _dynamic_columns) for (auto name : _dynamic_field_names)
{ {
_dynamic_fields.insert({name, _field_type{}}); _dynamic_fields.insert({name, _field_type{}});
} }
@ -259,10 +257,11 @@ namespace sqlpp
{ {
_impl::_bind(target); _impl::_bind(target);
std::size_t index = _last_static_index; std::size_t index = _field_index_sequence::_next_index;
for (const auto& name : _dynamic_columns) for (const auto& name : _dynamic_field_names)
{ {
_dynamic_fields.at(name)._bind(target, ++index); _dynamic_fields.at(name)._bind(target, index);
++index;
} }
} }
}; };

View File

@ -270,7 +270,7 @@ int main()
static_assert(sqlpp::is_regular<T>::value, "type requirement"); static_assert(sqlpp::is_regular<T>::value, "type requirement");
} }
// Test that select(all_of(tab)) is expanded in select // Test that all_of(tab) is expanded in select
{ {
auto a = select(all_of(t)); auto a = select(all_of(t));
auto b = select(t.alpha, t.beta, t.gamma, t.delta); auto b = select(t.alpha, t.beta, t.gamma, t.delta);
@ -279,7 +279,7 @@ int main()
//static_assert(std::is_same<decltype(b), decltype(c)>::value, "t has to be expanded by select()"); //static_assert(std::is_same<decltype(b), decltype(c)>::value, "t has to be expanded by select()");
} }
// Test that select(all_of(tab)) is expanded in multi_column // Test that all_of(tab) is expanded in multi_column
{ {
auto a = multi_column(all_of(t)).as(alias::a); auto a = multi_column(all_of(t)).as(alias::a);
auto b = multi_column(t.alpha, t.beta, t.gamma, t.delta).as(alias::a); auto b = multi_column(t.alpha, t.beta, t.gamma, t.delta).as(alias::a);
@ -292,6 +292,19 @@ int main()
static_assert(not sqlpp::is_expression_t<decltype(m)>::value, "a multi_column is not a value"); static_assert(not sqlpp::is_expression_t<decltype(m)>::value, "a multi_column is not a value");
} }
// Test result field indices
{
using Select = decltype(select(
all_of(t), // index 0, 1, 2, 3 (alpha, beta, gamma, delta)
multi_column(all_of(t)).as(alias::left), // index 4 (including 4, 5, 6, 7)
multi_column(all_of(t)).as(alias::right), // index 8 (including 8, 9, 10, 11)
t.alpha.as(alias::a) // index 12
).from(t).where(true)); // next index is 13
using ResultRow = typename Select::_result_methods_t::template _result_row_t<MockDb>;
using IndexSequence = ResultRow::_field_index_sequence;
static_assert(std::is_same<IndexSequence, sqlpp::detail::field_index_sequence<13, 0, 1, 2, 3, 4, 8, 12>>::value, "invalid field sequence");
}
// Test that result sets with identical name/value combinations have identical types // Test that result sets with identical name/value combinations have identical types
{ {
auto a = select(t.alpha); auto a = select(t.alpha);