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

Introduce optional, string_view, and span

sqlpp::optional is an alias for std::optional for C++17 and beyond.
Otherwise, it is a simple and incomplete backport.
For older versions of C++, the library offers simple back

Similar for string_view and span.
This commit is contained in:
Roland Bock 2024-04-13 12:04:41 +02:00
parent f6cb4d311a
commit bda77c620b
89 changed files with 1245 additions and 1721 deletions

View File

@ -0,0 +1,247 @@
#pragma once
/*
* Copyright (c) 2024, 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.
*/
#ifdef _MSVC_LANG
#define CXX_STD_VER _MSVC_LANG
#else
#define CXX_STD_VER __cplusplus
#endif
#if CXX_STD_VER >= 201703L
#include <optional>
namespace sqlpp
{
template <class T>
using optional = std::optional<T>;
using std::nullopt_t;
using std::nullopt;
using std::bad_optional_access;
} // namespace sqlpp
#else // incomplete backport of std::optional
#include <utility>
#include <stdexcept>
namespace sqlpp
{
class nullopt_t
{
};
constexpr nullopt_t nullopt;
class bad_optional_access : public std::exception
{
public:
~bad_optional_access() override = default;
const char* what() const noexcept override
{
return "bad optional access";
}
};
template <class T>
class optional
{
// Unnamed union, injecting members into scope.
union
{
char _nothing;
T _value;
};
bool _active = false;
// Placement new
template<typename... Args>
void create(Args&&... args)
{
new ((void*)std::addressof(_value)) T(std::forward<Args>(args)...);
_active = true;
}
void destroy()
{
if (_active)
{
_value.~T();
}
}
public:
optional() noexcept : _nothing(), _active(false)
{
}
optional(T t) : _active(true)
{
create(std::move(t));
}
optional(const optional&) = default;
optional(optional&&) = default;
optional(const nullopt_t&) noexcept
{
}
optional& operator=(const optional&) = default;
optional& operator=(optional&&) = default;
optional& operator=(const nullopt_t&) noexcept
{
destroy();
}
~optional() {
destroy();
}
bool has_value() const
{
return _active;
}
explicit operator bool() const
{
return _active;
}
T& operator*()
{
return _value;
}
const T& operator*() const
{
return _value;
}
const T& operator->() const
{
return _value;
}
template<typename... Args>
optional& emplace(Args&&... args) {
create(std::forward<Args>(args)...);
}
T& value()
{
if (_active)
return _value;
throw bad_optional_access();
}
template<typename U>
T value_or(U&& u)
{
if (_active)
return _value;
return std::forward<U>(u);
}
const T& value() const
{
if (_active)
return _value;
throw bad_optional_access();
}
void reset()
{
destroy();
}
};
template <class L, class R>
bool operator==(const optional<L>& left, const optional<R>& right)
{
if (static_cast<bool>(left) != static_cast<bool>(right))
return false;
if (!static_cast<bool>(left))
return true;
return *left == *right;
}
template <class L, class R>
bool operator==(const optional<L>& left, const R& right)
{
if (!static_cast<bool>(left))
return false;
return *left == right;
}
template <class L, class R>
bool operator==(const L& left, const optional<R>& right)
{
if (!static_cast<bool>(right))
return false;
return left == *right;
}
template <class L, class R>
bool operator!=(const optional<L>& left, const optional<R>& right)
{
if (static_cast<bool>(left) != static_cast<bool>(right))
return true;
if (!static_cast<bool>(left))
return false;
return *left != *right;
}
template <class L, class R>
bool operator!=(const optional<L>& left, const R& right)
{
if (!static_cast<bool>(left))
return true;
return *left != right;
}
template <class L, class R>
bool operator!=(const L& left, const optional<R>& right)
{
if (!static_cast<bool>(right))
return true;
return left != *right;
}
template<class T>
bool operator==(const optional<T>& left, const nullopt_t&)
{
return !left;
}
template<class T>
bool operator==(const nullopt_t& n, const optional<T>& right)
{
return !right;
}
} // namespace sqlpp
#endif

View File

@ -1,7 +1,7 @@
#pragma once
/*
* Copyright (c) 2013-2015, Roland Bock
* Copyright (c) 2024, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@ -26,28 +26,52 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/data_types/integral/data_type.h>
#include <sqlpp11/field_spec.h>
#ifdef _MSVC_LANG
#define CXX_STD_VER _MSVC_LANG
#else
#define CXX_STD_VER __cplusplus
#endif
#if CXX_STD_VER >= 202002L
#include <span>
namespace sqlpp
{
template<typename T>
using span = std::span<T>;
} // namespace sqlpp
#else // incomplete backport of std::span
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, integral, CanBeNull>>
: public result_field_base<Db, field_spec_t<NameType, integral, CanBeNull>>
template <typename T>
class span
{
template <typename Target>
void _bind(Target& target, size_t index)
const T* _data = nullptr;
size_t _size = 0u;
public:
constexpr span() = default;
constexpr span(const T* data, size_t size) : _data(data), _size(size)
{
target._bind_integral_result(index, &this->_value, &this->_is_null);
}
template <typename Target>
void _post_bind(Target& target, size_t index)
const char* data() const
{
target._post_bind_integral_result(index, &this->_value, &this->_is_null);
return _data;
}
size_t size() const
{
return _size;
}
const T& operator[](size_t i) const
{
return *(_data + i);
}
};
} // namespace sqlpp
#endif

View File

@ -0,0 +1,106 @@
#pragma once
/*
* Copyright (c) 2024, 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.
*/
#ifdef _MSVC_LANG
#define CXX_STD_VER _MSVC_LANG
#else
#define CXX_STD_VER __cplusplus
#endif
#if CXX_STD_VER >= 201703L
#include <string_view>
namespace sqlpp
{
using string_view = std::string_view;
} // namespace sqlpp
#else // incomplete backport of std::string_view
#include <utility>
#include <string>
#include <iosfwd>
namespace sqlpp
{
class string_view
{
const char* _data = nullptr;
size_t _size = 0u;
public:
constexpr string_view() = default;
string_view(const std::string& source) : _data(source.data()), _size(source.size())
{
}
constexpr string_view(const char* data, size_t size) : _data(data), _size(size)
{
}
string_view(const char* data) : _data(data), _size(std::char_traits<char>::length(data))
{
}
const char* data() const
{
return _data;
}
size_t size() const
{
return _size;
}
operator std::string() const
{
return std::string(_data, _size);
}
};
inline bool operator==(const string_view& left, const string_view& right)
{
if (left.size() != right.size())
return false;
return std::char_traits<char>::compare(left.data(), right.data(), left.size()) == 0;
}
inline bool operator!=(const string_view& left, const string_view& right)
{
if (left.size() != right.size())
return true;
return std::char_traits<char>::compare(left.data(), right.data(), left.size()) != 0;
}
inline std::ostream& operator<<(std::ostream& os, const string_view& sv)
{
return os << std::string(sv);
}
} // namespace sqlpp
#endif

View File

@ -32,7 +32,6 @@
#include <sqlpp11/data_types/blob/expression_operators.h>
#include <sqlpp11/data_types/blob/column_operators.h>
#include <sqlpp11/data_types/blob/parameter_value.h>
#include <sqlpp11/data_types/blob/result_field.h>
// blob specific functions
#include <sqlpp11/data_types/text/like.h>

View File

@ -30,6 +30,7 @@
#include <cstdint>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/compat/span.h>
#include <sqlpp11/logic.h>
namespace sqlpp
@ -38,6 +39,7 @@ namespace sqlpp
{
using _traits = make_traits<blob, tag::is_value_type>;
using _cpp_value_type = std::vector<std::uint8_t>;
using _result_type = sqlpp::span<std::uint8_t>;
template <typename T>
using _is_valid_operand = ::sqlpp::logic::any_t<is_blob_t<T>::value, is_text_t<T>::value>;

View File

@ -1,84 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2017, 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 <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/data_types/blob/data_type.h>
#include <sqlpp11/field_spec.h>
#include <ostream>
#include <string>
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, blob, CanBeNull>>
: public result_field_base<Db, field_spec_t<NameType, blob, CanBeNull>>
{
const uint8_t* blob{nullptr}; // Non-owning
size_t len{};
template <typename Target>
void _bind(Target& target, size_t index)
{
target._bind_blob_result(index, &blob, &len);
if (blob)
this->_value.assign(blob, blob + len);
else
this->_value.clear();
this->_is_null = (blob == nullptr);
}
template <typename Target>
void _post_bind(Target& target, size_t index)
{
target._post_bind_blob_result(index, &blob, &len);
if (blob)
this->_value.assign(blob, blob + len);
else
this->_value.clear();
this->_is_null = (blob == nullptr);
}
};
template <typename Db, typename NameType, bool CanBeNull>
inline std::ostream& operator<<(
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, blob, CanBeNull>>& e)
{
if (e.is_null())
{
return os << "NULL";
}
else
{
std::vector<uint8_t> value = e.value();
std::string value_str(value.begin(), value.end());
return os << value_str;
}
}
} // namespace sqlpp

View File

@ -32,4 +32,3 @@
#include <sqlpp11/data_types/boolean/expression_operators.h>
#include <sqlpp11/data_types/boolean/column_operators.h>
#include <sqlpp11/data_types/boolean/parameter_value.h>
#include <sqlpp11/data_types/boolean/result_field.h>

View File

@ -34,6 +34,7 @@ namespace sqlpp
{
using _traits = make_traits<boolean, tag::is_value_type>;
using _cpp_value_type = bool;
using _result_type = bool;
template <typename T>
using _is_valid_operand = is_boolean_t<T>;

View File

@ -1,53 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2015, 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 <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/data_types/boolean/data_type.h>
#include <sqlpp11/field_spec.h>
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, boolean, CanBeNull>>
: public result_field_base<Db, field_spec_t<NameType, boolean, CanBeNull>, signed char>
{
template <typename Target>
void _bind(Target& target, size_t index)
{
target._bind_boolean_result(index, &this->_value, &this->_is_null);
}
template <typename Target>
void _post_bind(Target& target, size_t index)
{
target._post_bind_boolean_result(index, &this->_value, &this->_is_null);
}
};
} // namespace sqlpp

View File

@ -32,4 +32,3 @@
#include <sqlpp11/data_types/day_point/expression_operators.h>
#include <sqlpp11/data_types/day_point/column_operators.h>
#include <sqlpp11/data_types/day_point/parameter_value.h>
#include <sqlpp11/data_types/day_point/result_field.h>

View File

@ -35,6 +35,7 @@ namespace sqlpp
{
using _traits = make_traits<day_point, tag::is_value_type>;
using _cpp_value_type = ::sqlpp::chrono::day_point;
using _result_type = ::sqlpp::chrono::day_point;
template <typename T>
using _is_valid_operand = is_day_or_time_point_t<T>;

View File

@ -1,70 +0,0 @@
#pragma once
/*
* Copyright (c) 2015-2015, 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 <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/data_types/day_point/data_type.h>
#include <sqlpp11/field_spec.h>
#include <ostream>
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, day_point, CanBeNull>>
: public result_field_base<Db, field_spec_t<NameType, day_point, CanBeNull>>
{
template <typename Target>
void _bind(Target& target, size_t index)
{
target._bind_date_result(index, &this->_value, &this->_is_null);
}
template <typename Target>
void _post_bind(Target& target, size_t index)
{
target._post_bind_date_result(index, &this->_value, &this->_is_null);
}
};
template <typename Db, typename NameType, bool CanBeNull>
inline std::ostream& operator<<(
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, day_point, CanBeNull>>& e)
{
if (e.is_null())
{
os << "NULL";
}
else
{
const auto ymd = ::date::year_month_day{e.value()};
os << ymd;
}
return os;
}
} // namespace sqlpp

View File

@ -32,4 +32,3 @@
#include <sqlpp11/data_types/floating_point/expression_operators.h>
#include <sqlpp11/data_types/floating_point/column_operators.h>
#include <sqlpp11/data_types/floating_point/parameter_value.h>
#include <sqlpp11/data_types/floating_point/result_field.h>

View File

@ -34,6 +34,7 @@ namespace sqlpp
{
using _traits = make_traits<floating_point, tag::is_value_type>;
using _cpp_value_type = double;
using _result_type = double;
template <typename T>
using _is_valid_operand = is_numeric_t<T>;

View File

@ -1,54 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2015, 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 <sqlpp11/exception.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/data_types/floating_point/data_type.h>
#include <sqlpp11/field_spec.h>
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, floating_point, CanBeNull>>
: public result_field_base<Db, field_spec_t<NameType, floating_point, CanBeNull>>
{
template <typename Target>
void _bind(Target& target, size_t index)
{
target._bind_floating_point_result(index, &this->_value, &this->_is_null);
}
template <typename Target>
void _post_bind(Target& target, size_t index)
{
target._post_bind_floating_point_result(index, &this->_value, &this->_is_null);
}
};
} // namespace sqlpp

View File

@ -32,4 +32,3 @@
#include <sqlpp11/data_types/integral/expression_operators.h>
#include <sqlpp11/data_types/integral/column_operators.h>
#include <sqlpp11/data_types/integral/parameter_value.h>
#include <sqlpp11/data_types/integral/result_field.h>

View File

@ -34,6 +34,7 @@ namespace sqlpp
{
using _traits = make_traits<integral, tag::is_value_type>;
using _cpp_value_type = int64_t;
using _result_type = int64_t;
template <typename T>
using _is_valid_operand = is_numeric_t<T>;

View File

@ -32,4 +32,3 @@
#include <sqlpp11/data_types/no_value/expression_operators.h>
#include <sqlpp11/data_types/no_value/column_operators.h>
#include <sqlpp11/data_types/no_value/parameter_value.h>
#include <sqlpp11/data_types/no_value/result_field.h>

View File

@ -1,70 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2015, 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 <sqlpp11/result_field.h>
#include <sqlpp11/data_types/no_value/data_type.h>
#include <sqlpp11/field_spec.h>
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, no_value_t, CanBeNull>>
{
template <typename Target>
void _bind(Target& /*unused*/, size_t /*unused*/)
{
}
template <typename Target>
void _post_bind(Target& /*unused*/, size_t /*unused*/)
{
}
void _validate() const
{
}
void _invalidate() const
{
}
constexpr bool is_null() const
{
return true;
}
};
template <typename Db, typename NameType, bool CanBeNull>
inline std::ostream& operator<<(
std::ostream& os,
const result_field_t<Db, field_spec_t<NameType, no_value_t, CanBeNull>>& /*unused*/)
{
os << "NULL";
return os;
}
} // namespace sqlpp

View File

@ -32,7 +32,6 @@
#include <sqlpp11/data_types/text/expression_operators.h>
#include <sqlpp11/data_types/text/column_operators.h>
#include <sqlpp11/data_types/text/parameter_value.h>
#include <sqlpp11/data_types/text/result_field.h>
// text specific functions
#include <sqlpp11/data_types/text/like.h>

View File

