0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +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 <sqlpp11/field_spec.h>
#include <sqlpp11/text.h>
#include <sqlpp11/detail/column_index_sequence.h>
#include <sqlpp11/detail/field_index_sequence.h>
namespace sqlpp
{
@ -66,9 +66,9 @@ namespace sqlpp
template<std::size_t index, typename AliasProvider, typename Db, typename... 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;
@ -89,12 +89,10 @@ namespace sqlpp
}
};
template<typename Db, std::size_t LastIndex, std::size_t... Is, typename... FieldSpecs>
struct result_row_impl<Db, detail::column_index_sequence<LastIndex, Is...>, FieldSpecs...>:
template<typename Db, std::size_t NextIndex, std::size_t... Is, typename... FieldSpecs>
struct result_row_impl<Db, detail::field_index_sequence<NextIndex, Is...>, FieldSpecs...>:
public result_field<Db, Is, FieldSpecs>...
{
static constexpr std::size_t _last_index = LastIndex;
result_row_impl() = default;
void _validate()
@ -120,11 +118,11 @@ namespace sqlpp
}
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;
static constexpr size_t _last_static_index = _impl::_last_index;
result_row_t():
_impl(),
@ -168,7 +166,7 @@ namespace sqlpp
static constexpr size_t static_size()
{
return _last_static_index;
return _field_index_sequence::_next_index;
}
template<typename Target>
@ -179,9 +177,10 @@ namespace sqlpp
};
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
{
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 {};
};
using _field_type = result_field_t<text, Db, _field_spec_t>;
static constexpr size_t _last_static_index = _impl::_last_index;
bool _is_valid;
std::vector<std::string> _dynamic_columns;
std::vector<std::string> _dynamic_field_names;
std::map<std::string, _field_type> _dynamic_fields;
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(),
_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{}});
}
@ -259,10 +257,11 @@ namespace sqlpp
{
_impl::_bind(target);
std::size_t index = _last_static_index;
for (const auto& name : _dynamic_columns)
std::size_t index = _field_index_sequence::_next_index;
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");
}
// 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 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()");
}
// 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 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");
}
// 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
{
auto a = select(t.alpha);