@ -28,12 +28,17 @@
#include <sqlpp11/type_traits.h>
#include <string>
#include <sqlpp11/compat/string_view.h>
namespace sqlpp
{
struct text
{
using _traits = make_traits<text, tag::is_value_type>;
using _cpp_value_type = std::string;
using _result_type = sqlpp::string_view;
template <typename T>
using _is_valid_operand = is_text_t<T>;

View File

@ -28,9 +28,7 @@
#include <string>
#include <utility>
#if __cplusplus >= 201703L
#include <string_view>
#endif
#include <sqlpp11/compat/string_view.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/alias_operators.h>
@ -51,16 +49,14 @@ namespace sqlpp
text_operand(_value_t t) : _t(std::move(t))
{
}
#if __cplusplus >= 201703L
// allow construction from an std::string_view
text_operand(std::string_view t) : _t(t)
// allow construction from an sqlpp::string_view
text_operand(sqlpp::string_view t) : _t(t)
{
}
// additional const char* overload, required to disambiguate
text_operand(const char* t) : _t(t)
{
}
#endif
text_operand(const text_operand&) = default;
text_operand(text_operand&&) = default;

View File

@ -32,9 +32,7 @@
#include <sqlpp11/data_types/text/wrap_operand.h>
#include <sqlpp11/data_types/text/operand.h>
#if __cplusplus >= 201703L
#include <string_view>
#endif
#include <sqlpp11/compat/string_view.h>
namespace sqlpp
{
@ -51,8 +49,7 @@ namespace sqlpp
target._bind_text_parameter(index, &_value, _is_null);
}
#if __cplusplus >= 201703L
parameter_value_base& operator=(const std::string_view& val)
parameter_value_base& operator=(const sqlpp::string_view& val)
{
_value = val;
_is_null = false;
@ -65,6 +62,5 @@ namespace sqlpp
_is_null = false;
return *this;
}
#endif
};
} // namespace sqlpp

View File

@ -1,87 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2015, 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 <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/data_types/text/data_type.h>
#include <sqlpp11/field_spec.h>
#include <ostream>
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, text, CanBeNull>>
: public result_field_base<Db, field_spec_t<NameType, text, CanBeNull>>
{
const char* text{nullptr}; // Non-owning
size_t len{};
template <typename Target>
void _bind(Target& target, size_t index)
{
target._bind_text_result(index, &text, &len);
if (text)
{
this->_value.assign(text, len);
}
else
{
this->_value.assign("");
}
this->_is_null = (text == nullptr);
}
template <typename Target>
void _post_bind(Target& target, size_t index)
{
target._post_bind_text_result(index, &text, &len);
if (text)
{
this->_value.assign(text, len);
}
else
{
this->_value.assign("");
}
this->_is_null = (text == nullptr);
}
};
template <typename Db, typename NameType, bool CanBeNull>
inline std::ostream& operator<<(
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, text, CanBeNull>>& e)
{
if (e.is_null())
{
return os << "NULL";
}
return os << e.value();
}
} // namespace sqlpp

View File

@ -27,21 +27,14 @@
*/
#include <utility>
#if __cplusplus >= 201703L
#include <string_view>
#endif
#include <sqlpp11/compat/string_view.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/wrap_operand.h>
namespace sqlpp
{
struct text_operand;
#if __cplusplus >= 201703L
using checked_type = std::string_view;
#else
using checked_type = std::string;
#endif
using checked_type = sqlpp::string_view;
template <typename T>
struct wrap_operand<

View File

@ -32,4 +32,3 @@
#include <sqlpp11/data_types/time_of_day/expression_operators.h>
#include <sqlpp11/data_types/time_of_day/column_operators.h>
#include <sqlpp11/data_types/time_of_day/parameter_value.h>
#include <sqlpp11/data_types/time_of_day/result_field.h>

View File

@ -35,6 +35,7 @@ namespace sqlpp
{
using _traits = make_traits<time_of_day, tag::is_value_type>;
using _cpp_value_type = std::chrono::microseconds;
using _result_type = std::chrono::microseconds;
template <typename T>
using _is_valid_operand = is_time_of_day_t<T>;

View File

@ -1,70 +0,0 @@
#pragma once
/*
* Copyright (c) 2015-2015, 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 <sqlpp11/chrono.h>
#include <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/data_types/time_of_day/data_type.h>
#include <sqlpp11/field_spec.h>
#include <ostream>
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, time_of_day, CanBeNull>>
: public result_field_base<Db, field_spec_t<NameType, time_of_day, CanBeNull>>
{
template <typename Target>
void _bind(Target& target, size_t i)
{
target._bind_time_of_day_result(i, &this->_value, &this->_is_null);
}
template <typename Target>
void _post_bind(Target& target, size_t i)
{
target._post_bind_time_of_day_result(i, &this->_value, &this->_is_null);
}
};
template <typename Db, typename NameType, bool CanBeNull>
inline std::ostream& operator<<(
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, time_of_day, CanBeNull>>& e)
{
if (e.is_null())
{
os << "NULL";
}
else
{
os << ::date::make_time(e.value());
}
return os;
}
} // namespace sqlpp

View File

@ -32,4 +32,3 @@
#include <sqlpp11/data_types/time_point/expression_operators.h>
#include <sqlpp11/data_types/time_point/column_operators.h>
#include <sqlpp11/data_types/time_point/parameter_value.h>
#include <sqlpp11/data_types/time_point/result_field.h>

View File

@ -35,6 +35,7 @@ namespace sqlpp
{
using _traits = make_traits<time_point, tag::is_value_type>;
using _cpp_value_type = ::sqlpp::chrono::microsecond_point;
using _result_type = ::sqlpp::chrono::microsecond_point;
template <typename T>
using _is_valid_operand = is_day_or_time_point_t<T>;

View File

@ -1,73 +0,0 @@
#pragma once
/*
* Copyright (c) 2015-2015, 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 <sqlpp11/chrono.h>
#include <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/data_types/time_point/data_type.h>
#include <sqlpp11/field_spec.h>
#include <ostream>
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, time_point, CanBeNull>>
: public result_field_base<Db, field_spec_t<NameType, time_point, CanBeNull>>
{
template <typename Target>
void _bind(Target& target, size_t i)
{
target._bind_date_time_result(i, &this->_value, &this->_is_null);
}
template <typename Target>
void _post_bind(Target& target, size_t i)
{
target._post_bind_date_time_result(i, &this->_value, &this->_is_null);
}
};
template <typename Db, typename NameType, bool CanBeNull>
inline std::ostream& operator<<(
std::ostream& os, const result_field_t<Db, field_spec_t<NameType, time_point, CanBeNull>>& e)
{
if (e.is_null())
{
os << "NULL";
}
else
{
const auto dp = ::sqlpp::chrono::floor<::date::days>(e.value());
const auto time = ::date::make_time(e.value() - dp);
const auto ymd = ::date::year_month_day{dp};
os << ymd << 'T' << time;
}
return os;
}
} // namespace sqlpp

View File

@ -32,4 +32,3 @@
#include <sqlpp11/data_types/unsigned_integral/expression_operators.h>
#include <sqlpp11/data_types/unsigned_integral/column_operators.h>
#include <sqlpp11/data_types/unsigned_integral/parameter_value.h>
#include <sqlpp11/data_types/unsigned_integral/result_field.h>

View File

@ -34,6 +34,7 @@ namespace sqlpp
{
using _traits = make_traits<unsigned_integral, tag::is_value_type>;
using _cpp_value_type = uint64_t;
using _result_type = uint64_t;
template <typename T>
using _is_valid_operand = is_numeric_t<T>;

View File

@ -1,53 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2016, Roland Bock, Aaron Bishop
* 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 <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/data_types/unsigned_integral/data_type.h>
#include <sqlpp11/field_spec.h>
namespace sqlpp
{
template <typename Db, typename NameType, bool CanBeNull>
struct result_field_t<Db, field_spec_t<NameType, unsigned_integral, CanBeNull>>
: public result_field_base<Db, field_spec_t<NameType, unsigned_integral, CanBeNull>>
{
template <typename Target>
void _bind(Target& target, size_t index)
{
target._bind_unsigned_integral_result(index, &this->_value, &this->_is_null);
}
template <typename Target>
void _post_bind(Target& target, size_t index)
{
target._post_bind_unsigned_integral_result(index, &this->_value, &this->_is_null);
}
};
} // namespace sqlpp

View File

@ -44,7 +44,7 @@ namespace sqlpp
using _name_type = alias::a_t::_alias_t;
using _value_type = value_type_of<Expr>;
using _field_spec = field_spec_t<_name_type, _value_type, true>;
using type = result_field_t<Db, _field_spec>;
using type = typename _field_spec::cpp_type;
};
template <typename Db,

View File

@ -28,6 +28,10 @@
#include <sqlpp11/type_traits.h>
#include <type_traits>
#include <sqlpp11/compat/optional.h>
namespace sqlpp
{
template <typename NameType, typename ValueType, bool CanBeNull>
@ -39,6 +43,10 @@ namespace sqlpp
using _nodes = detail::type_vector<>;
using _alias_t = NameType;
using cpp_type = typename std::conditional<CanBeNull,
sqlpp::optional<typename ValueType::_result_type>,
typename ValueType::_result_type>::type;
};
template <typename Left, typename Right, typename Enable = void>

View File

@ -28,6 +28,9 @@
#include <sqlpp11/chrono.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/compat/optional.h>
#include <sqlpp11/compat/string_view.h>
#include <sqlpp11/compat/span.h>
#include <sqlpp11/mysql/detail/prepared_statement_handle.h>
#include <sqlpp11/mysql/sqlpp_mysql.h>
@ -45,6 +48,7 @@ namespace sqlpp
{
std::shared_ptr<detail::prepared_statement_handle_t> _handle;
void* _result_row_address{nullptr};
bool _require_bind = true;
public:
bind_result_t() = default;
@ -79,17 +83,23 @@ namespace sqlpp
if (&result_row != _result_row_address)
{
result_row._bind(*this); // sets row data to mysql bind data
bind_impl(); // binds mysql statement to data
result_row._bind_fields(*this); // sets row data to mysql bind data
_result_row_address = &result_row;
}
if (_require_bind)
{
bind_impl(); // binds mysql statement to data
_require_bind = false;
}
if (next_impl())
{
if (not result_row)
{
result_row._validate();
}
result_row._post_bind(*this); // translates bind_data to row data where required
result_row._read_fields(*this); // translates bind_data to row data where required
}
else
{
@ -103,270 +113,289 @@ namespace sqlpp
return !_handle or !*_handle;
}
void _bind_boolean_result(size_t index, signed char* value, bool* is_null)
void bind_field(size_t index, bool& /*value*/)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding boolean result " << static_cast<void*>(value) << " at index: " << index
std::cerr << "MySQL debug: binding boolean result at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]};
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
auto& buffer{_handle->result_buffers[index]};
new (&buffer._bool) bool{};
MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_TINY;
param.buffer = value;
param.buffer_length = sizeof(*value);
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.buffer = &buffer._bool;
param.buffer_length = sizeof(buffer._bool);
param.length = &buffer.length;
param.is_null = &buffer.is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
param.error = &buffer.error;
}
void _bind_integral_result(size_t index, int64_t* value, bool* is_null)
void bind_field(size_t index, int64_t& /*value*/)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding integral result " << static_cast<void*>(value) << " at index: " << index
std::cerr << "MySQL debug: binding integral result at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]};
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
auto& buffer{_handle->result_buffers[index]};
new (&buffer._int64) int64_t{};
MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_LONGLONG;
param.buffer = value;
param.buffer_length = sizeof(*value);
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.buffer = &buffer._int64;
param.buffer_length = sizeof(buffer._int64);
param.length = &buffer.length;
param.is_null = &buffer.is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
param.error = &buffer.error;
}
void _bind_unsigned_integral_result(size_t index, uint64_t* value, bool* is_null)
void bind_field(size_t index, uint64_t& /*value*/)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding unsigned integral result " << static_cast<void*>(value)
<< " at index: " << index << std::endl;
std::cerr << "MySQL debug: binding unsigned integral result at index: " << index << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]};
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
auto& buffer{_handle->result_buffers[index]};
new (&buffer._uint64) uint64_t{};
MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_LONGLONG;
param.buffer = value;
param.buffer_length = sizeof(*value);
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.buffer = &buffer._uint64;
param.buffer_length = sizeof(buffer._uint64);
param.length = &buffer.length;
param.is_null = &buffer.is_null;
param.is_unsigned = true;
param.error = &meta_data.bound_error;
param.error = &buffer.error;
}
void _bind_floating_point_result(size_t index, double* value, bool* is_null)
void bind_field(size_t index, double& /*value*/)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding floating point result " << static_cast<void*>(value)
<< " at index: " << index << std::endl;
std::cerr << "MySQL debug: binding floating point result at index: " << index << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]};
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
auto& buffer{_handle->result_buffers[index]};
new (&buffer._double) double{};
MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_DOUBLE;
param.buffer = value;
param.buffer_length = sizeof(*value);
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.buffer = &buffer._double;
param.buffer_length = sizeof(buffer._double);
param.length = &buffer.length;
param.is_null = &buffer.is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
param.error = &buffer.error;
}
void _bind_text_result(size_t index, const char** value, size_t* len)
void bind_field(size_t index, sqlpp::string_view& /*value*/)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding text result " << static_cast<const void*>(*value) << " at index: " << index
std::cerr << "MySQL debug: binding text result at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]};
meta_data.index = index;
meta_data.len = len;
meta_data.is_null = nullptr;
meta_data.text_buffer = value;
if (meta_data.bound_text_buffer.empty())
meta_data.bound_text_buffer.resize(8);
auto& buffer{_handle->result_buffers[index]};
MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_STRING;
param.buffer = meta_data.bound_text_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size();
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.buffer = buffer.var_buffer.data();
param.buffer_length = buffer.var_buffer.size();
param.length = &buffer.length;
param.is_null = &buffer.is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
param.error = &buffer.error;
}
void _bind_blob_result(size_t index, const char** value, size_t* len)
void bind_field(size_t index, sqlpp::span<uint8_t>& /*value*/)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding text result " << static_cast<const void*>(*value) << " at index: " << index
std::cerr << "MySQL debug: binding blob result at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]};
meta_data.index = index;
meta_data.len = len;
meta_data.is_null = nullptr;
meta_data.text_buffer = value;
if (meta_data.bound_text_buffer.empty())
meta_data.bound_text_buffer.resize(8);
auto& buffer{_handle->result_buffers[index]};
MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_BLOB;
param.buffer = meta_data.bound_text_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size();
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.buffer = buffer.var_buffer.data();
param.buffer_length = buffer.var_buffer.size();
param.length = &buffer.length;
param.is_null = &buffer.is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
param.error = &buffer.error;
}
void _bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null)
void bind_chrono_field(size_t index, enum_field_types buffer_type)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding date result " << static_cast<void*>(value) << " at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]};
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
meta_data.text_buffer = nullptr;
meta_data.bound_text_buffer.resize(sizeof(MYSQL_TIME));
auto& buffer{_handle->result_buffers[index]};
new (&buffer._mysql_time) MYSQL_TIME{};
MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_DATE;
param.buffer = meta_data.bound_text_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size();
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.buffer_type = buffer_type;
param.buffer = &buffer._mysql_time;
param.buffer_length = sizeof(buffer._mysql_time);
param.length = &buffer.length;
param.is_null = &buffer.is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
param.error = &buffer.error;
}
void _bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null)
void bind_field(size_t index, ::sqlpp::chrono::day_point& /*value*/)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding date time result " << static_cast<void*>(value) << " at index: " << index
std::cerr << "MySQL debug: binding date result at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]};
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
meta_data.text_buffer = nullptr;
meta_data.bound_text_buffer.resize(sizeof(MYSQL_TIME));
MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_DATETIME;
param.buffer = meta_data.bound_text_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size();
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
bind_chrono_field(index, MYSQL_TYPE_DATE);
}
void _bind_time_of_day_result(size_t index, ::std::chrono::microseconds* value, bool* is_null)
void bind_field(size_t index, ::sqlpp::chrono::microsecond_point& /*value*/)
{
if (_handle->debug)
std::cerr << "MySQL debug: binding time of day result " << static_cast<void*>(value) << " at index: " << index
std::cerr << "MySQL debug: binding date time result at index: " << index
<< std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]};
meta_data.index = index;
meta_data.len = nullptr;
meta_data.is_null = is_null;
meta_data.text_buffer = nullptr;
meta_data.bound_text_buffer.resize(sizeof(MYSQL_TIME));
MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_TIME;
param.buffer = meta_data.bound_text_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size();
param.length = &meta_data.bound_len;
param.is_null = &meta_data.bound_is_null;
param.is_unsigned = false;
param.error = &meta_data.bound_error;
bind_chrono_field(index, MYSQL_TYPE_DATETIME);
}
void _post_bind_boolean_result(size_t /* index */, signed char* /* value */, bool* /* is_null */)
{
}
void _post_bind_floating_point_result(size_t /* index */, double* /* value */, bool* /* is_null */)
{
}
void _post_bind_integral_result(size_t /* index */, int64_t* /* value */, bool* /* is_null */)
{
}
void _post_bind_unsigned_integral_result(size_t /* index */, uint64_t* /* value */, bool* /* is_null */)
{
}
void _post_bind_text_result(size_t /* index */, const char** /* text */, size_t* /* len */)
{
}
void _post_bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null)
void bind_field(size_t index, ::std::chrono::microseconds& /*value*/)
{
if (_handle->debug)
std::cerr << "MySQL debug: post binding date result " << static_cast<void*>(value) << " at index: " << index
std::cerr << "MySQL debug: binding time of day result at index: " << index
<< std::endl;
if (not *is_null)
bind_chrono_field(index, MYSQL_TYPE_TIME);
}
template <class T>
void bind_field(size_t index, sqlpp::optional<T>& value)
{
value = T{};
bind_field(index, *value);
}
void read_field(size_t index, bool& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: reading bool result at index: " << index
<< std::endl;
value = _handle->result_buffers[index]._bool;
}
void read_field(size_t index, int64_t& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: reading integral result at index: " << index
<< std::endl;
value = _handle->result_buffers[index]._int64;
}
void read_field(size_t index, uint64_t& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: reading unsigned integral result at index: " << index
<< std::endl;
value = _handle->result_buffers[index]._uint64;
}
void read_field(size_t index, double& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: reading floating point result at index: " << index
<< std::endl;
value = _handle->result_buffers[index]._double;
}
void refetch_if_required(size_t index)
{
if (_handle->debug)
std::cerr << "MySQL debug: Checking result size at index: " << index
<< std::endl;
auto& buffer = _handle->result_buffers[index];
auto& params = _handle->result_params[index];
if (*params.length > params.buffer_length)
{
const auto& dt =
*reinterpret_cast<const MYSQL_TIME*>(_handle->result_param_meta_data[index].bound_text_buffer.data());
if (dt.year > std::numeric_limits<int>::max())
throw sqlpp::exception{"cannot read year from db: " + std::to_string(dt.year)};
*is_null = false;
*value = ::date::year(static_cast<int>(dt.year)) / ::date::month(dt.month) / ::date::day(dt.day);
if (_handle->debug)
std::cerr << "MySQL debug: increasing buffer at: " << index << " to " << *params.length << std::endl;
buffer.var_buffer.resize(*params.length);
params.buffer = buffer.var_buffer.data();
params.buffer_length = buffer.var_buffer.size();
const auto err = mysql_stmt_fetch_column(_handle->mysql_stmt, &params, index, 0);
if (err)
throw sqlpp::exception{std::string{"MySQL: Fetch column after reallocate failed: "} + "error-code: " +
std::to_string(err) + ", stmt-error: " + mysql_stmt_error(_handle->mysql_stmt) +
", stmt-errno: " + std::to_string(mysql_stmt_errno(_handle->mysql_stmt))};
_require_bind = true;
}
}
void _post_bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null)
void read_field(size_t index, sqlpp::string_view& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: post binding date time result " << static_cast<void*>(value) << " at index: " << index
std::cerr << "MySQL debug: reading text result at index: " << index
<< std::endl;
if (not *is_null)
{
const auto& dt =
*reinterpret_cast<const MYSQL_TIME*>(_handle->result_param_meta_data[index].bound_text_buffer.data());
if (dt.year > std::numeric_limits<int>::max())
throw sqlpp::exception{"cannot read year from db: " + std::to_string(dt.year)};
*is_null = false;
*value = ::sqlpp::chrono::day_point(::date::year(static_cast<int>(dt.year)) / ::date::month(dt.month) / ::date::day(dt.day)) +
std::chrono::hours(dt.hour) + std::chrono::minutes(dt.minute) + std::chrono::seconds(dt.second) +
std::chrono::microseconds(dt.second_part);
}
refetch_if_required(index);
const auto& buffer = _handle->result_buffers[index];
const auto& params = _handle->result_params[index];
value = sqlpp::string_view(buffer.var_buffer.data(), *params.length);
}
void _post_bind_time_of_day_result(size_t index, ::std::chrono::microseconds* value, bool* is_null)
void read_field(size_t index, sqlpp::span<uint8_t>& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: post binding date time result " << static_cast<void*>(value) << " at index: " << index
std::cerr << "MySQL debug: reading blob result at index: " << index
<< std::endl;
refetch_if_required(index);
const auto& buffer = _handle->result_buffers[index];
const auto& params = _handle->result_params[index];
value = sqlpp::span<uint8_t>(reinterpret_cast<const uint8_t*>(buffer.var_buffer.data()), *params.length);
}
void read_field(size_t index, ::sqlpp::chrono::day_point& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: reading date result at index: " << index
<< std::endl;
if (not *is_null)
const auto& dt = _handle->result_buffers[index]._mysql_time;
if (dt.year > std::numeric_limits<int>::max())
throw sqlpp::exception{"cannot read year from db: " + std::to_string(dt.year)};
value = ::date::year(static_cast<int>(dt.year)) / ::date::month(dt.month) / ::date::day(dt.day);
}
void read_field(size_t index, ::sqlpp::chrono::microsecond_point& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: reading date time result at index: " << index << std::endl;
const auto& dt = _handle->result_buffers[index]._mysql_time;
if (dt.year > std::numeric_limits<int>::max())
throw sqlpp::exception{"cannot read year from db: " + std::to_string(dt.year)};
value = ::sqlpp::chrono::day_point(::date::year(static_cast<int>(dt.year)) / ::date::month(dt.month) /
::date::day(dt.day)) +
std::chrono::hours(dt.hour) + std::chrono::minutes(dt.minute) + std::chrono::seconds(dt.second) +
std::chrono::microseconds(dt.second_part);
}
void read_field(size_t index, ::std::chrono::microseconds& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: reading date time result at index: " << index << std::endl;
const auto& dt = _handle->result_buffers[index]._mysql_time;
value = std::chrono::hours(dt.hour) + std::chrono::minutes(dt.minute) + std::chrono::seconds(dt.second) +
std::chrono::microseconds(dt.second_part);
}
template <class T>
void read_field(size_t index, sqlpp::optional<T>& value)
{
if (_handle->result_buffers[index].is_null)
{
const auto& dt =
*reinterpret_cast<const MYSQL_TIME*>(_handle->result_param_meta_data[index].bound_text_buffer.data());
*value = std::chrono::hours(dt.hour) + std::chrono::minutes(dt.minute) + std::chrono::seconds(dt.second) +
std::chrono::microseconds(dt.second_part);
value.reset();
return;
}
if (!value)
value = T{};
read_field(index, *value);
}
private:
@ -387,58 +416,12 @@ namespace sqlpp
if (_handle->debug)
std::cerr << "MySQL debug: Accessing next row of handle at " << _handle.get() << std::endl;
auto flag = mysql_stmt_fetch(_handle->mysql_stmt);
const auto flag = mysql_stmt_fetch(_handle->mysql_stmt);
switch (flag)
{
case 0:
case MYSQL_DATA_TRUNCATED:
{
bool need_to_rebind{false};
for (auto& r : _handle->result_param_meta_data)
{
if (r.len)
{
if (r.bound_is_null)
{
*r.text_buffer = nullptr;
*r.len = 0;
}
else
{
if (r.bound_len > r.bound_text_buffer.size())
{
if (_handle->debug)
std::cerr << "MySQL debug: Need to reallocate buffer " << static_cast<const void*>(*r.text_buffer)
<< " at index " << r.index << " for handle at " << _handle.get() << std::endl;
need_to_rebind = true;
r.bound_text_buffer.resize(r.bound_len);
MYSQL_BIND& param{_handle->result_params[r.index]};
param.buffer = r.bound_text_buffer.data();
param.buffer_length = r.bound_text_buffer.size();
auto err =
mysql_stmt_fetch_column(_handle->mysql_stmt, &param, static_cast<unsigned int>(r.index), 0);
if (err)
throw sqlpp::exception{std::string{"MySQL: Fetch column after reallocate failed: "} +
"error-code: " + std::to_string(err) +
", stmt-error: " + mysql_stmt_error(_handle->mysql_stmt) +
", stmt-errno: " + std::to_string(mysql_stmt_errno(_handle->mysql_stmt))};
}
*r.text_buffer = r.bound_text_buffer.data();
if (_handle->debug)
std::cerr << "MySQL debug: New buffer " << static_cast<const void*>(*r.text_buffer) << " at index "
<< r.index << " for handle at " << _handle.get() << std::endl;
*r.len = r.bound_len;
}
}
if (r.is_null)
*r.is_null = r.bound_is_null;
}
if (need_to_rebind)
bind_impl();
}
return true;
case 1:
throw sqlpp::exception{std::string{"MySQL: Could not fetch next result: "} +

View File

@ -36,6 +36,9 @@
#include <sqlpp11/mysql/detail/result_handle.h>
#include <sqlpp11/mysql/sqlpp_mysql.h>
#include <sqlpp11/mysql/char_result_row.h>
#include <sqlpp11/compat/optional.h>
#include <sqlpp11/compat/string_view.h>
#include <sqlpp11/compat/span.h>
namespace sqlpp
{
@ -88,7 +91,7 @@ namespace sqlpp
{
result_row._validate();
}
result_row._bind(*this);
result_row._read_fields(*this);
}
else
{
@ -102,114 +105,102 @@ namespace sqlpp
return !_handle or !*_handle;
}
void _bind_boolean_result(size_t index, signed char* value, bool* is_null)
void read_field(size_t index, bool& value)
{
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value =
(*is_null ? false : (_char_result_row.data[index][0] == 't' or _char_result_row.data[index][0] == '1'));
value = (_char_result_row.data[index][0] == 't' or _char_result_row.data[index][0] == '1');
}
void _bind_floating_point_result(size_t index, double* value, bool* is_null)
void read_field(size_t index, double& value)
{
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value = (*is_null ? 0 : std::strtod(_char_result_row.data[index], nullptr));
value = std::strtod(_char_result_row.data[index], nullptr);
}
void _bind_integral_result(size_t index, int64_t* value, bool* is_null)
void read_field(size_t index, int64_t& value)
{
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value = (*is_null ? 0 : std::strtoll(_char_result_row.data[index], nullptr, 10));
value = std::strtoll(_char_result_row.data[index], nullptr, 10);
}
void _bind_unsigned_integral_result(size_t index, uint64_t* value, bool* is_null)
void read_field(size_t index, uint64_t& value)
{
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
*value = (*is_null ? 0 : std::strtoull(_char_result_row.data[index], nullptr, 10));
value = std::strtoull(_char_result_row.data[index], nullptr, 10);
}
void _bind_blob_result(size_t index, const uint8_t** value, size_t* len)
void read_field(size_t index, sqlpp::span<uint8_t>& value)
{
bool is_null{_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr};
*value = (uint8_t*)(is_null ? nullptr : _char_result_row.data[index]);
*len = (is_null ? 0 : _char_result_row.len[index]);
value = sqlpp::span<uint8_t>(reinterpret_cast<const uint8_t*>(_char_result_row.data[index]), _char_result_row.len[index]);
}
void _bind_text_result(size_t index, const char** value, size_t* len)
void read_field(size_t index, sqlpp::string_view& value)
{
bool is_null{_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr};
*value = (is_null ? nullptr : _char_result_row.data[index]);
*len = (is_null ? 0 : _char_result_row.len[index]);
value = sqlpp::string_view(_char_result_row.data[index], _char_result_row.len[index]);
}
void _bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null)
void read_field(size_t index, ::sqlpp::chrono::day_point& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: parsing date result at index: " << index << std::endl;
*value = {};
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
if (*is_null)
{
return;
}
const auto date_string = _char_result_row.data[index];
if (_handle->debug)
std::cerr << "MySQL debug: date string: " << date_string << std::endl;
if (::sqlpp::detail::parse_date(*value, date_string) == false)
if (::sqlpp::detail::parse_date(value, date_string) == false)
{
if (_handle->debug)
std::cerr << "MySQL debug: invalid date result: " << date_string << std::endl;
}
}
void _bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null)
void read_field(size_t index, ::sqlpp::chrono::microsecond_point& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: parsing date result at index: " << index << std::endl;
*value = {};
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
if (*is_null)
{
return;
}
const auto date_time_string = _char_result_row.data[index];
if (_handle->debug)
std::cerr << "MySQL debug: date_time string: " << date_time_string << std::endl;
if (::sqlpp::detail::parse_timestamp(*value, date_time_string) == false)
if (::sqlpp::detail::parse_timestamp(value, date_time_string) == false)
{
if (_handle->debug)
std::cerr << "MySQL debug: invalid date_time result: " << date_time_string << std::endl;
}
}
void _bind_time_of_day_result(size_t index, ::std::chrono::microseconds* value, bool* is_null)
void read_field(size_t index, ::std::chrono::microseconds& value)
{
if (_handle->debug)
std::cerr << "MySQL debug: parsing time of day result at index: " << index << std::endl;
*value = {};
*is_null = (_char_result_row.data == nullptr or _char_result_row.data[index] == nullptr);
if (*is_null)
{
return;
}
const auto time_string = _char_result_row.data[index];
if (_handle->debug)
std::cerr << "MySQL debug: time of day string: " << time_string << std::endl;
if (::sqlpp::detail::parse_time_of_day(*value, time_string) == false)
if (::sqlpp::detail::parse_time_of_day(value, time_string) == false)
{
if (_handle->debug)
std::cerr << "MySQL debug: invalid time result: " << time_string << std::endl;
}
}
template <typename T>
auto read_field(size_t index, sqlpp::optional<T>& value) -> void
{
const bool is_null = _char_result_row.data[index] == nullptr;
if (is_null)
{
value.reset();
}
else
{
if (not value)
{
value = T{};
}
read_field(index, *value);
}
}
private:
bool next_impl()
{

View File

@ -36,16 +36,20 @@ namespace sqlpp
{
namespace detail
{
struct result_meta_data_t
struct bind_result_buffer
{
size_t index;
unsigned long bound_len;
my_bool bound_is_null;
my_bool bound_error;
std::vector<char> bound_text_buffer; // also for blobs
const char** text_buffer;
size_t* len;
bool* is_null;
unsigned long length;
my_bool is_null;
my_bool error;
union // unnamed union injects members into scope
{
bool _bool;
int64_t _int64;
uint64_t _uint64;
double _double;
MYSQL_TIME _mysql_time;
};
std::vector<char> var_buffer; // text and blobs
};
struct prepared_statement_handle_t
@ -72,7 +76,7 @@ namespace sqlpp
std::vector<MYSQL_TIME> stmt_date_time_param_buffer;
std::vector<wrapped_bool> stmt_param_is_null; // my_bool is bool after 8.0, and vector<bool> is bad
std::vector<MYSQL_BIND> result_params;
std::vector<result_meta_data_t> result_param_meta_data;
std::vector<bind_result_buffer> result_buffers;
bool debug;
prepared_statement_handle_t(MYSQL_STMT* stmt, size_t no_of_parameters, size_t no_of_columns, bool debug_)
@ -81,7 +85,7 @@ namespace sqlpp
stmt_date_time_param_buffer(no_of_parameters, MYSQL_TIME{}), // ()-init for correct constructor
stmt_param_is_null(no_of_parameters, false), // ()-init for correct constructor
result_params(no_of_columns, MYSQL_BIND{}), // ()-init for correct constructor
result_param_meta_data(no_of_columns, result_meta_data_t{}), // ()-init for correct constructor
result_buffers(no_of_columns, bind_result_buffer{}), // ()-init for correct constructor
debug{debug_}
{
}

View File

@ -30,6 +30,9 @@
#include <sqlpp11/chrono.h>
#include <sqlpp11/data_types.h>
#include <sqlpp11/detail/parse_date_time.h>
#include <sqlpp11/compat/optional.h>
#include <sqlpp11/compat/string_view.h>
#include <sqlpp11/compat/span.h>
#include <iomanip>
#include <iostream>
@ -49,10 +52,63 @@ namespace sqlpp
namespace detail
{
struct statement_handle_t;
}
inline unsigned char unhex(unsigned char c)
{
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return c - '0';
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
return c + 10 - 'a';
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
return c + 10 - 'A';
}
throw sqlpp::exception{std::string{"Unexpected hex char: "} + static_cast<char>(c)};
}
inline size_t hex_assign(std::vector<uint8_t>& value, const uint8_t* blob, size_t len)
{
const auto result_size = len / 2 - 1; // unhex - leading chars
if (value.size() < result_size)
{
value.resize(result_size); // unhex - leading chars
}
size_t val_index = 0;
size_t blob_index = 2;
while (blob_index < len)
{
value[val_index] = static_cast<unsigned char>(unhex(blob[blob_index]) << 4) + unhex(blob[blob_index + 1]);
++val_index;
blob_index += 2;
}
return result_size;
}
} // namespace detail
class bind_result_t
{
// Need to buffer blobs (or switch to PQexecParams with binary results)
std::vector<std::vector<uint8_t>> _var_buffers;
private:
std::shared_ptr<detail::statement_handle_t> _handle;
@ -97,9 +153,9 @@ namespace sqlpp
bind_result_t(const std::shared_ptr<detail::statement_handle_t>& handle) : _handle(handle)
{
_var_buffers.resize(_handle->result.field_count());
if (this->_handle && this->_handle->debug())
{
// cerr
std::cerr << "PostgreSQL debug: constructing bind result, using handle at: " << this->_handle.get()
<< std::endl;
}
@ -131,7 +187,7 @@ namespace sqlpp
{
result_row._validate();
}
result_row._bind(*this);
result_row._read_fields(*this);
}
else
{
@ -142,72 +198,60 @@ namespace sqlpp
}
}
void _bind_boolean_result(size_t _index, signed char* value, bool* is_null)
void read_field(size_t _index, bool& value)
{
auto index = static_cast<int>(_index);
const auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding boolean result at index: " << index << std::endl;
std::cerr << "PostgreSQL debug: reading boolean result at index: " << index << std::endl;
}
*is_null = _handle->result.is_null(_handle->count, index);
*value = _handle->result.get_bool_value(_handle->count, index);
value = _handle->result.get_bool_value(_handle->count, index);
}
void _bind_floating_point_result(size_t _index, double* value, bool* is_null)
void read_field(size_t _index, double& value)
{
auto index = static_cast<int>(_index);
const auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding floating_point result at index: " << index << std::endl;
std::cerr << "PostgreSQL debug: reading floating_point result at index: " << index << std::endl;
}
*is_null = _handle->result.is_null(_handle->count, index);
*value = _handle->result.get_double_value(_handle->count, index);
value = _handle->result.get_double_value(_handle->count, index);
}
void _bind_integral_result(size_t _index, int64_t* value, bool* is_null)
void read_field(size_t _index, int64_t& value)
{
auto index = static_cast<int>(_index);
const auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding integral result at index: " << index << std::endl;
std::cerr << "PostgreSQL debug: reading integral result at index: " << index << std::endl;
}
*is_null = _handle->result.is_null(_handle->count, index);
*value = _handle->result.get_int64_value(_handle->count, index);
value = _handle->result.get_int64_value(_handle->count, index);
}
void _bind_unsigned_integral_result(size_t _index, uint64_t* value, bool* is_null)
void read_field(size_t _index, uint64_t& value)
{
auto index = static_cast<int>(_index);
const auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding unsigned integral result at index: " << index << std::endl;
std::cerr << "PostgreSQL debug: reading unsigned integral result at index: " << index << std::endl;
}
*is_null = _handle->result.is_null(_handle->count, index);
*value = _handle->result.get_uint64_value(_handle->count, index);
value = _handle->result.get_uint64_value(_handle->count, index);
}
void _bind_text_result(size_t _index, const char** value, size_t* len)
void read_field(size_t _index, sqlpp::string_view& value)
{
auto index = static_cast<int>(_index);
const auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding text result at index: " << index << std::endl;
std::cerr << "PostgreSQL debug: reading text result at index: " << index << std::endl;
}
if (_handle->result.is_null(_handle->count, index))
{
*value = nullptr;
*len = 0;
}
else
{
*value = _handle->result.get_char_ptr_value(_handle->count, index);
*len = static_cast<size_t>(_handle->result.length(_handle->count, index));
}
value = sqlpp::string_view(_handle->result.get_char_ptr_value(_handle->count, index),
static_cast<size_t>(_handle->result.length(_handle->count, index)));
}
// PostgreSQL will return one of those (using the default ISO client):
@ -218,20 +262,13 @@ namespace sqlpp
// 1992-10-10 01:02:03-06:30 - for some timezones with non-hour offset
// 1900-01-01 - date only
// we do not support time-only values !
void _bind_date_result(size_t _index, ::sqlpp::chrono::day_point* value, bool* is_null)
void read_field(size_t _index, ::sqlpp::chrono::day_point& value)
{
auto index = static_cast<int>(_index);
const auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding date result at index: " << index << std::endl;
}
*value = {};
*is_null = _handle->result.is_null(_handle->count, index);
if (*is_null)
{
return;
std::cerr << "PostgreSQL debug: reading date result at index: " << index << std::endl;
}
const auto date_string = _handle->result.get_char_ptr_value(_handle->count, index);
@ -239,7 +276,7 @@ namespace sqlpp
{
std::cerr << "PostgreSQL debug: date string: " << date_string << std::endl;
}
if (::sqlpp::detail::parse_date(*value, date_string) == false)
if (::sqlpp::detail::parse_date(value, date_string) == false)
{
if (_handle->debug())
{
@ -249,19 +286,12 @@ namespace sqlpp
}
// always returns UTC time for timestamp with time zone
void _bind_date_time_result(size_t _index, ::sqlpp::chrono::microsecond_point* value, bool* is_null)
void read_field(size_t _index, ::sqlpp::chrono::microsecond_point& value)
{
auto index = static_cast<int>(_index);
const auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding date_time result at index: " << index << std::endl;
}
*value = {};
*is_null = _handle->result.is_null(_handle->count, index);
if (*is_null)
{
return;
std::cerr << "PostgreSQL debug: reading date_time result at index: " << index << std::endl;
}
const auto date_string = _handle->result.get_char_ptr_value(_handle->count, index);
@ -269,7 +299,7 @@ namespace sqlpp
{
std::cerr << "PostgreSQL debug: got date_time string: " << date_string << std::endl;
}
if (::sqlpp::detail::parse_timestamp(*value, date_string) == false)
if (::sqlpp::detail::parse_timestamp(value, date_string) == false)
{
if (_handle->debug())
{
@ -279,19 +309,12 @@ namespace sqlpp
}
// always returns UTC time for time with time zone
void _bind_time_of_day_result(size_t _index, ::std::chrono::microseconds* value, bool* is_null)
void read_field(size_t _index, ::std::chrono::microseconds& value)
{
auto index = static_cast<int>(_index);
const auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding time result at index: " << index << std::endl;
}
*value = {};
*is_null = _handle->result.is_null(_handle->count, index);
if (*is_null)
{
return;
std::cerr << "PostgreSQL debug: reading time result at index: " << index << std::endl;
}
const auto time_string = _handle->result.get_char_ptr_value(_handle->count, index);
@ -301,7 +324,7 @@ namespace sqlpp
std::cerr << "PostgreSQL debug: got time string: " << time_string << std::endl;
}
if (::sqlpp::detail::parse_time_of_day(*value, time_string) == false)
if (::sqlpp::detail::parse_time_of_day(value, time_string) == false)
{
if (_handle->debug()) {
std::cerr << "PostgreSQL debug: got invalid time '" << time_string << "'" << std::endl;
@ -309,23 +332,39 @@ namespace sqlpp
}
}
void _bind_blob_result(size_t _index, const uint8_t** value, size_t* len)
void read_field(size_t _index, sqlpp::span<uint8_t>& value)
{
auto index = static_cast<int>(_index);
const auto index = static_cast<int>(_index);
if (_handle->debug())
{
std::cerr << "PostgreSQL debug: binding blob result at index: " << index << std::endl;
std::cerr << "PostgreSQL debug: reading blob result at index: " << index << std::endl;
}
// Need to decode the hex data.
// Using PQexecParams would allow to use binary data.
// That's certainly faster, but some effort to determine the correct column types.
const auto size =
detail::hex_assign(_var_buffers[_index], _handle->result.get_blob_value(_handle->count, index),
static_cast<size_t>(_handle->result.length(_handle->count, index)));
value = sqlpp::span<uint8_t>(_var_buffers[_index].data(), size);
}
template <typename T>
auto read_field(size_t _index, sqlpp::optional<T>& value) -> void
{
const auto index = static_cast<int>(_index);
if (_handle->result.is_null(_handle->count, index))
{
*value = nullptr;
*len = 0;
value.reset();
}
else
{
*value = _handle->result.get_blob_value(_handle->count, index);
*len = static_cast<size_t>(_handle->result.length(_handle->count, index));
if (not value)
{
value = T{};
}
read_field(_index, *value);
}
}

View File

@ -36,7 +36,6 @@
#include <sqlpp11/connection.h>
#include <sqlpp11/detail/float_safe_ostringstream.h>
#include <sqlpp11/postgresql/bind_result.h>
#include <sqlpp11/postgresql/result_field.h>
#include <sqlpp11/postgresql/connection_config.h>
#include <sqlpp11/postgresql/prepared_statement.h>
#include <sqlpp11/postgresql/exception.h>

View File

@ -141,8 +141,10 @@ namespace sqlpp
valid = false;
count = 0;
total_count = 0;
result = PQexecPrepared(connection.native_handle(), _name.data(), static_cast<int>(size), values.data(), nullptr, nullptr, 0);
/// @todo validate result? is it really valid
result = PQexecPrepared(connection.native_handle(), /*stmtName*/ _name.data(),
/*nParams*/ static_cast<int>(size), /*paramValues*/ values.data(),
/*paramLengths*/ nullptr, /*paramFormats*/ nullptr, /*resultFormat*/ 0);
/// @todo validate result? is it really valid
valid = true;
}
@ -171,7 +173,8 @@ namespace sqlpp
void prepare(const std::string& stmt)
{
// Create the prepared statement
result = PQprepare(connection.native_handle(), _name.c_str(), stmt.c_str(), 0, nullptr);
result = PQprepare(connection.native_handle(), _name.c_str(), stmt.c_str(),
/*nParams*/ 0, /*paramTypes*/ nullptr);
valid = true;
}
};

View File

@ -118,6 +118,7 @@ namespace sqlpp
check_index(record, field);
auto t = int64_t{};
const auto txt = std::string{get_pq_value(m_result, record, field)};
std::cerr << "txt: " << txt << ", record: " << record << ", field: " << field << std::endl;
if(txt != "")
{
t = std::stoll(txt);

View File

@ -1,120 +0,0 @@
#pragma once
/*
* Copyright (c) 2021-2021, 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 <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/result_field_base.h>
#include <sqlpp11/data_types/blob/data_type.h>
#include <sqlpp11/field_spec.h>
#include <ostream>
#include <string>
namespace sqlpp
{
namespace postgresql
{
// Forward declaration
class connection_base;
}
namespace detail
{
inline unsigned char unhex(unsigned char c)
{
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return c - '0';
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
return c + 10 - 'a';
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
return c + 10 - 'A';
}
throw sqlpp::exception{std::string{"Unexpected hex char: "} + static_cast<char>(c)};
}
inline void hex_assign(std::vector<unsigned char>& value, const uint8_t* blob, size_t len)
{
value.resize(len / 2 - 1); // unhex - leading chars
size_t val_index = 0;
size_t blob_index = 2;
while (blob_index < len)
{
value[val_index] = static_cast<unsigned char>(unhex(blob[blob_index]) << 4) + unhex(blob[blob_index + 1]);
++val_index;
blob_index += 2;
}
}
} // namespace detail
template <typename NameType, bool CanBeNull>
struct result_field_t<postgresql::connection_base, field_spec_t<NameType, blob, CanBeNull>>
: public result_field_base<postgresql::connection_base, field_spec_t<NameType, blob, CanBeNull>>
{
private:
const uint8_t* _blob{nullptr}; // Non-owning
public:
size_t len{};
template <typename Target>
void _bind(Target& target, size_t index)
{
target._bind_blob_result(index, &_blob, &len);
if (_blob)
{
detail::hex_assign(this->_value, _blob, len);
len = this->_value.size();
}
else
this->_value.clear();
this->_is_null = (_blob == nullptr);
}
};
} // namespace sqlpp

View File

@ -1,62 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2015, 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 <ostream>
#include <sqlpp11/wrong.h>
#include <sqlpp11/wrap_operand.h>
#include <sqlpp11/type_traits.h>
namespace sqlpp
{
template <typename Db, typename FieldSpec>
struct result_field_t
{
using X = typename FieldSpec::incorrect;
static_assert(wrong_t<result_field_t>::value, "Missing specialization for result_field_t");
};
template <typename Context, typename Db, typename FieldSpec>
Context& serialize(const result_field_t<Db, FieldSpec>& t, Context& context)
{
if (t.is_null())
{
context << "NULL";
}
else
{
serialize(wrap_operand_t<cpp_value_type_of<FieldSpec>>(t.value()), context);
}
return context;
}
template <typename Db, typename FieldSpec>
inline std::ostream& operator<<(std::ostream& os, const result_field_t<Db, FieldSpec>& rf)
{
return serialize(rf, os);
}
} // namespace sqlpp

View File

@ -1,111 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-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 <sqlpp11/alias_operators.h>
#include <sqlpp11/basic_expression_operators.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/result_field.h>
#include <sqlpp11/type_traits.h>
#include <utility>
namespace sqlpp
{
template <typename Db, typename FieldSpec, typename StorageType = typename value_type_of<FieldSpec>::_cpp_value_type>
struct result_field_base
{
using _field_spec_t = FieldSpec;
using _alias_t = typename FieldSpec::_alias_t;
using _cpp_value_type = typename value_type_of<FieldSpec>::_cpp_value_type;
using _cpp_storage_type = StorageType;
using _traits = make_traits<value_type_of<_field_spec_t>,
tag::is_result_field,
tag::is_expression>;
using _nodes = detail::type_vector<>;
using _can_be_null = column_spec_can_be_null_t<_field_spec_t>;
result_field_base() : _is_valid{false}, _is_null{true}, _value{}
{
}
bool operator==(const _cpp_value_type& rhs) const
{
return value() == rhs;
}
bool operator!=(const _cpp_value_type& rhs) const
{
return not operator==(rhs);
}
void _validate()
{
_is_valid = true;
}
void _invalidate()
{
_is_valid = false;
_is_null = true;
_value = {};
}
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)
{
return {};
}
return _value;
}
operator _cpp_value_type() const
{
return value();
}
bool _is_valid;
bool _is_null;
_cpp_storage_type _value;
};
} // namespace sqlpp

View File

@ -28,6 +28,7 @@
#include <map>
#include <utility>
#include <sqlpp11/compat/string_view.h>
#include <sqlpp11/data_types/text.h>
#include <sqlpp11/detail/index_sequence.h>
#include <sqlpp11/dynamic_select_column_list.h>
@ -43,32 +44,22 @@ namespace sqlpp
struct result_row_impl;
template <typename Db, std::size_t index, typename FieldSpec>
struct result_field : public member_t<FieldSpec, result_field_t<Db, FieldSpec>>
struct result_field : public member_t<FieldSpec, typename FieldSpec::cpp_type>
{
using _field = member_t<FieldSpec, result_field_t<Db, FieldSpec>>;
using _field = member_t<FieldSpec, typename FieldSpec::cpp_type>;
result_field() = default;
void _validate()
template <typename Target>
void _bind_field(Target& target)
{
_field::operator()()._validate();
}
void _invalidate()
{
_field::operator()()._invalidate();
target.bind_field(index, _field::operator()());
}
template <typename Target>
void _bind(Target& target)
void _read_field(Target& target)
{
_field::operator()()._bind(target, index);
}
template <typename Target>
void _post_bind(Target& target)
{
_field::operator()()._post_bind(target, index);
target.read_field(index, _field::operator()());
}
template <typename Callable>
@ -90,30 +81,18 @@ namespace sqlpp
{
result_row_impl() = default;
void _validate()
template <typename Target>
void _bind_fields(Target& target)
{
using swallow = int[];
(void)swallow{(result_field<Db, Is, FieldSpecs>::_validate(), 0)...};
}
void _invalidate()
{
using swallow = int[];
(void)swallow{(result_field<Db, Is, FieldSpecs>::_invalidate(), 0)...};
(void)swallow{(result_field<Db, Is, FieldSpecs>::_bind_field(target), 0)...};
}
template <typename Target>
void _bind(Target& target)
void _read_fields(Target& target)
{
using swallow = int[];
(void)swallow{(result_field<Db, Is, FieldSpecs>::_bind(target), 0)...};
}
template <typename Target>
void _post_bind(Target& target)
{
using swallow = int[];
(void)swallow{(result_field<Db, Is, FieldSpecs>::_post_bind(target), 0)...};
(void)swallow{(result_field<Db, Is, FieldSpecs>::_read_field(target), 0)...};
}
template <typename Callable>
@ -154,13 +133,11 @@ namespace sqlpp
void _validate()
{
_impl::_validate();
_is_valid = true;
}
void _invalidate()
{
_impl::_invalidate();
_is_valid = false;
}
@ -180,15 +157,15 @@ namespace sqlpp
}
template <typename Target>
void _bind(Target& target)
void _bind_fields(Target& target)
{
_impl::_bind(target);
_impl::_bind_fields(target);
}
template <typename Target>
void _post_bind(Target& target)
void _read_fields(Target& target)
{
_impl::_post_bind(target);
_impl::_read_fields(target);
}
template <typename Callable>
@ -223,7 +200,7 @@ namespace sqlpp
: public detail::result_row_impl<Db, detail::make_index_sequence<sizeof...(FieldSpecs)>, FieldSpecs...>
{
using _impl = detail::result_row_impl<Db, detail::make_index_sequence<sizeof...(FieldSpecs)>, FieldSpecs...>;
using _field_type = result_field_t<Db, field_spec_t<no_name_t, text, true>>;
using _field_type = sqlpp::string_view;
bool _is_valid{false};
std::vector<std::string> _dynamic_field_names;
@ -249,22 +226,12 @@ namespace sqlpp
void _validate()
{
_impl::_validate();
_is_valid = true;
for (auto& field : _dynamic_fields)
{
field.second._validate();
}
}
void _invalidate()
{
_impl::_invalidate();
_is_valid = false;
for (auto& field : _dynamic_fields)
{
field.second._invalidate();
}
}
bool operator==(const dynamic_result_row_t& rhs) const
@ -290,7 +257,7 @@ namespace sqlpp
std::size_t index = sizeof...(FieldSpecs);
for (const auto& field_name : _dynamic_field_names)
{
_dynamic_fields.at(field_name)._bind(target, index);
target.read_field(index, _dynamic_fields.at(field_name));
++index;
}
}
@ -303,7 +270,7 @@ namespace sqlpp
std::size_t index = sizeof...(FieldSpecs);
for (const auto& field_name : _dynamic_field_names)
{
_dynamic_fields.at(field_name)._post_bind(target, index);
target.post_read(index, _dynamic_fields.at(field_name));
++index;
}
}
@ -313,11 +280,9 @@ namespace sqlpp
{
_impl::_apply(callable);
std::size_t index = sizeof...(FieldSpecs);
for (const auto& field_name : _dynamic_field_names)
{
_dynamic_fields.at(field_name)._apply(callable);
++index;
callable(_dynamic_fields.at(field_name));
}
}
@ -326,11 +291,9 @@ namespace sqlpp
{
_impl::_apply(callable);
std::size_t index = sizeof...(FieldSpecs);
for (const auto& field_name : _dynamic_field_names)
{
_dynamic_fields.at(field_name)._apply(callable);
++index;
callable(_dynamic_fields.at(field_name));
}
}
};

View File

@ -31,6 +31,9 @@
#include <sqlpp11/exception.h>
#include <sqlpp11/sqlite3/detail/prepared_statement_handle.h>
#include <sqlpp11/sqlite3/export.h>
#include <sqlpp11/compat/optional.h>
#include <sqlpp11/compat/string_view.h>
#include <sqlpp11/compat/span.h>
#include <iostream>
#include <memory>
@ -83,7 +86,7 @@ namespace sqlpp
{
result_row._validate();
}
result_row._bind(*this);
result_row._read_fields(*this);
}
else
{
@ -92,118 +95,119 @@ namespace sqlpp
}
}
void _bind_boolean_result(size_t index, signed char* value, bool* is_null)
void read_field(size_t index, bool& value)
{
if (_handle->debug)
std::cerr << "Sqlite3 debug: binding boolean result " << *value << " at index: " << index << std::endl;
std::cerr << "Sqlite3 debug: binding boolean result at index: " << index << std::endl;
*value = static_cast<signed char>(sqlite3_column_int(_handle->sqlite_statement, static_cast<int>(index)));
*is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast<int>(index)) == SQLITE_NULL;
value = static_cast<signed char>(sqlite3_column_int(_handle->sqlite_statement, static_cast<int>(index)));
}
void _bind_floating_point_result(size_t index, double* value, bool* is_null)
void read_field(size_t index, double& value)
{
if (_handle->debug)
std::cerr << "Sqlite3 debug: binding floating_point result " << *value << " at index: " << index << std::endl;
std::cerr << "Sqlite3 debug: binding floating_point result at index: " << index << std::endl;
switch (sqlite3_column_type(_handle->sqlite_statement, static_cast<int>(index)))
{
case (SQLITE3_TEXT):
*value = atof(
value = atof(
reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index))));
break;
default:
*value = sqlite3_column_double(_handle->sqlite_statement, static_cast<int>(index));
value = sqlite3_column_double(_handle->sqlite_statement, static_cast<int>(index));
}
*is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast<int>(index)) == SQLITE_NULL;
}
void _bind_integral_result(size_t index, int64_t* value, bool* is_null)
void read_field(size_t index, int64_t& value)
{
if (_handle->debug)
std::cerr << "Sqlite3 debug: binding integral result " << *value << " at index: " << index << std::endl;
std::cerr << "Sqlite3 debug: reading integral result at index: " << index << std::endl;
*value = sqlite3_column_int64(_handle->sqlite_statement, static_cast<int>(index));
*is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast<int>(index)) == SQLITE_NULL;
value = sqlite3_column_int64(_handle->sqlite_statement, static_cast<int>(index));
}
void _bind_unsigned_integral_result(size_t index, uint64_t* value, bool* is_null)
void read_field(size_t index, uint64_t& value)
{
if (_handle->debug)
std::cerr << "Sqlite3 debug: binding unsigned integral result " << *value << " at index: " << index
<< std::endl;
std::cerr << "Sqlite3 debug: binding unsigned integral result at index: " << index << std::endl;
*value = static_cast<uint64_t>(sqlite3_column_int64(_handle->sqlite_statement, static_cast<int>(index)));
*is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast<int>(index)) == SQLITE_NULL;
value = static_cast<uint64_t>(sqlite3_column_int64(_handle->sqlite_statement, static_cast<int>(index)));
}
void _bind_text_result(size_t index, const char** value, size_t* len)
void read_field(size_t index, sqlpp::string_view& value)
{
if (_handle->debug)
std::cerr << "Sqlite3 debug: binding text result at index: " << index << std::endl;
*value =
(reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index))));
*len = static_cast<size_t>(sqlite3_column_bytes(_handle->sqlite_statement, static_cast<int>(index)));
value = sqlpp::string_view(
reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index))),
static_cast<size_t>(sqlite3_column_bytes(_handle->sqlite_statement, static_cast<int>(index))));
}
void _bind_blob_result(size_t index, const uint8_t** value, size_t* len)
void read_field(size_t index, sqlpp::span<uint8_t>& value)
{
if (_handle->debug)
std::cerr << "Sqlite3 debug: binding text result at index: " << index << std::endl;
std::cerr << "Sqlite3 debug: binding blob result at index: " << index << std::endl;
*value =
(reinterpret_cast<const uint8_t*>(sqlite3_column_blob(_handle->sqlite_statement, static_cast<int>(index))));
*len = static_cast<size_t>(sqlite3_column_bytes(_handle->sqlite_statement, static_cast<int>(index)));
value = sqlpp::span<uint8_t>(
reinterpret_cast<const uint8_t*>(sqlite3_column_blob(_handle->sqlite_statement, static_cast<int>(index))),
static_cast<size_t>(sqlite3_column_bytes(_handle->sqlite_statement, static_cast<int>(index))));
}
void _bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null)
void read_field(size_t index, ::sqlpp::chrono::day_point& value)
{
if (_handle->debug)
std::cerr << "Sqlite3 debug: binding date result at index: " << index << std::endl;
*value = {};
*is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast<int>(index)) == SQLITE_NULL;
if (*is_null)
{
return;
}
const auto date_string =
reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index)));
if (_handle->debug)
std::cerr << "Sqlite3 debug: date string: " << date_string << std::endl;
if (::sqlpp::detail::parse_date(*value, date_string) == false)
if (::sqlpp::detail::parse_date(value, date_string) == false)
{
value = {};
if (_handle->debug)
std::cerr << "Sqlite3 debug: invalid date result: " << date_string << std::endl;
}
}
void _bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null)
void read_field(size_t index, ::sqlpp::chrono::microsecond_point& value)
{
if (_handle->debug)
std::cerr << "Sqlite3 debug: binding date result at index: " << index << std::endl;
*value = {};
*is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast<int>(index)) == SQLITE_NULL;
if (*is_null)
{
return;
}
const auto date_time_string =
reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index)));
if (_handle->debug)
std::cerr << "Sqlite3 debug: date_time string: " << date_time_string << std::endl;
// We treat DATETIME fields as containing either date+time or just date.
if (::sqlpp::detail::parse_date_or_timestamp(*value, date_time_string) == false)
if (::sqlpp::detail::parse_date_or_timestamp(value, date_time_string) == false)
{
value = {};
if (_handle->debug)
std::cerr << "Sqlite3 debug: invalid date_time result: " << date_time_string << std::endl;
}
}
template <typename T>
auto read_field(size_t index, sqlpp::optional<T>& value) -> void
{
const bool is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast<int>(index)) == SQLITE_NULL;
if (is_null)
{
value.reset();
}
else
{
if (not value)
{
value = T{};
}
read_field(index, *value);
}
}
private:
bool next_impl()
{

View File

@ -47,12 +47,11 @@ int Insert(int, char* [])
"INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")");
compare(__LINE__, insert_into(bar).set(bar.beta = ::sqlpp::null, bar.gamma = true),
"INSERT INTO tab_bar (beta,gamma) VALUES(NULL," + getTrue() + ")");
#if __cplusplus >= 201703L
// string_view argument
std::string_view cheeseCake = "cheesecake";
compare(__LINE__, insert_into(bar).set(bar.beta = cheeseCake, bar.gamma = true),
sqlpp::string_view cheeseCake = "cheesecake";
compare(__LINE__, insert_into(bar).set(bar.beta = std::string(cheeseCake), bar.gamma = true),
"INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")");
compare(__LINE__, insert_into(bar).set(bar.beta = sqlpp::string_view(cheeseCake), bar.gamma = true),
"INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")");
#endif
return 0;
}

View File

@ -68,11 +68,12 @@ int Where(int, char*[])
compare(__LINE__, where(is_equal_to_or_null(bar.beta, ::sqlpp::value_or_null("SQL"))), " WHERE (tab_bar.beta='SQL')");
compare(__LINE__, where(is_equal_to_or_null(bar.beta, ::sqlpp::value_or_null<sqlpp::text>(::sqlpp::null))),
" WHERE tab_bar.beta IS NULL");
#if __cplusplus >= 201703L
// string argument
compare(__LINE__, where(bar.beta == std::string("SQL")), " WHERE (tab_bar.beta='SQL')");
// string_view argument
std::string_view sqlString = "SQL";
compare(__LINE__, where(bar.beta == sqlString), " WHERE (tab_bar.beta='SQL')");
#endif
compare(__LINE__, where(bar.beta == sqlpp::string_view("SQL")), " WHERE (tab_bar.beta='SQL')");
return 0;
}

View File

@ -27,6 +27,8 @@
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
namespace
{
constexpr auto bar = test::TabBar{};
@ -47,9 +49,9 @@ namespace
// result fields are as nullable as the expressions they represent
const auto rows = db(select(bar.alpha, bar.gamma, seven).from(bar).unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "");
static_assert(is_optional<decltype(x.alpha)>::value, "");
static_assert(not is_optional<decltype(x.gamma)>::value, "");
static_assert(not is_optional<decltype(x.s)>::value, "");
}
}
@ -61,20 +63,20 @@ namespace
.from(foo.join(bar).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of (inner) join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of (inner) join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not is_optional<decltype(x.delta)>::value, "left side of (inner) join cannot be null");
static_assert(not is_optional<decltype(x.gamma)>::value, "right side of (inner) join cannot be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto& rows = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.join(foo).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of (inner) join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of (inner) join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not is_optional<decltype(x.gamma)>::value, "left side of (inner) join cannot be null");
static_assert(not is_optional<decltype(x.delta)>::value, "right side of (inner) join cannot be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
MockSizeDb db2;
@ -91,20 +93,20 @@ namespace
.from(foo.inner_join(bar).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of inner join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of inner join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not is_optional<decltype(x.delta)>::value, "left side of inner join cannot be null");
static_assert(not is_optional<decltype(x.gamma)>::value, "right side of inner join cannot be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto rows = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.inner_join(foo).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of inner join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of inner join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not is_optional<decltype(x.gamma)>::value, "left side of inner join cannot be null");
static_assert(not is_optional<decltype(x.delta)>::value, "right side of inner join cannot be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
// Left outer join
@ -113,20 +115,20 @@ namespace
.from(foo.left_outer_join(bar).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of left outer join cannot be null");
static_assert(sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of left outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not is_optional<decltype(x.delta)>::value, "left side of left outer join cannot be null");
static_assert(is_optional<decltype(x.gamma)>::value, "right side of left outer join can be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto rows = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.left_outer_join(foo).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of left outer join cannot be null");
static_assert(sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of left outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not is_optional<decltype(x.gamma)>::value, "left side of left outer join cannot be null");
static_assert(is_optional<decltype(x.delta)>::value, "right side of left outer join can be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
// Right outer join
@ -135,22 +137,22 @@ namespace
.from(foo.right_outer_join(bar).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of right outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value,
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(is_optional<decltype(x.delta)>::value, "left side of right outer join can be null");
static_assert(not is_optional<decltype(x.gamma)>::value,
"right side of right outer join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto rows = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.right_outer_join(foo).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of right outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value,
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(is_optional<decltype(x.gamma)>::value, "left side of right outer join can be null");
static_assert(not is_optional<decltype(x.delta)>::value,
"right side of right outer join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
// Outer join
@ -159,20 +161,20 @@ namespace
.from(foo.outer_join(bar).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of outer join can be null");
static_assert(sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(is_optional<decltype(x.delta)>::value, "left side of outer join can be null");
static_assert(is_optional<decltype(x.gamma)>::value, "right side of outer join can be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto rows = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.outer_join(foo).on(foo.omega > bar.alpha))
.unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of outer join can be null");
static_assert(sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(is_optional<decltype(x.gamma)>::value, "left side of outer join can be null");
static_assert(is_optional<decltype(x.delta)>::value, "right side of outer join can be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
// Cross join
@ -180,19 +182,19 @@ namespace
const auto rows =
db(select(bar.alpha, foo.delta, bar.gamma, seven).from(foo.cross_join(bar)).unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of cross join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of cross join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not is_optional<decltype(x.delta)>::value, "left side of cross join cannot be null");
static_assert(not is_optional<decltype(x.gamma)>::value, "right side of cross join cannot be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto rows =
db(select(bar.alpha, foo.delta, bar.gamma, seven).from(bar.cross_join(foo)).unconditionally());
auto& x = rows.front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of cross join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of cross join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
static_assert(is_optional<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not is_optional<decltype(x.gamma)>::value, "left side of cross join cannot be null");
static_assert(not is_optional<decltype(x.delta)>::value, "right side of cross join cannot be null");
static_assert(not is_optional<decltype(x.s)>::value, "constant non-null value can not be null");
}
}
@ -205,11 +207,11 @@ namespace
static_assert(sqlpp::can_be_null_t<decltype(a)>::value, "");
const auto rows = db(select(count(a), avg(a), max(a), min(a), sum(a)).from(bar).unconditionally());
auto& x = rows.front();
static_assert(not sqlpp::can_be_null_t<decltype(x.count)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.avg)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.sum)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.max)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.min)>::value, "");
static_assert(not is_optional<decltype(x.count)>::value, "");
static_assert(is_optional<decltype(x.avg)>::value, "");
static_assert(is_optional<decltype(x.sum)>::value, "");
static_assert(is_optional<decltype(x.max)>::value, "");
static_assert(is_optional<decltype(x.min)>::value, "");
}
{
// aggregates of nullable values
@ -218,11 +220,11 @@ namespace
static_assert(sqlpp::can_be_null_t<decltype(o)>::value, "");
const auto rows = db(select(count(o), avg(o), max(o), min(o), sum(o)).from(foo).unconditionally());
auto& x = rows.front();
static_assert(not sqlpp::can_be_null_t<decltype(x.count)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.avg)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.sum)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.max)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.min)>::value, "");
static_assert(not is_optional<decltype(x.count)>::value, "");
static_assert(is_optional<decltype(x.avg)>::value, "");
static_assert(is_optional<decltype(x.sum)>::value, "");
static_assert(is_optional<decltype(x.max)>::value, "");
static_assert(is_optional<decltype(x.min)>::value, "");
}
}
}

View File

@ -28,6 +28,7 @@
#include "MockDb.h"
#include <sqlpp11/sqlpp11.h>
#include <sqlpp11/custom_query.h>
#include "../../include/test_helpers.h"
namespace
{

View File

@ -28,6 +28,8 @@
#include "MockDb.h"
#include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
SQLPP_ALIAS_PROVIDER(now)
#if _MSC_FULL_VER >= 190023918

View File

@ -27,9 +27,7 @@
#include "Sample.h"
#include "is_regular.h"
#include <iostream>
#if __cplusplus >= 201703L
#include <string_view>
#endif
#include <sqlpp11/compat/string_view.h>
#include <sqlpp11/functions.h>
#include <sqlpp11/insert.h>
#include <sqlpp11/select.h>
@ -109,14 +107,11 @@ int Insert(int, char*[])
prepared_insert.params.delta = sqlpp::value_or_null(17);
db(prepared_insert);
#if __cplusplus >= 201703L
auto prepared_insert_sv = db.prepare(insert_into(t).set(t.gamma = parameter(t.gamma), t.delta = parameter(t.delta), t.beta = parameter(t.beta)));
prepared_insert_sv.params.gamma = true;
prepared_insert_sv.params.delta = 17;
std::string_view sv = "string_view";
prepared_insert_sv.params.beta = sv;
prepared_insert_sv.params.beta = sqlpp::string_view("string_view");;
db(prepared_insert_sv);
#endif
return 0;
}

View File

@ -27,7 +27,7 @@
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
#include <iostream>
#include "../../include/test_helpers.h"
int Interpret(int, char* [])
{
@ -171,9 +171,9 @@ int Interpret(int, char* [])
for (const auto& row : db(select(all_of(t)).from(t).unconditionally()))
{
serialize(row.alpha, printer);
serialize(row.beta, printer);
serialize(row.gamma, printer);
serialize(t.alpha == row.alpha.value(), printer);
serialize(t.beta == row.beta.value(), printer);
serialize(t.gamma == row.gamma, printer);
}
get_sql_name(t);

View File

@ -28,6 +28,7 @@
#include "is_regular.h"
#include <sqlpp11/functions.h>
#include <sqlpp11/select.h>
#include "../../include/test_helpers.h"
int Prepared(int, char* [])
{
@ -132,7 +133,10 @@ int Prepared(int, char* [])
// Can we prepare a query without parameters?
{
auto ps = db.prepare(select(all_of(t)).from(t).where((t.beta.like("%"))));
auto res = db(ps);
for (const auto& row : db(ps))
{
std::cerr << row.alpha << std::endl;
}
}
// Check that a prepared select is default-constructable

View File

@ -28,6 +28,9 @@
#include "MockDb.h"
#include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
int Result(int, char* [])
{
MockDb db = {};
@ -39,28 +42,24 @@ int Result(int, char* [])
// Using a non-enforcing db
for (const auto& row : db(select(all_of(t), t.beta.like("")).from(t).unconditionally()))
{
static_assert(sqlpp::can_be_null_t<decltype(row.alpha)>::value, "row.alpha can be null");
static_assert(std::is_same<bool, 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");
static_assert(is_optional<decltype(row.alpha)>::value, "row.alpha can be null");
for (const auto& sub : db(select(all_of(t)).from(t).where(t.alpha == row.alpha)))
for (const auto& sub : db(select(all_of(t)).from(t).where(t.alpha == row.alpha.value())))
{
std::cerr << sub.alpha << std::endl;
}
db(insert_into(t).set(t.beta = row.beta, t.gamma = false));
db(insert_into(t).set(t.beta = row.beta.value(), t.gamma = false));
}
sqlpp::select((t.alpha + 1).as(t.alpha)).flags(sqlpp::all).from(t);
for (const auto& row : db(select(all_of(t)).from(t).unconditionally()))
{
static_assert(sqlpp::can_be_null_t<decltype(row.alpha)>::value, "row.alpha can be null");
static_assert(is_optional<decltype(row.alpha)>::value, "row.alpha can be null");
}
for (const auto& row : db(select(all_of(t)).from(t).unconditionally()))
{
static_assert(sqlpp::can_be_null_t<decltype(row.alpha)>::value, "row.alpha can be null");
static_assert(is_optional<decltype(row.alpha)>::value, "row.alpha can be null");
}
sqlpp::select((t.alpha + 1).as(t.alpha)).flags(sqlpp::all).from(t);

View File

@ -33,13 +33,14 @@
#include <sqlpp11/functions.h>
#include <sqlpp11/select.h>
#include <sqlpp11/without_table_check.h>
#include "../../include/test_helpers.h"
template <typename Db, typename Column>
int64_t getColumn(Db&& db, const Column& column)
{
auto result = db(select(column.as(sqlpp::alias::a)).from(column.table()).unconditionally());
if (not result.empty())
return result.front().a;
if (not result.empty() and result.front().a.has_value())
return result.front().a.value();
else
return 0;
}
@ -49,15 +50,15 @@ struct to_cerr
template <typename Field>
auto operator()(const Field& field) const -> void
{
std::cerr << get_sql_name(field) << " = " << field << std::endl;
std::cerr << field << std::endl;
}
};
template <typename Row>
void print_row(Row const& row)
{
int64_t a = row.alpha;
const std::string b = row.beta;
const sqlpp::optional<int64_t> a = row.alpha;
const sqlpp::optional<sqlpp::string_view> b = row.beta;
std::cout << a << ", " << b << std::endl;
}
@ -90,16 +91,16 @@ int Select(int, char*[])
for (const auto& row : db(select(all_of(t)).from(t).unconditionally()))
{
int64_t a = row.alpha;
const std::string b = row.beta;
const sqlpp::optional<int64_t> a = row.alpha;
const sqlpp::optional<sqlpp::string_view> b = row.beta;
std::cout << a << ", " << b << std::endl;
}
for (const auto& row :
db(select(all_of(t), t.gamma.as(t)).from(t).where(t.alpha > 7 and trim(t.beta) == "test").for_update()))
{
int64_t a = row.alpha;
const std::string b = row.beta;
const sqlpp::optional<int64_t> a = row.alpha;
const sqlpp::optional<sqlpp::string_view> b = row.beta;
const bool g = row.tabBar;
std::cout << a << ", " << b << ", " << g << std::endl;
}
@ -177,7 +178,7 @@ int Select(int, char*[])
s.order_by.add(t.delta.order(sqlpp::sort_type::desc));
for (const auto& row : db(db.prepare(s)))
{
int64_t a = row.alpha;
const sqlpp::optional<int64_t> a = row.alpha;
std::cout << a << std::endl;
}
@ -187,7 +188,7 @@ int Select(int, char*[])
select(sqlpp::value(7).as(t.alpha));
for (const auto& row :
db(select(sqlpp::case_when(true).then(sqlpp::null).else_(sqlpp::null).as(t.beta)).from(t).unconditionally()))
db(select(sqlpp::case_when(true).then(t.beta).else_(sqlpp::null).as(t.beta)).from(t).unconditionally()))
{
std::cerr << row.beta << std::endl;
}

View File

@ -32,6 +32,7 @@
#include <sqlpp11/functions.h>
#include <sqlpp11/select.h>
#include <sqlpp11/without_table_check.h>
#include "../../include/test_helpers.h"
namespace alias
{
@ -345,7 +346,7 @@ int SelectType(int, char*[])
for (const auto& row : db(select(all_of(t)).from(t).unconditionally()))
{
int64_t a = row.alpha;
const auto a = row.alpha;
std::cout << a << std::endl;
}

View File

@ -28,6 +28,7 @@
#include <sqlpp11/select.h>
#include <sqlpp11/alias_provider.h>
#include <iostream>
#include "../../include/test_helpers.h"
int With(int, char*[])
{

View File

@ -0,0 +1,104 @@
#pragma once
/*
* Copyright (c) 2024, 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 <sqlpp11/sqlpp11.h>
template <typename Clock, typename Period>
std::ostream& operator<<(std::ostream& os, const std::chrono::time_point<Clock, Period>& t)
{
const auto dp = ::sqlpp::chrono::floor<::date::days>(t);
const auto ymd = ::date::year_month_day{dp};
const auto time = ::date::make_time(t - dp);
os << "TIMESTAMP '" << ymd << ' ' << time << "'";
return os;
}
template <typename Rep, typename Period>
std::ostream& operator<<(std::ostream& os, const std::chrono::duration<Rep, Period>& t)
{
return os << '\'' << ::date::make_time(t) << '\'';
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const sqlpp::optional<T>& t)
{
if (not t)
return os << "NULL";
return os << t.value();
}
inline std::ostream& operator<<(std::ostream& stream, const sqlpp::isolation_level& level)
{
switch (level)
{
case sqlpp::isolation_level::serializable:
{
stream << "SERIALIZABLE";
break;
}
case sqlpp::isolation_level::repeatable_read:
{
stream << "REPEATABLE READ";
break;
}
case sqlpp::isolation_level::read_committed:
{
stream << "READ COMMITTED";
break;
}
case sqlpp::isolation_level::read_uncommitted:
{
stream << "READ UNCOMMITTED";
break;
}
case sqlpp::isolation_level::undefined:
{
stream << "BEGIN";
break;
}
}
return stream;
}
template <typename L, typename R>
auto require_equal(int line, const L& l, const R& r) -> void
{
if (l != r)
{
std::cerr << line << ": " << l << " != " << r << std::endl;
throw std::runtime_error("Unexpected result");
}
}
template <typename T>
struct is_optional : public std::false_type{};
template <typename T>
struct is_optional<sqlpp::optional<T>> : public std::true_type{};

View File

@ -28,6 +28,8 @@
#include <sqlpp11/mysql/mysql.h>
#include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
#include <cassert>
#include <iostream>
#include <vector>
@ -36,20 +38,6 @@ const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{};
namespace
{
template <typename L, typename R>
auto require_equal(int line, const L& l, const R& r) -> void
{
if (l != r)
{
std::cerr << line << ": ";
serialize(::sqlpp::wrap_operand_t<L>{l}, std::cerr);
std::cerr << " != ";
serialize(::sqlpp::wrap_operand_t<R>{r}, std::cerr);
std::cerr << "\n" ;
throw std::runtime_error("Unexpected result");
}
}
template <typename L, typename R>
auto require_close(int line, const L& l, const R& r) -> void
{
@ -90,13 +78,10 @@ int DateTime(int, char*[])
db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.colDayPoint.is_null(), true);
require_equal(__LINE__, row.colDayPoint.value(), ::sqlpp::chrono::day_point{});
require_equal(__LINE__, row.colTimePoint.is_null(), true);
require_equal(__LINE__, row.colTimePoint.value(), ::sqlpp::chrono::microsecond_point{});
require_close(__LINE__, row.colDateTimePoint.value(), now);
require_equal(__LINE__, row.colTimeOfDay.is_null(), true);
require_equal(__LINE__, row.colTimeOfDay.value(), ::std::chrono::microseconds{});
require_equal(__LINE__, row.colDayPoint.has_value(), false);
require_equal(__LINE__, row.colTimePoint.has_value(), false);
require_close(__LINE__, row.colDateTimePoint, now);
require_equal(__LINE__, row.colTimeOfDay.has_value(), false);
}
db(update(tab).set(tab.colDayPoint = today, tab.colTimePoint = now, tab.colTimeOfDay = current).unconditionally());
@ -111,8 +96,7 @@ int DateTime(int, char*[])
auto statement = db.prepare(select(all_of(tab)).from(tab).unconditionally());
for (const auto& row : db(statement))
{
require_equal(__LINE__, row.colDateTimePoint.is_null(), false);
require_close(__LINE__, row.colDateTimePoint.value(), now);
require_close(__LINE__, row.colDateTimePoint, now);
require_equal(__LINE__, row.colDayPoint.value(), today);
require_equal(__LINE__, row.colTimePoint.value(), now);
require_close(__LINE__, row.colTimeOfDay.value(), current);

View File

@ -48,9 +48,9 @@ int DynamicSelect(int, char*[])
auto db = sql::make_test_connection();
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) DEFAULT NULL,
alpha bigint(20) AUTO_INCREMENT NOT NULL PRIMARY KEY,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
gamma bool NOT NULL DEFAULT 0
))");
const auto tab = TabSample{};

View File

@ -78,10 +78,10 @@ int Json(int, char*[])
if (result.empty())
throw std::runtime_error{"selection result is empty"};
const std::string value = result.front().value;
const sqlpp::optional<sqlpp::string_view> value = result.front().value;
if (value != "value")
throw std::runtime_error{std::string{"unexpected value: "} + value};
throw std::runtime_error{std::string{"unexpected value: "} + std::string(value ? value.value() : "NULL")};
}
catch (const std::exception& e)
{

View File

@ -50,9 +50,9 @@ int MoveConstructor(int, char*[])
connections.at(0).execute(R"(DROP TABLE IF EXISTS tab_sample)");
connections.at(0).execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) DEFAULT NULL,
alpha bigint(20) AUTO_INCREMENT NOT NULL PRIMARY KEY,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
gamma bool NOT NULL DEFAULT 0
))");
assert(connections.at(0).is_transaction_active() == false);

View File

@ -27,6 +27,7 @@
#include "TabSample.h"
#include <sqlpp11/mysql/mysql.h>
#include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
#include <cassert>
#include <iostream>
@ -82,9 +83,9 @@ int Sample(int, char*[])
const auto y = db.prepare(x);
for (const auto& row : db(db.prepare(select(all_of(tab)).from(tab).unconditionally())))
{
std::cerr << "alpha: " << row.alpha.is_null() << std::endl;
std::cerr << "beta: " << row.beta.is_null() << std::endl;
std::cerr << "gamma: " << row.gamma.is_null() << std::endl;
std::cerr << "alpha: " << row.alpha << std::endl;
std::cerr << "beta: " << row.beta << std::endl;
std::cerr << "gamma: " << row.gamma << std::endl;
}
db(insert_into(tab).set(tab.beta = "kaesekuchen", tab.gamma = true));
db(insert_into(tab).default_values());
@ -122,8 +123,8 @@ int Sample(int, char*[])
auto result = db(select(all_of(tab), select(max(tab.alpha)).from(tab)).from(tab).unconditionally());
if (const auto& row = *result.begin())
{
long a = row.alpha;
long m = row.max;
const int64_t a = row.alpha;
const sqlpp::optional<long> m = row.max;
std::cerr << __LINE__ << " row.alpha: " << a << ", row.max: " << m << std::endl;
}
tx.commit();

View File

@ -34,6 +34,7 @@
#include <sqlpp11/select.h>
#include <sqlpp11/transaction.h>
#include <sqlpp11/update.h>
#include "../../include/test_helpers.h"
#include <iostream>
#include <vector>
@ -91,7 +92,7 @@ int Select(int, char*[])
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) AUTO_INCREMENT,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL,
gamma bool NOT NULL DEFAULT 0,
PRIMARY KEY (alpha)
))");
db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
@ -153,8 +154,8 @@ int Select(int, char*[])
auto result = db(select(all_of(tab), select(max(tab.alpha)).from(tab)).from(tab).unconditionally());
if (const auto& row = *result.begin())
{
long a = row.alpha;
long m = row.max;
sqlpp::optional<long> a = row.alpha;
sqlpp::optional<long> m = row.max;
std::cerr << "-----------------------------" << a << ", " << m << std::endl;
}
tx.commit();

View File

@ -34,6 +34,7 @@
#include <sqlpp11/select.h>
#include <sqlpp11/transaction.h>
#include <sqlpp11/update.h>
#include "../../include/test_helpers.h"
#include <iostream>
#include <vector>
@ -51,14 +52,13 @@ int Truncated(int, char*[])
auto db = sql::make_test_connection();
db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE tab_sample (
alpha bigint(20) AUTO_INCREMENT,
alpha bigint(20) AUTO_INCREMENT NOT NULL PRIMARY KEY,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL,
PRIMARY KEY (alpha)
gamma bool NOT NULL DEFAULT 0
))");
db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
db.execute(R"(CREATE TABLE tab_foo (
omega bigint(20) DEFAULT NULL
omega bigint(20) NOT NULL
))");
db(insert_into(tab).set(tab.gamma = true, tab.beta = "cheese"));

View File

@ -27,6 +27,7 @@
#include "TabSample.h"
#include <sqlpp11/mysql/connection.h>
#include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
#include <iostream>

View File

@ -41,35 +41,30 @@ const auto blob = model::BlobSample{};
constexpr size_t blob_size = 1000 * 1000ul;
constexpr size_t blob_small_size = 999;
void verify_blob(sql::connection& db, const std::vector<uint8_t>& data, uint64_t id)
void verify_blob(sql::connection& db, const std::vector<uint8_t>& expected, uint64_t id)
{
auto result = db(select(blob.data).from(blob).where(blob.id == id));
const auto& result_row = result.front();
std::cerr << "id: " << id << std::endl;
std::cerr << "Insert size: " << data.size() << std::endl;
std::cerr << "Select size: " << result_row.data.len << std::endl;
if (data.size() != result_row.data.len)
if (!result_row.data)
throw std::runtime_error("blob data is unpexpectedly NULL for id " + std::to_string(id));
const auto received = *result_row.data;
if (expected.size() != received.size())
{
std::cerr << "Size mismatch" << std::endl;
throw std::runtime_error("Size mismatch " + std::to_string(data.size()) +
" != " + std::to_string(result_row.data.len));
throw std::runtime_error("Size mismatch " + std::to_string(expected.size()) +
" != " + std::to_string(received.size()));
}
std::cerr << "Verifying content" << std::endl;
const auto result_blob = result_row.data.value();
if (data != result_blob)
for (size_t i = 0; i < expected.size(); i++)
{
std::cout << "Content mismatch ([row] original -> received)" << std::endl;
for (size_t i = 0; i < data.size(); i++)
if (expected[i] != received[i])
{
if (data[i] != result_row.data.value()[i])
{
std::cerr << "[" << i << "] " << static_cast<int>(data.at(i)) << " -> " << static_cast<int>(result_blob.at(i))
<< std::endl;
}
std::cerr << "expected[" << i << "] " << static_cast<int>(expected[i]) << " != received " << static_cast<int>(received[i])
<< std::endl;
throw std::runtime_error("Content mismatch");
}
throw std::runtime_error("Content mismatch");
}
}
@ -108,12 +103,10 @@ int Blob(int, char*[])
{
auto result = db(select(blob.data).from(blob).where(blob.id == null_id));
const auto& result_row = result.front();
std::cerr << "Null blob is_null:\t" << std::boolalpha << result_row.data.is_null() << std::endl;
std::cerr << "Null blob len == 0:\t" << std::boolalpha << (result_row.data.len == 0) << std::endl;
std::cerr << "Null blob blob == nullptr:\t" << std::boolalpha << (result_row.data.is_null()) << std::endl;
if (!result_row.data.is_null() || result_row.data.len != 0)
std::cerr << "Null blob is_null:\t" << std::boolalpha << (result_row.data == sqlpp::nullopt) << std::endl;
if (result_row.data.has_value())
{
throw std::runtime_error("Null blob has incorrect values");
throw std::runtime_error("Expected NULL blob has value");
}
}

View File

@ -93,10 +93,8 @@ int Date(int, char*[])
db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.colDayPoint.is_null(), true);
require_equal(__LINE__, row.colDayPoint.value(), ::sqlpp::chrono::day_point{});
require_equal(__LINE__, row.colTimePoint.is_null(), true);
require_equal(__LINE__, row.colTimePoint.value(), ::sqlpp::chrono::microsecond_point{});
require_equal(__LINE__, row.colDayPoint.has_value(), false);
require_equal(__LINE__, row.colTimePoint.has_value(), false);
}
db(update(tab).set(tab.colDayPoint = today, tab.colTimePoint = now).unconditionally());

View File

@ -75,12 +75,9 @@ int DateTime(int, char*[])
db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.c_day.is_null(), true);
require_equal(__LINE__, row.c_day.value(), ::sqlpp::chrono::day_point{});
require_equal(__LINE__, row.c_time.is_null(), true);
require_equal(__LINE__, row.c_time.value(), ::std::chrono::microseconds{});
require_equal(__LINE__, row.c_timepoint.is_null(), true);
require_equal(__LINE__, row.c_timepoint.value(), ::sqlpp::chrono::microsecond_point{});
require_equal(__LINE__, row.c_day.has_value(), false);
require_equal(__LINE__, row.c_time.has_value(), false);
require_equal(__LINE__, row.c_timepoint.has_value(), false);
}
db(update(tab).set(tab.c_day = today, tab.c_time = current, tab.c_timepoint = now).unconditionally());

View File

@ -33,6 +33,7 @@
#include "TabBar.h"
#include "TabFoo.h"
#include "make_test_connection.h"
#include "../../include/test_helpers.h"
namespace sql = sqlpp::postgresql;

View File

@ -2,6 +2,7 @@
#include <sqlpp11/postgresql/postgresql.h>
#include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
#include "TabFoo.h"
#include "make_test_connection.h"

View File

@ -32,6 +32,7 @@
#include "TabFoo.h"
#include "make_test_connection.h"
#include "../../include/test_helpers.h"
namespace sql = sqlpp::postgresql;
model::TabFoo tab = {};
@ -69,7 +70,7 @@ int Select(int, char*[])
db.execute(R"(DROP TABLE IF EXISTS tabfoo;)");
db.execute(R"(CREATE TABLE tabfoo
(
alpha bigserial NOT NULL,
alpha bigserial,
beta smallint,
gamma text,
c_bool boolean,
@ -112,8 +113,8 @@ int Select(int, char*[])
db(insert_into(tab).set(tab.c_bool = false, tab.gamma = "asdfg"));
assert(db(select(tab.c_bool).from(tab).where(tab.gamma == "asdf")).front().c_bool);
assert(not db(select(tab.c_bool).from(tab).where(tab.gamma == "asdfg")).front().c_bool);
assert(not db(select(tab.c_bool).from(tab).where(tab.alpha == 1)).front().c_bool);
assert(not db(select(tab.c_bool).from(tab).where(tab.gamma == "asdfg")).front().c_bool.value());
assert(not db(select(tab.c_bool).from(tab).where(tab.alpha == 1)).front().c_bool.has_value());
// test

View File

@ -32,56 +32,10 @@
#include <sqlpp11/postgresql/connection.h>
#include <sqlpp11/sqlpp11.h>
#include <sqlpp11/transaction.h>
#include "../../include/test_helpers.h"
#include "make_test_connection.h"
namespace
{
std::ostream& operator<<(std::ostream& stream, const sqlpp::isolation_level& level)
{
switch (level)
{
case sqlpp::isolation_level::serializable:
{
stream << "SERIALIZABLE";
break;
}
case sqlpp::isolation_level::repeatable_read:
{
stream << "REPEATABLE READ";
break;
}
case sqlpp::isolation_level::read_committed:
{
stream << "READ COMMITTED";
break;
}
case sqlpp::isolation_level::read_uncommitted:
{
stream << "READ UNCOMMITTED";
break;
}
case sqlpp::isolation_level::undefined:
{
stream << "BEGIN";
break;
}
}
return stream;
}
template <typename L, typename R>
void require_equal(int line, const L& l, const R& r)
{
if (l != r)
{
std::cerr << line << ": " << l << " != " << r << std::endl;
throw std::runtime_error("Unexpected result");
}
}
}
namespace sql = sqlpp::postgresql;
SQLPP_ALIAS_PROVIDER(level);
@ -95,10 +49,10 @@ int Transaction(int, char*[])
{
require_equal(__LINE__, db.is_transaction_active(), false);
auto current_level = db(custom_query(sqlpp::verbatim("show transaction_isolation;"))
.with_result_type_of(select(sqlpp::value("").as(level))))
.front()
.level;
auto current_level = std::string(db(custom_query(sqlpp::verbatim("show transaction_isolation;"))
.with_result_type_of(select(sqlpp::value("").as(level))))
.front()
.level);
require_equal(__LINE__, current_level, "read committed");
std::cerr << "isolation level outside transaction: " << current_level << "\n";

View File

@ -51,7 +51,7 @@ namespace
{
// prepare test with timezone
db.execute("DROP TABLE IF EXISTS tab_sample");
db.execute("CREATE TABLE tab_sample (alpha bigint, beta text, gamma bool)");
db.execute("CREATE TABLE tab_sample (alpha bigint, beta text, gamma bool NOT NULL DEFAULT 'f')");
}
}
@ -69,24 +69,20 @@ int Type(int, char*[])
db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.alpha.is_null(), true);
require_equal(__LINE__, row.alpha.value(), 0);
require_equal(__LINE__, row.beta.is_null(), true);
require_equal(__LINE__, row.beta.value(), "");
require_equal(__LINE__, row.gamma.is_null(), true);
require_equal(__LINE__, row.gamma.value(), false);
require_equal(__LINE__, row.alpha.has_value(), false);
require_equal(__LINE__, row.beta.has_value(), false);
require_equal(__LINE__, row.gamma, false);
}
db(update(tab).set(tab.alpha = 10, tab.beta = "Cookies!", tab.gamma = true).unconditionally());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.alpha.is_null(), false);
require_equal(__LINE__, row.alpha.has_value(), true);
require_equal(__LINE__, row.alpha.value(), 10);
require_equal(__LINE__, row.beta.is_null(), false);
require_equal(__LINE__, row.beta.has_value(), true);
require_equal(__LINE__, row.beta.value(), "Cookies!");
require_equal(__LINE__, row.gamma.is_null(), false);
require_equal(__LINE__, row.gamma.value(), true);
require_equal(__LINE__, row.gamma, true);
}
db(update(tab).set(tab.alpha = 20, tab.beta = "Monster", tab.gamma = false).unconditionally());
@ -95,7 +91,7 @@ int Type(int, char*[])
{
require_equal(__LINE__, row.alpha.value(), 20);
require_equal(__LINE__, row.beta.value(), "Monster");
require_equal(__LINE__, row.gamma.value(), false);
require_equal(__LINE__, row.gamma, false);
}
auto prepared_update = db.prepare(
@ -113,7 +109,7 @@ int Type(int, char*[])
{
require_equal(__LINE__, row.alpha.value(), 30);
require_equal(__LINE__, row.beta.value(), "IceCream");
require_equal(__LINE__, row.gamma.value(), true);
require_equal(__LINE__, row.gamma, true);
}
}
catch (std::exception& e)

View File

@ -50,7 +50,7 @@ int Attach(int, char*[])
db.execute(R"(CREATE TABLE tab_sample (
alpha INTEGER PRIMARY KEY,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
gamma bool
))");
// Attaching another in-memory database and creating the same table in it
@ -58,7 +58,7 @@ int Attach(int, char*[])
db.execute(R"(CREATE TABLE other.tab_sample (
alpha INTEGER PRIMARY KEY,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
gamma bool
))");
auto left = TabSample{};

View File

@ -60,7 +60,8 @@ int AutoIncrement(int, char*[])
std::set<int64_t> results;
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
results.insert(row.alpha);
if (row.alpha)
results.insert(row.alpha.value());
};
const auto expected = std::set<int64_t>{1, 2, 3};
assert(results == expected);

View File

@ -12,7 +12,7 @@
#include <random>
namespace sql = sqlpp::sqlite3;
const auto blob = BlobSample{};
const auto tab = BlobSample{};
/*
* max default blob/text is 1,000,000,000
@ -23,34 +23,30 @@ const auto blob = BlobSample{};
constexpr size_t blob_size = 1000 * 1000ul;
constexpr size_t blob_small_size = 999;
void verify_blob(sql::connection& db, const std::vector<uint8_t>& data, uint64_t id)
void verify_blob(sql::connection& db, const std::vector<uint8_t>& expected, uint64_t id)
{
auto result = db(select(blob.data).from(blob).where(blob.id == id));
auto result = db(select(tab.data).from(tab).where(tab.id == id));
const auto& result_row = result.front();
std::cerr << "Insert size: " << data.size() << std::endl;
std::cerr << "Select size: " << result_row.data.len << std::endl;
if (data.size() != result_row.data.len)
if (!result_row.data)
throw std::runtime_error("blob data is unpexpectedly NULL for id " + std::to_string(id));
const auto received = *result_row.data;
if (expected.size() != received.size())
{
std::cerr << "Size mismatch" << std::endl;
throw std::runtime_error("Size mismatch " + std::to_string(data.size()) +
" != " + std::to_string(result_row.data.len));
throw std::runtime_error("Size mismatch " + std::to_string(expected.size()) +
" != " + std::to_string(received.size()));
}
std::cerr << "Verifying content" << std::endl;
std::vector<uint8_t> result_blob(result_row.data.blob, result_row.data.blob + result_row.data.len);
if (data != result_blob)
for (size_t i = 0; i < expected.size(); i++)
{
std::cout << "Content mismatch ([row] original -> received)" << std::endl;
for (size_t i = 0; i < data.size(); i++)
if (expected[i] != received[i])
{
if (data[i] != result_row.data.blob[i])
{
std::cerr << "[" << i << "] " << static_cast<int>(data.at(i)) << " -> " << static_cast<int>(result_blob.at(i))
<< std::endl;
}
std::cerr << "expected[" << i << "] " << static_cast<int>(expected[i]) << " != received " << static_cast<int>(received[i])
<< std::endl;
throw std::runtime_error("Content mismatch");
}
throw std::runtime_error("Content mismatch");
}
}
@ -77,26 +73,20 @@ int Blob(int, char*[])
std::generate_n(data_smaller.begin(), blob_small_size, generator);
// If we use the bigger blob it will trigger SQLITE_TOOBIG for the query
auto id = db(insert_into(blob).set(blob.data = data_smaller));
auto id = db(insert_into(tab).set(tab.data = data_smaller));
auto prepared_insert = db.prepare(insert_into(blob).set(blob.data = parameter(blob.data)));
auto prepared_insert = db.prepare(insert_into(tab).set(tab.data = parameter(tab.data)));
prepared_insert.params.data = data;
auto prep_id = db(prepared_insert);
const auto prep_id = db(prepared_insert);
prepared_insert.params.data.set_null();
auto null_id = db(prepared_insert);
const auto null_id = db(prepared_insert);
verify_blob(db, data_smaller, id);
verify_blob(db, data, prep_id);
{
auto result = db(select(blob.data).from(blob).where(blob.id == null_id));
auto result = db(select(tab.data).from(tab).where(tab.id == null_id));
const auto& result_row = result.front();
std::cerr << "Null blob is_null:\t" << std::boolalpha << result_row.data.is_null() << std::endl;
std::cerr << "Null blob len == 0:\t" << std::boolalpha << (result_row.data.len == 0) << std::endl;
std::cerr << "Null blob blob == nullptr:\t" << std::boolalpha << (result_row.data.blob == nullptr) << std::endl;
if (!result_row.data.is_null() || result_row.data.len != 0 || result_row.data.blob != nullptr)
{
throw std::runtime_error("Null blob has incorrect values");
}
std::cerr << "Null blob is_null:\t" << std::boolalpha << (result_row.data == sqlpp::nullopt) << std::endl;
}
return 0;
}

View File

@ -78,10 +78,8 @@ int DateTime(int, char*[])
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
{
require_equal(__LINE__, row.colDayPoint.is_null(), true);
require_equal(__LINE__, row.colDayPoint.value(), ::sqlpp::chrono::day_point{});
require_equal(__LINE__, row.colTimePoint.is_null(), true);
require_equal(__LINE__, row.colTimePoint.value(), ::sqlpp::chrono::microsecond_point{});
require_equal(__LINE__, row.colDayPoint == sqlpp::nullopt, true);
require_equal(__LINE__, row.colTimePoint == sqlpp::nullopt, true);
}
db(update(tab).set(tab.colDayPoint = today, tab.colTimePoint = now).unconditionally());

View File

@ -57,7 +57,7 @@ int main()
db.execute("CREATE TABLE tab_sample (\
alpha bigint(20) DEFAULT NULL,\
beta varchar(255) DEFAULT NULL,\
gamma bool DEFAULT NULL\
gamma bool\
)");
const auto tab = TabSample{};

View File

@ -41,6 +41,13 @@
#include <iostream>
#include <vector>
template <typename T>
std::ostream& operator<<(std::ostream& os, const sqlpp::optional<T>& t) {
if (not t)
return os << "NULL";
return os << t.value();
}
SQLPP_ALIAS_PROVIDER(left)
namespace sql = sqlpp::sqlite3;
@ -55,7 +62,7 @@ int DynamicSelect(int, char*[])
db.execute("CREATE TABLE tab_sample (\
alpha bigint(20) DEFAULT NULL,\
beta varchar(255) DEFAULT NULL,\
gamma bool DEFAULT NULL\
gamma bool\
)");
const auto tab = TabSample{};

View File

@ -39,15 +39,22 @@ namespace sql = sqlpp::sqlite3;
const auto fp = FpSample{};
template <typename T>
std::ostream& operator<<(std::ostream& os, const sqlpp::optional<T>& t) {
if (not t)
return os << "NULL";
return os << t.value();
}
template <typename L, typename R>
auto require_equal(int line, const L& l, const R& r) -> void
{
if (l != r)
{
std::cerr << line << ": ";
serialize(::sqlpp::wrap_operand_t<L>{l}, std::cerr);
std::cerr << l;
std::cerr << " != ";
serialize(::sqlpp::wrap_operand_t<R>{r}, std::cerr);
std::cerr << r;
throw std::runtime_error("Unexpected result");
}
}

View File

@ -40,6 +40,13 @@
SQLPP_ALIAS_PROVIDER(pragma)
SQLPP_ALIAS_PROVIDER(sub)
template <typename T>
std::ostream& operator<<(std::ostream& os, const sqlpp::optional<T>& t) {
if (not t)
return os << "NULL";
return os << t.value();
}
namespace sql = sqlpp::sqlite3;
int Sample(int, char*[])
{
@ -52,7 +59,7 @@ int Sample(int, char*[])
db.execute(R"(CREATE TABLE tab_sample (
alpha INTEGER PRIMARY KEY,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
gamma bool
))");
db.execute(R"(CREATE TABLE tab_foo (
omega bigint(20) DEFAULT NULL
@ -102,8 +109,8 @@ int Sample(int, char*[])
.from(tab)
.unconditionally()))
{
int64_t x = row.alpha;
int64_t a = row.max;
sqlpp::optional<int64_t> x = row.alpha;
sqlpp::optional<int64_t> a = row.max;
std::cout << x << ", " << a << std::endl;
}
tx.commit();
@ -134,7 +141,8 @@ int Sample(int, char*[])
}
std::cerr << "--------" << std::endl;
ps.params.alpha = sqlpp::eval<sqlpp::integer>(db, "last_insert_rowid()");
const auto last_id = sqlpp::eval<sqlpp::integer>(db, "last_insert_rowid()");
ps.params.alpha = last_id.value();
ps.params.gamma = false;
for (const auto& row : db(ps))
{

View File

@ -41,6 +41,13 @@
namespace sql = sqlpp::sqlite3;
const auto tab = TabSample{};
template <typename T>
std::ostream& operator<<(std::ostream& os, const sqlpp::optional<T>& t) {
if (not t)
return os << "NULL";
return os << t.value();
}
void testSelectAll(sql::connection& db, size_t expectedRowCount)
{
std::cerr << "--------------------------------------" << std::endl;
@ -50,7 +57,7 @@ void testSelectAll(sql::connection& db, size_t expectedRowCount)
++i;
std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma
<< std::endl;
assert(static_cast<size_t>(row.alpha) == i);
assert(row.alpha == static_cast<int64_t>(i));
};
assert(i == expectedRowCount);
@ -61,7 +68,7 @@ void testSelectAll(sql::connection& db, size_t expectedRowCount)
++i;
std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma
<< std::endl;
assert(static_cast<size_t>(row.alpha) == i);
assert(row.alpha == static_cast<int64_t>(i));
};
assert(i == expectedRowCount);
std::cerr << "--------------------------------------" << std::endl;
@ -93,7 +100,7 @@ int Select(int, char*[])
db.execute(R"(CREATE TABLE tab_sample (
alpha INTEGER PRIMARY KEY,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
gamma bool
))");
testSelectAll(db, 0);
@ -141,8 +148,8 @@ int Select(int, char*[])
auto tx = start_transaction(db);
for (const auto& row : db(select(all_of(tab), select(max(tab.alpha)).from(tab)).from(tab).unconditionally()))
{
const int64_t x = row.alpha;
const int64_t a = row.max;
const auto x = row.alpha;
const auto a = row.max;
std::cout << ">>>" << x << ", " << a << std::endl;
}
for (const auto& row :
@ -153,14 +160,14 @@ int Select(int, char*[])
std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma
<< ", row.trim: '" << row.trim << "'" << std::endl;
// check trim
assert(string_util::trim(row.beta.value()) == row.trim.value());
assert((not row.beta and not row.trim) || string_util::trim(std::string(row.beta.value())) == row.trim.value());
// end
};
for (const auto& row : db(select(all_of(tab), select(trim(tab.beta)).from(tab)).from(tab).unconditionally()))
{
const int64_t x = row.alpha;
const std::string a = row.trim;
const sqlpp::optional<int64_t> x = row.alpha;
const sqlpp::optional<sqlpp::string_view> a = row.trim;
std::cout << ">>>" << x << ", " << a << std::endl;
}

View File

@ -1,5 +1,5 @@
CREATE TABLE tab_sample (
alpha bigint(20) DEFAULT NULL,
beta tinyint(1) DEFAULT NULL,
gamma varchar(255) DEFAULT NULL
gamma varchar(255)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

View File

@ -37,6 +37,13 @@
namespace sql = sqlpp::sqlite3;
const auto tab = TabSample{};
template <typename T>
std::ostream& operator<<(std::ostream& os, const sqlpp::optional<T>& t) {
if (not t)
return os << "NULL";
return os << t.value();
}
int Union(int, char*[])
{
sql::connection_config config;
@ -48,7 +55,7 @@ int Union(int, char*[])
db.execute(R"(CREATE TABLE tab_sample (
alpha INTEGER PRIMARY KEY,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
gamma bool
))");
auto u = select(all_of(tab)).from(tab).unconditionally().union_all(select(all_of(tab)).from(tab).unconditionally());

View File

@ -39,6 +39,13 @@
namespace sql = sqlpp::sqlite3;
const auto tab = TabSample{};
template <typename T>
std::ostream& operator<<(std::ostream& os, const sqlpp::optional<T>& t) {
if (not t)
return os << "NULL";
return os << t.value();
}
int With(int, char*[])
{
#if SQLITE_VERSION_NUMBER >= 3008003
@ -51,7 +58,7 @@ int With(int, char*[])
db.execute(R"(CREATE TABLE tab_sample (
alpha INTEGER PRIMARY KEY,
beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL
gamma bool
))");
auto a = sqlpp::cte(sqlpp::alias::a).as(select(all_of(tab)).from(tab).where(tab.alpha > 3));