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 #pragma once
/* /*
* Copyright (c) 2013-2015, Roland Bock * Copyright (c) 2024, Roland Bock
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * 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. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <sqlpp11/basic_expression_operators.h> #ifdef _MSVC_LANG
#include <sqlpp11/result_field.h> #define CXX_STD_VER _MSVC_LANG
#include <sqlpp11/result_field_base.h> #else
#include <sqlpp11/data_types/integral/data_type.h> #define CXX_STD_VER __cplusplus
#include <sqlpp11/field_spec.h> #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 namespace sqlpp
{ {
template <typename Db, typename NameType, bool CanBeNull> template <typename T>
struct result_field_t<Db, field_spec_t<NameType, integral, CanBeNull>> class span
: public result_field_base<Db, field_spec_t<NameType, integral, CanBeNull>>
{ {
template <typename Target> const T* _data = nullptr;
void _bind(Target& target, size_t index) 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> const char* data() const
void _post_bind(Target& target, size_t index)
{ {
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 } // 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/expression_operators.h>
#include <sqlpp11/data_types/blob/column_operators.h> #include <sqlpp11/data_types/blob/column_operators.h>
#include <sqlpp11/data_types/blob/parameter_value.h> #include <sqlpp11/data_types/blob/parameter_value.h>
#include <sqlpp11/data_types/blob/result_field.h>
// blob specific functions // blob specific functions
#include <sqlpp11/data_types/text/like.h> #include <sqlpp11/data_types/text/like.h>

View File

@ -30,6 +30,7 @@
#include <cstdint> #include <cstdint>
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/compat/span.h>
#include <sqlpp11/logic.h> #include <sqlpp11/logic.h>
namespace sqlpp namespace sqlpp
@ -38,6 +39,7 @@ namespace sqlpp
{ {
using _traits = make_traits<blob, tag::is_value_type>; using _traits = make_traits<blob, tag::is_value_type>;
using _cpp_value_type = std::vector<std::uint8_t>; using _cpp_value_type = std::vector<std::uint8_t>;
using _result_type = sqlpp::span<std::uint8_t>;
template <typename T> template <typename T>
using _is_valid_operand = ::sqlpp::logic::any_t<is_blob_t<T>::value, is_text_t<T>::value>; 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/expression_operators.h>
#include <sqlpp11/data_types/boolean/column_operators.h> #include <sqlpp11/data_types/boolean/column_operators.h>
#include <sqlpp11/data_types/boolean/parameter_value.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 _traits = make_traits<boolean, tag::is_value_type>;
using _cpp_value_type = bool; using _cpp_value_type = bool;
using _result_type = bool;
template <typename T> template <typename T>
using _is_valid_operand = is_boolean_t<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/expression_operators.h>
#include <sqlpp11/data_types/day_point/column_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/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 _traits = make_traits<day_point, tag::is_value_type>;
using _cpp_value_type = ::sqlpp::chrono::day_point; using _cpp_value_type = ::sqlpp::chrono::day_point;
using _result_type = ::sqlpp::chrono::day_point;
template <typename T> template <typename T>
using _is_valid_operand = is_day_or_time_point_t<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/expression_operators.h>
#include <sqlpp11/data_types/floating_point/column_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/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 _traits = make_traits<floating_point, tag::is_value_type>;
using _cpp_value_type = double; using _cpp_value_type = double;
using _result_type = double;
template <typename T> template <typename T>
using _is_valid_operand = is_numeric_t<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/expression_operators.h>
#include <sqlpp11/data_types/integral/column_operators.h> #include <sqlpp11/data_types/integral/column_operators.h>
#include <sqlpp11/data_types/integral/parameter_value.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 _traits = make_traits<integral, tag::is_value_type>;
using _cpp_value_type = int64_t; using _cpp_value_type = int64_t;
using _result_type = int64_t;
template <typename T> template <typename T>
using _is_valid_operand = is_numeric_t<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/expression_operators.h>
#include <sqlpp11/data_types/no_value/column_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/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/expression_operators.h>
#include <sqlpp11/data_types/text/column_operators.h> #include <sqlpp11/data_types/text/column_operators.h>
#include <sqlpp11/data_types/text/parameter_value.h> #include <sqlpp11/data_types/text/parameter_value.h>
#include <sqlpp11/data_types/text/result_field.h>
// text specific functions // text specific functions
#include <sqlpp11/data_types/text/like.h> #include <sqlpp11/data_types/text/like.h>

View File

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

View File

@ -28,9 +28,7 @@
#include <string> #include <string>
#include <utility> #include <utility>
#if __cplusplus >= 201703L #include <sqlpp11/compat/string_view.h>
#include <string_view>
#endif
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/alias_operators.h> #include <sqlpp11/alias_operators.h>
@ -51,16 +49,14 @@ namespace sqlpp
text_operand(_value_t t) : _t(std::move(t)) text_operand(_value_t t) : _t(std::move(t))
{ {
} }
#if __cplusplus >= 201703L // allow construction from an sqlpp::string_view
// allow construction from an std::string_view text_operand(sqlpp::string_view t) : _t(t)
text_operand(std::string_view t) : _t(t)
{ {
} }
// additional const char* overload, required to disambiguate // additional const char* overload, required to disambiguate
text_operand(const char* t) : _t(t) text_operand(const char* t) : _t(t)
{ {
} }
#endif
text_operand(const text_operand&) = default; text_operand(const text_operand&) = default;
text_operand(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/wrap_operand.h>
#include <sqlpp11/data_types/text/operand.h> #include <sqlpp11/data_types/text/operand.h>
#if __cplusplus >= 201703L #include <sqlpp11/compat/string_view.h>
#include <string_view>
#endif
namespace sqlpp namespace sqlpp
{ {
@ -51,8 +49,7 @@ namespace sqlpp
target._bind_text_parameter(index, &_value, _is_null); target._bind_text_parameter(index, &_value, _is_null);
} }
#if __cplusplus >= 201703L parameter_value_base& operator=(const sqlpp::string_view& val)
parameter_value_base& operator=(const std::string_view& val)
{ {
_value = val; _value = val;
_is_null = false; _is_null = false;
@ -65,6 +62,5 @@ namespace sqlpp
_is_null = false; _is_null = false;
return *this; return *this;
} }
#endif
}; };
} // namespace sqlpp } // 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> #include <utility>
#if __cplusplus >= 201703L #include <sqlpp11/compat/string_view.h>
#include <string_view>
#endif
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/wrap_operand.h> #include <sqlpp11/wrap_operand.h>
namespace sqlpp namespace sqlpp
{ {
struct text_operand; struct text_operand;
using checked_type = sqlpp::string_view;
#if __cplusplus >= 201703L
using checked_type = std::string_view;
#else
using checked_type = std::string;
#endif
template <typename T> template <typename T>
struct wrap_operand< 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/expression_operators.h>
#include <sqlpp11/data_types/time_of_day/column_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/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 _traits = make_traits<time_of_day, tag::is_value_type>;
using _cpp_value_type = std::chrono::microseconds; using _cpp_value_type = std::chrono::microseconds;
using _result_type = std::chrono::microseconds;
template <typename T> template <typename T>
using _is_valid_operand = is_time_of_day_t<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/expression_operators.h>
#include <sqlpp11/data_types/time_point/column_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/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 _traits = make_traits<time_point, tag::is_value_type>;
using _cpp_value_type = ::sqlpp::chrono::microsecond_point; using _cpp_value_type = ::sqlpp::chrono::microsecond_point;
using _result_type = ::sqlpp::chrono::microsecond_point;
template <typename T> template <typename T>
using _is_valid_operand = is_day_or_time_point_t<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/expression_operators.h>
#include <sqlpp11/data_types/unsigned_integral/column_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/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 _traits = make_traits<unsigned_integral, tag::is_value_type>;
using _cpp_value_type = uint64_t; using _cpp_value_type = uint64_t;
using _result_type = uint64_t;
template <typename T> template <typename T>
using _is_valid_operand = is_numeric_t<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 _name_type = alias::a_t::_alias_t;
using _value_type = value_type_of<Expr>; using _value_type = value_type_of<Expr>;
using _field_spec = field_spec_t<_name_type, _value_type, true>; 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, template <typename Db,

View File

@ -28,6 +28,10 @@
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <type_traits>
#include <sqlpp11/compat/optional.h>
namespace sqlpp namespace sqlpp
{ {
template <typename NameType, typename ValueType, bool CanBeNull> template <typename NameType, typename ValueType, bool CanBeNull>
@ -39,6 +43,10 @@ namespace sqlpp
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _alias_t = NameType; 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> template <typename Left, typename Right, typename Enable = void>

View File

@ -28,6 +28,9 @@
#include <sqlpp11/chrono.h> #include <sqlpp11/chrono.h>
#include <sqlpp11/exception.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/detail/prepared_statement_handle.h>
#include <sqlpp11/mysql/sqlpp_mysql.h> #include <sqlpp11/mysql/sqlpp_mysql.h>
@ -45,6 +48,7 @@ namespace sqlpp
{ {
std::shared_ptr<detail::prepared_statement_handle_t> _handle; std::shared_ptr<detail::prepared_statement_handle_t> _handle;
void* _result_row_address{nullptr}; void* _result_row_address{nullptr};
bool _require_bind = true;
public: public:
bind_result_t() = default; bind_result_t() = default;
@ -79,17 +83,23 @@ namespace sqlpp
if (&result_row != _result_row_address) if (&result_row != _result_row_address)
{ {
result_row._bind(*this); // sets row data to mysql bind data result_row._bind_fields(*this); // sets row data to mysql bind data
bind_impl(); // binds mysql statement to data
_result_row_address = &result_row; _result_row_address = &result_row;
} }
if (_require_bind)
{
bind_impl(); // binds mysql statement to data
_require_bind = false;
}
if (next_impl()) if (next_impl())
{ {
if (not result_row) if (not result_row)
{ {
result_row._validate(); 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 else
{ {
@ -103,270 +113,289 @@ namespace sqlpp
return !_handle or !*_handle; 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) 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; << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]}; auto& buffer{_handle->result_buffers[index]};
meta_data.index = index; new (&buffer._bool) bool{};
meta_data.len = nullptr;
meta_data.is_null = is_null;
MYSQL_BIND& param{_handle->result_params[index]}; MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_TINY; param.buffer_type = MYSQL_TYPE_TINY;
param.buffer = value; param.buffer = &buffer._bool;
param.buffer_length = sizeof(*value); param.buffer_length = sizeof(buffer._bool);
param.length = &meta_data.bound_len; param.length = &buffer.length;
param.is_null = &meta_data.bound_is_null; param.is_null = &buffer.is_null;
param.is_unsigned = false; 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) 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; << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]}; auto& buffer{_handle->result_buffers[index]};
meta_data.index = index; new (&buffer._int64) int64_t{};
meta_data.len = nullptr;
meta_data.is_null = is_null;
MYSQL_BIND& param{_handle->result_params[index]}; MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_LONGLONG; param.buffer_type = MYSQL_TYPE_LONGLONG;
param.buffer = value; param.buffer = &buffer._int64;
param.buffer_length = sizeof(*value); param.buffer_length = sizeof(buffer._int64);
param.length = &meta_data.bound_len; param.length = &buffer.length;
param.is_null = &meta_data.bound_is_null; param.is_null = &buffer.is_null;
param.is_unsigned = false; 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) if (_handle->debug)
std::cerr << "MySQL debug: binding unsigned integral result " << static_cast<void*>(value) std::cerr << "MySQL debug: binding unsigned integral result at index: " << index << std::endl;
<< " at index: " << index << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]}; auto& buffer{_handle->result_buffers[index]};
meta_data.index = index; new (&buffer._uint64) uint64_t{};
meta_data.len = nullptr;
meta_data.is_null = is_null;
MYSQL_BIND& param{_handle->result_params[index]}; MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_LONGLONG; param.buffer_type = MYSQL_TYPE_LONGLONG;
param.buffer = value; param.buffer = &buffer._uint64;
param.buffer_length = sizeof(*value); param.buffer_length = sizeof(buffer._uint64);
param.length = &meta_data.bound_len; param.length = &buffer.length;
param.is_null = &meta_data.bound_is_null; param.is_null = &buffer.is_null;
param.is_unsigned = true; 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) if (_handle->debug)
std::cerr << "MySQL debug: binding floating point result " << static_cast<void*>(value) std::cerr << "MySQL debug: binding floating point result at index: " << index << std::endl;
<< " at index: " << index << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]}; auto& buffer{_handle->result_buffers[index]};
meta_data.index = index; new (&buffer._double) double{};
meta_data.len = nullptr;
meta_data.is_null = is_null;
MYSQL_BIND& param{_handle->result_params[index]}; MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_DOUBLE; param.buffer_type = MYSQL_TYPE_DOUBLE;
param.buffer = value; param.buffer = &buffer._double;
param.buffer_length = sizeof(*value); param.buffer_length = sizeof(buffer._double);
param.length = &meta_data.bound_len; param.length = &buffer.length;
param.is_null = &meta_data.bound_is_null; param.is_null = &buffer.is_null;
param.is_unsigned = false; 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) 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; << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]}; auto& buffer{_handle->result_buffers[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);
MYSQL_BIND& param{_handle->result_params[index]}; MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_STRING; param.buffer_type = MYSQL_TYPE_STRING;
param.buffer = meta_data.bound_text_buffer.data(); param.buffer = buffer.var_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size(); param.buffer_length = buffer.var_buffer.size();
param.length = &meta_data.bound_len; param.length = &buffer.length;
param.is_null = &meta_data.bound_is_null; param.is_null = &buffer.is_null;
param.is_unsigned = false; 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) 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; << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]}; auto& buffer{_handle->result_buffers[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);
MYSQL_BIND& param{_handle->result_params[index]}; MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_BLOB; param.buffer_type = MYSQL_TYPE_BLOB;
param.buffer = meta_data.bound_text_buffer.data(); param.buffer = buffer.var_buffer.data();
param.buffer_length = meta_data.bound_text_buffer.size(); param.buffer_length = buffer.var_buffer.size();
param.length = &meta_data.bound_len; param.length = &buffer.length;
param.is_null = &meta_data.bound_is_null; param.is_null = &buffer.is_null;
param.is_unsigned = false; 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) auto& buffer{_handle->result_buffers[index]};
std::cerr << "MySQL debug: binding date result " << static_cast<void*>(value) << " at index: " << index new (&buffer._mysql_time) MYSQL_TIME{};
<< 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]}; MYSQL_BIND& param{_handle->result_params[index]};
param.buffer_type = MYSQL_TYPE_DATE; param.buffer_type = buffer_type;
param.buffer = meta_data.bound_text_buffer.data(); param.buffer = &buffer._mysql_time;
param.buffer_length = meta_data.bound_text_buffer.size(); param.buffer_length = sizeof(buffer._mysql_time);
param.length = &meta_data.bound_len; param.length = &buffer.length;
param.is_null = &meta_data.bound_is_null; param.is_null = &buffer.is_null;
param.is_unsigned = false; 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) 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; << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]}; bind_chrono_field(index, MYSQL_TYPE_DATE);
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;
} }
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) 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; << std::endl;
detail::result_meta_data_t& meta_data{_handle->result_param_meta_data[index]}; bind_chrono_field(index, MYSQL_TYPE_DATETIME);
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;
} }
void _post_bind_boolean_result(size_t /* index */, signed char* /* value */, bool* /* is_null */) void bind_field(size_t index, ::std::chrono::microseconds& /*value*/)
{
}
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)
{ {
if (_handle->debug) 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; << 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 = if (_handle->debug)
*reinterpret_cast<const MYSQL_TIME*>(_handle->result_param_meta_data[index].bound_text_buffer.data()); std::cerr << "MySQL debug: increasing buffer at: " << index << " to " << *params.length << std::endl;
if (dt.year > std::numeric_limits<int>::max()) buffer.var_buffer.resize(*params.length);
throw sqlpp::exception{"cannot read year from db: " + std::to_string(dt.year)}; params.buffer = buffer.var_buffer.data();
*is_null = false; params.buffer_length = buffer.var_buffer.size();
*value = ::date::year(static_cast<int>(dt.year)) / ::date::month(dt.month) / ::date::day(dt.day); 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) 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; << std::endl;
refetch_if_required(index);
if (not *is_null) const auto& buffer = _handle->result_buffers[index];
{ const auto& params = _handle->result_params[index];
const auto& dt = value = sqlpp::string_view(buffer.var_buffer.data(), *params.length);
*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);
}
} }
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) 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; << 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 = value.reset();
*reinterpret_cast<const MYSQL_TIME*>(_handle->result_param_meta_data[index].bound_text_buffer.data()); return;
*value = std::chrono::hours(dt.hour) + std::chrono::minutes(dt.minute) + std::chrono::seconds(dt.second) +
std::chrono::microseconds(dt.second_part);
} }
if (!value)
value = T{};
read_field(index, *value);
} }
private: private:
@ -387,58 +416,12 @@ namespace sqlpp
if (_handle->debug) if (_handle->debug)
std::cerr << "MySQL debug: Accessing next row of handle at " << _handle.get() << std::endl; 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) switch (flag)
{ {
case 0: case 0:
case MYSQL_DATA_TRUNCATED: 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; return true;
case 1: case 1:
throw sqlpp::exception{std::string{"MySQL: Could not fetch next result: "} + 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/detail/result_handle.h>
#include <sqlpp11/mysql/sqlpp_mysql.h> #include <sqlpp11/mysql/sqlpp_mysql.h>
#include <sqlpp11/mysql/char_result_row.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 namespace sqlpp
{ {
@ -88,7 +91,7 @@ namespace sqlpp
{ {
result_row._validate(); result_row._validate();
} }
result_row._bind(*this); result_row._read_fields(*this);
} }
else else
{ {
@ -102,114 +105,102 @@ namespace sqlpp
return !_handle or !*_handle; 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 = (_char_result_row.data[index][0] == 't' or _char_result_row.data[index][0] == '1');
*value =
(*is_null ? false : (_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 = std::strtod(_char_result_row.data[index], nullptr);
*value = (*is_null ? 0 : 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 = std::strtoll(_char_result_row.data[index], nullptr, 10);
*value = (*is_null ? 0 : 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 = std::strtoull(_char_result_row.data[index], nullptr, 10);
*value = (*is_null ? 0 : 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 = sqlpp::span<uint8_t>(reinterpret_cast<const uint8_t*>(_char_result_row.data[index]), _char_result_row.len[index]);
*value = (uint8_t*)(is_null ? nullptr : _char_result_row.data[index]);
*len = (is_null ? 0 : _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 = sqlpp::string_view(_char_result_row.data[index], _char_result_row.len[index]);
*value = (is_null ? nullptr : _char_result_row.data[index]);
*len = (is_null ? 0 : _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) if (_handle->debug)
std::cerr << "MySQL debug: parsing date result at index: " << index << std::endl; 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]; const auto date_string = _char_result_row.data[index];
if (_handle->debug) if (_handle->debug)
std::cerr << "MySQL debug: date string: " << date_string << std::endl; 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) if (_handle->debug)
std::cerr << "MySQL debug: invalid date result: " << date_string << std::endl; 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) if (_handle->debug)
std::cerr << "MySQL debug: parsing date result at index: " << index << std::endl; 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]; const auto date_time_string = _char_result_row.data[index];
if (_handle->debug) if (_handle->debug)
std::cerr << "MySQL debug: date_time string: " << date_time_string << std::endl; 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) if (_handle->debug)
std::cerr << "MySQL debug: invalid date_time result: " << date_time_string << std::endl; 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) if (_handle->debug)
std::cerr << "MySQL debug: parsing time of day result at index: " << index << std::endl; 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]; const auto time_string = _char_result_row.data[index];
if (_handle->debug) if (_handle->debug)
std::cerr << "MySQL debug: time of day string: " << time_string << std::endl; 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) if (_handle->debug)
std::cerr << "MySQL debug: invalid time result: " << time_string << std::endl; 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: private:
bool next_impl() bool next_impl()
{ {

View File

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

View File

@ -30,6 +30,9 @@
#include <sqlpp11/chrono.h> #include <sqlpp11/chrono.h>
#include <sqlpp11/data_types.h> #include <sqlpp11/data_types.h>
#include <sqlpp11/detail/parse_date_time.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 <iomanip>
#include <iostream> #include <iostream>
@ -49,10 +52,63 @@ namespace sqlpp
namespace detail namespace detail
{ {
struct statement_handle_t; 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 class bind_result_t
{ {
// Need to buffer blobs (or switch to PQexecParams with binary results)
std::vector<std::vector<uint8_t>> _var_buffers;
private: private:
std::shared_ptr<detail::statement_handle_t> _handle; 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) 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()) if (this->_handle && this->_handle->debug())
{ {
// cerr
std::cerr << "PostgreSQL debug: constructing bind result, using handle at: " << this->_handle.get() std::cerr << "PostgreSQL debug: constructing bind result, using handle at: " << this->_handle.get()
<< std::endl; << std::endl;
} }
@ -131,7 +187,7 @@ namespace sqlpp
{ {
result_row._validate(); result_row._validate();
} }
result_row._bind(*this); result_row._read_fields(*this);
} }
else 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()) 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()) 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()) 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()) 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()) 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 = sqlpp::string_view(_handle->result.get_char_ptr_value(_handle->count, index),
{ static_cast<size_t>(_handle->result.length(_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));
}
} }
// PostgreSQL will return one of those (using the default ISO client): // 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 // 1992-10-10 01:02:03-06:30 - for some timezones with non-hour offset
// 1900-01-01 - date only // 1900-01-01 - date only
// we do not support time-only values ! // 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()) if (_handle->debug())
{ {
std::cerr << "PostgreSQL debug: binding date result at index: " << index << std::endl; std::cerr << "PostgreSQL debug: reading date result at index: " << index << std::endl;
}
*value = {};
*is_null = _handle->result.is_null(_handle->count, index);
if (*is_null)
{
return;
} }
const auto date_string = _handle->result.get_char_ptr_value(_handle->count, index); 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; 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()) if (_handle->debug())
{ {
@ -249,19 +286,12 @@ namespace sqlpp
} }
// always returns UTC time for timestamp with time zone // 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()) if (_handle->debug())
{ {
std::cerr << "PostgreSQL debug: binding date_time result at index: " << index << std::endl; std::cerr << "PostgreSQL debug: reading date_time result at index: " << index << std::endl;
}
*value = {};
*is_null = _handle->result.is_null(_handle->count, index);
if (*is_null)
{
return;
} }
const auto date_string = _handle->result.get_char_ptr_value(_handle->count, index); 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; 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()) if (_handle->debug())
{ {
@ -279,19 +309,12 @@ namespace sqlpp
} }
// always returns UTC time for time with time zone // 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()) if (_handle->debug())
{ {
std::cerr << "PostgreSQL debug: binding time result at index: " << index << std::endl; std::cerr << "PostgreSQL debug: reading time result at index: " << index << std::endl;
}
*value = {};
*is_null = _handle->result.is_null(_handle->count, index);
if (*is_null)
{
return;
} }
const auto time_string = _handle->result.get_char_ptr_value(_handle->count, index); 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; 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()) { if (_handle->debug()) {
std::cerr << "PostgreSQL debug: got invalid time '" << time_string << "'" << std::endl; 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()) 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)) if (_handle->result.is_null(_handle->count, index))
{ {
*value = nullptr; value.reset();
*len = 0;
} }
else else
{ {
*value = _handle->result.get_blob_value(_handle->count, index); if (not value)
*len = static_cast<size_t>(_handle->result.length(_handle->count, index)); {
value = T{};
}
read_field(_index, *value);
} }
} }

View File

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

View File

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

View File

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

View File

@ -31,6 +31,9 @@
#include <sqlpp11/exception.h> #include <sqlpp11/exception.h>
#include <sqlpp11/sqlite3/detail/prepared_statement_handle.h> #include <sqlpp11/sqlite3/detail/prepared_statement_handle.h>
#include <sqlpp11/sqlite3/export.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 <iostream>
#include <memory> #include <memory>
@ -83,7 +86,7 @@ namespace sqlpp
{ {
result_row._validate(); result_row._validate();
} }
result_row._bind(*this); result_row._read_fields(*this);
} }
else 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) 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))); 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;
} }
void _bind_floating_point_result(size_t index, double* value, bool* is_null) void read_field(size_t index, double& value)
{ {
if (_handle->debug) 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))) switch (sqlite3_column_type(_handle->sqlite_statement, static_cast<int>(index)))
{ {
case (SQLITE3_TEXT): case (SQLITE3_TEXT):
*value = atof( value = atof(
reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index)))); reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index))));
break; break;
default: 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) 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)); 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;
} }
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) if (_handle->debug)
std::cerr << "Sqlite3 debug: binding unsigned integral result " << *value << " at index: " << index std::cerr << "Sqlite3 debug: binding unsigned integral result at index: " << index << std::endl;
<< std::endl;
*value = static_cast<uint64_t>(sqlite3_column_int64(_handle->sqlite_statement, static_cast<int>(index))); 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;
} }
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) if (_handle->debug)
std::cerr << "Sqlite3 debug: binding text result at index: " << index << std::endl; std::cerr << "Sqlite3 debug: binding text result at index: " << index << std::endl;
*value = value = sqlpp::string_view(
(reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index)))); 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))); 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) 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 = value = sqlpp::span<uint8_t>(
(reinterpret_cast<const uint8_t*>(sqlite3_column_blob(_handle->sqlite_statement, static_cast<int>(index)))); 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))); 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) if (_handle->debug)
std::cerr << "Sqlite3 debug: binding date result at index: " << index << std::endl; 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 = const auto date_string =
reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index))); reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index)));
if (_handle->debug) if (_handle->debug)
std::cerr << "Sqlite3 debug: date string: " << date_string << std::endl; 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) if (_handle->debug)
std::cerr << "Sqlite3 debug: invalid date result: " << date_string << std::endl; 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) if (_handle->debug)
std::cerr << "Sqlite3 debug: binding date result at index: " << index << std::endl; 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 = const auto date_time_string =
reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index))); reinterpret_cast<const char*>(sqlite3_column_text(_handle->sqlite_statement, static_cast<int>(index)));
if (_handle->debug) if (_handle->debug)
std::cerr << "Sqlite3 debug: date_time string: " << date_time_string << std::endl; std::cerr << "Sqlite3 debug: date_time string: " << date_time_string << std::endl;
// We treat DATETIME fields as containing either date+time or just date. // 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) if (_handle->debug)
std::cerr << "Sqlite3 debug: invalid date_time result: " << date_time_string << std::endl; 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: private:
bool next_impl() bool next_impl()
{ {

View File

@ -47,12 +47,11 @@ int Insert(int, char* [])
"INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")"); "INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")");
compare(__LINE__, insert_into(bar).set(bar.beta = ::sqlpp::null, bar.gamma = true), compare(__LINE__, insert_into(bar).set(bar.beta = ::sqlpp::null, bar.gamma = true),
"INSERT INTO tab_bar (beta,gamma) VALUES(NULL," + getTrue() + ")"); "INSERT INTO tab_bar (beta,gamma) VALUES(NULL," + getTrue() + ")");
#if __cplusplus >= 201703L sqlpp::string_view cheeseCake = "cheesecake";
// string_view argument compare(__LINE__, insert_into(bar).set(bar.beta = std::string(cheeseCake), bar.gamma = true),
std::string_view cheeseCake = "cheesecake"; "INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")");
compare(__LINE__, insert_into(bar).set(bar.beta = cheeseCake, bar.gamma = true), compare(__LINE__, insert_into(bar).set(bar.beta = sqlpp::string_view(cheeseCake), bar.gamma = true),
"INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")"); "INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")");
#endif
return 0; 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("SQL"))), " WHERE (tab_bar.beta='SQL')");
compare(__LINE__, where(is_equal_to_or_null(bar.beta, ::sqlpp::value_or_null<sqlpp::text>(::sqlpp::null))), compare(__LINE__, where(is_equal_to_or_null(bar.beta, ::sqlpp::value_or_null<sqlpp::text>(::sqlpp::null))),
" WHERE tab_bar.beta IS 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 // string_view argument
std::string_view sqlString = "SQL"; compare(__LINE__, where(bar.beta == sqlpp::string_view("SQL")), " WHERE (tab_bar.beta='SQL')");
compare(__LINE__, where(bar.beta == sqlString), " WHERE (tab_bar.beta='SQL')");
#endif
return 0; return 0;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,6 +28,7 @@
#include "is_regular.h" #include "is_regular.h"
#include <sqlpp11/functions.h> #include <sqlpp11/functions.h>
#include <sqlpp11/select.h> #include <sqlpp11/select.h>
#include "../../include/test_helpers.h"
int Prepared(int, char* []) int Prepared(int, char* [])
{ {
@ -132,7 +133,10 @@ int Prepared(int, char* [])
// Can we prepare a query without parameters? // Can we prepare a query without parameters?
{ {
auto ps = db.prepare(select(all_of(t)).from(t).where((t.beta.like("%")))); 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 // Check that a prepared select is default-constructable

View File

@ -28,6 +28,9 @@
#include "MockDb.h" #include "MockDb.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
int Result(int, char* []) int Result(int, char* [])
{ {
MockDb db = {}; MockDb db = {};
@ -39,28 +42,24 @@ int Result(int, char* [])
// Using a non-enforcing db // Using a non-enforcing db
for (const auto& row : db(select(all_of(t), t.beta.like("")).from(t).unconditionally())) 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(is_optional<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");
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; 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); 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())) 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())) 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); 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/functions.h>
#include <sqlpp11/select.h> #include <sqlpp11/select.h>
#include <sqlpp11/without_table_check.h> #include <sqlpp11/without_table_check.h>
#include "../../include/test_helpers.h"
template <typename Db, typename Column> template <typename Db, typename Column>
int64_t getColumn(Db&& db, const Column& column) int64_t getColumn(Db&& db, const Column& column)
{ {
auto result = db(select(column.as(sqlpp::alias::a)).from(column.table()).unconditionally()); auto result = db(select(column.as(sqlpp::alias::a)).from(column.table()).unconditionally());
if (not result.empty()) if (not result.empty() and result.front().a.has_value())
return result.front().a; return result.front().a.value();
else else
return 0; return 0;
} }
@ -49,15 +50,15 @@ struct to_cerr
template <typename Field> template <typename Field>
auto operator()(const Field& field) const -> void auto operator()(const Field& field) const -> void
{ {
std::cerr << get_sql_name(field) << " = " << field << std::endl; std::cerr << field << std::endl;
} }
}; };
template <typename Row> template <typename Row>
void print_row(Row const& row) void print_row(Row const& row)
{ {
int64_t a = row.alpha; const sqlpp::optional<int64_t> a = row.alpha;
const std::string b = row.beta; const sqlpp::optional<sqlpp::string_view> b = row.beta;
std::cout << a << ", " << b << std::endl; 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())) for (const auto& row : db(select(all_of(t)).from(t).unconditionally()))
{ {
int64_t a = row.alpha; const sqlpp::optional<int64_t> a = row.alpha;
const std::string b = row.beta; const sqlpp::optional<sqlpp::string_view> b = row.beta;
std::cout << a << ", " << b << std::endl; std::cout << a << ", " << b << std::endl;
} }
for (const auto& row : 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())) 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 sqlpp::optional<int64_t> a = row.alpha;
const std::string b = row.beta; const sqlpp::optional<sqlpp::string_view> b = row.beta;
const bool g = row.tabBar; const bool g = row.tabBar;
std::cout << a << ", " << b << ", " << g << std::endl; 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)); s.order_by.add(t.delta.order(sqlpp::sort_type::desc));
for (const auto& row : db(db.prepare(s))) 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; std::cout << a << std::endl;
} }
@ -187,7 +188,7 @@ int Select(int, char*[])
select(sqlpp::value(7).as(t.alpha)); select(sqlpp::value(7).as(t.alpha));
for (const auto& row : 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; std::cerr << row.beta << std::endl;
} }

View File

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

View File

@ -28,6 +28,7 @@
#include <sqlpp11/select.h> #include <sqlpp11/select.h>
#include <sqlpp11/alias_provider.h> #include <sqlpp11/alias_provider.h>
#include <iostream> #include <iostream>
#include "../../include/test_helpers.h"
int With(int, char*[]) 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/mysql/mysql.h>
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
@ -36,20 +38,6 @@ const auto library_raii = sqlpp::mysql::scoped_library_initializer_t{};
namespace 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> template <typename L, typename R>
auto require_close(int line, const L& l, const R& r) -> void 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()); db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) 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.has_value(), false);
require_equal(__LINE__, row.colDayPoint.value(), ::sqlpp::chrono::day_point{}); require_equal(__LINE__, row.colTimePoint.has_value(), false);
require_equal(__LINE__, row.colTimePoint.is_null(), true); require_close(__LINE__, row.colDateTimePoint, now);
require_equal(__LINE__, row.colTimePoint.value(), ::sqlpp::chrono::microsecond_point{}); require_equal(__LINE__, row.colTimeOfDay.has_value(), false);
require_close(__LINE__, row.colDateTimePoint.value(), now);
require_equal(__LINE__, row.colTimeOfDay.is_null(), true);
require_equal(__LINE__, row.colTimeOfDay.value(), ::std::chrono::microseconds{});
} }
db(update(tab).set(tab.colDayPoint = today, tab.colTimePoint = now, tab.colTimeOfDay = current).unconditionally()); 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()); auto statement = db.prepare(select(all_of(tab)).from(tab).unconditionally());
for (const auto& row : db(statement)) for (const auto& row : db(statement))
{ {
require_equal(__LINE__, row.colDateTimePoint.is_null(), false); require_close(__LINE__, row.colDateTimePoint, now);
require_close(__LINE__, row.colDateTimePoint.value(), now);
require_equal(__LINE__, row.colDayPoint.value(), today); require_equal(__LINE__, row.colDayPoint.value(), today);
require_equal(__LINE__, row.colTimePoint.value(), now); require_equal(__LINE__, row.colTimePoint.value(), now);
require_close(__LINE__, row.colTimeOfDay.value(), current); require_close(__LINE__, row.colTimeOfDay.value(), current);

View File

@ -48,9 +48,9 @@ int DynamicSelect(int, char*[])
auto db = sql::make_test_connection(); auto db = sql::make_test_connection();
db.execute(R"(DROP TABLE IF EXISTS tab_sample)"); db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE 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, beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL gamma bool NOT NULL DEFAULT 0
))"); ))");
const auto tab = TabSample{}; const auto tab = TabSample{};

View File

@ -78,10 +78,10 @@ int Json(int, char*[])
if (result.empty()) if (result.empty())
throw std::runtime_error{"selection result is 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") 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) 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"(DROP TABLE IF EXISTS tab_sample)");
connections.at(0).execute(R"(CREATE TABLE 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, beta varchar(255) DEFAULT NULL,
gamma bool DEFAULT NULL gamma bool NOT NULL DEFAULT 0
))"); ))");
assert(connections.at(0).is_transaction_active() == false); assert(connections.at(0).is_transaction_active() == false);

View File

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

View File

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

View File

@ -34,6 +34,7 @@
#include <sqlpp11/select.h> #include <sqlpp11/select.h>
#include <sqlpp11/transaction.h> #include <sqlpp11/transaction.h>
#include <sqlpp11/update.h> #include <sqlpp11/update.h>
#include "../../include/test_helpers.h"
#include <iostream> #include <iostream>
#include <vector> #include <vector>
@ -51,14 +52,13 @@ int Truncated(int, char*[])
auto db = sql::make_test_connection(); auto db = sql::make_test_connection();
db.execute(R"(DROP TABLE IF EXISTS tab_sample)"); db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
db.execute(R"(CREATE TABLE 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, 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)"); db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
db.execute(R"(CREATE TABLE 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")); db(insert_into(tab).set(tab.gamma = true, tab.beta = "cheese"));

View File

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

View File

@ -41,35 +41,30 @@ const auto blob = model::BlobSample{};
constexpr size_t blob_size = 1000 * 1000ul; constexpr size_t blob_size = 1000 * 1000ul;
constexpr size_t blob_small_size = 999; 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(blob.data).from(blob).where(blob.id == id));
const auto& result_row = result.front(); const auto& result_row = result.front();
std::cerr << "id: " << id << std::endl; if (!result_row.data)
std::cerr << "Insert size: " << data.size() << std::endl; throw std::runtime_error("blob data is unpexpectedly NULL for id " + std::to_string(id));
std::cerr << "Select size: " << result_row.data.len << std::endl; const auto received = *result_row.data;
if (data.size() != result_row.data.len)
if (expected.size() != received.size())
{ {
std::cerr << "Size mismatch" << std::endl; std::cerr << "Size mismatch" << std::endl;
throw std::runtime_error("Size mismatch " + std::to_string(data.size()) + throw std::runtime_error("Size mismatch " + std::to_string(expected.size()) +
" != " + std::to_string(result_row.data.len)); " != " + std::to_string(received.size()));
} }
std::cerr << "Verifying content" << std::endl; std::cerr << "Verifying content" << std::endl;
const auto result_blob = result_row.data.value(); for (size_t i = 0; i < expected.size(); i++)
if (data != result_blob)
{ {
std::cout << "Content mismatch ([row] original -> received)" << std::endl; if (expected[i] != received[i])
for (size_t i = 0; i < data.size(); i++)
{ {
if (data[i] != result_row.data.value()[i]) std::cerr << "expected[" << i << "] " << static_cast<int>(expected[i]) << " != received " << static_cast<int>(received[i])
{ << std::endl;
std::cerr << "[" << i << "] " << static_cast<int>(data.at(i)) << " -> " << static_cast<int>(result_blob.at(i)) throw std::runtime_error("Content mismatch");
<< std::endl;
}
} }
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)); auto result = db(select(blob.data).from(blob).where(blob.id == null_id));
const auto& result_row = result.front(); 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 is_null:\t" << std::boolalpha << (result_row.data == sqlpp::nullopt) << std::endl;
std::cerr << "Null blob len == 0:\t" << std::boolalpha << (result_row.data.len == 0) << std::endl; if (result_row.data.has_value())
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)
{ {
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()); db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) 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.has_value(), false);
require_equal(__LINE__, row.colDayPoint.value(), ::sqlpp::chrono::day_point{}); require_equal(__LINE__, row.colTimePoint.has_value(), false);
require_equal(__LINE__, row.colTimePoint.is_null(), true);
require_equal(__LINE__, row.colTimePoint.value(), ::sqlpp::chrono::microsecond_point{});
} }
db(update(tab).set(tab.colDayPoint = today, tab.colTimePoint = now).unconditionally()); 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()); db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) 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.has_value(), false);
require_equal(__LINE__, row.c_day.value(), ::sqlpp::chrono::day_point{}); require_equal(__LINE__, row.c_time.has_value(), false);
require_equal(__LINE__, row.c_time.is_null(), true); require_equal(__LINE__, row.c_timepoint.has_value(), false);
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{});
} }
db(update(tab).set(tab.c_day = today, tab.c_time = current, tab.c_timepoint = now).unconditionally()); 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 "TabBar.h"
#include "TabFoo.h" #include "TabFoo.h"
#include "make_test_connection.h" #include "make_test_connection.h"
#include "../../include/test_helpers.h"
namespace sql = sqlpp::postgresql; namespace sql = sqlpp::postgresql;

View File

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

View File

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

View File

@ -32,56 +32,10 @@
#include <sqlpp11/postgresql/connection.h> #include <sqlpp11/postgresql/connection.h>
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#include <sqlpp11/transaction.h> #include <sqlpp11/transaction.h>
#include "../../include/test_helpers.h"
#include "make_test_connection.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; namespace sql = sqlpp::postgresql;
SQLPP_ALIAS_PROVIDER(level); SQLPP_ALIAS_PROVIDER(level);
@ -95,10 +49,10 @@ int Transaction(int, char*[])
{ {
require_equal(__LINE__, db.is_transaction_active(), false); require_equal(__LINE__, db.is_transaction_active(), false);
auto current_level = db(custom_query(sqlpp::verbatim("show transaction_isolation;")) auto current_level = std::string(db(custom_query(sqlpp::verbatim("show transaction_isolation;"))
.with_result_type_of(select(sqlpp::value("").as(level)))) .with_result_type_of(select(sqlpp::value("").as(level))))
.front() .front()
.level; .level);
require_equal(__LINE__, current_level, "read committed"); require_equal(__LINE__, current_level, "read committed");
std::cerr << "isolation level outside transaction: " << current_level << "\n"; std::cerr << "isolation level outside transaction: " << current_level << "\n";

View File

@ -51,7 +51,7 @@ namespace
{ {
// prepare test with timezone // prepare test with timezone
db.execute("DROP TABLE IF EXISTS tab_sample"); 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()); db(insert_into(tab).default_values());
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) 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.has_value(), false);
require_equal(__LINE__, row.alpha.value(), 0); require_equal(__LINE__, row.beta.has_value(), false);
require_equal(__LINE__, row.beta.is_null(), true); require_equal(__LINE__, row.gamma, false);
require_equal(__LINE__, row.beta.value(), "");
require_equal(__LINE__, row.gamma.is_null(), true);
require_equal(__LINE__, row.gamma.value(), false);
} }
db(update(tab).set(tab.alpha = 10, tab.beta = "Cookies!", tab.gamma = true).unconditionally()); 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())) 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.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.beta.value(), "Cookies!");
require_equal(__LINE__, row.gamma.is_null(), false); require_equal(__LINE__, row.gamma, true);
require_equal(__LINE__, row.gamma.value(), true);
} }
db(update(tab).set(tab.alpha = 20, tab.beta = "Monster", tab.gamma = false).unconditionally()); 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.alpha.value(), 20);
require_equal(__LINE__, row.beta.value(), "Monster"); 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( auto prepared_update = db.prepare(
@ -113,7 +109,7 @@ int Type(int, char*[])
{ {
require_equal(__LINE__, row.alpha.value(), 30); require_equal(__LINE__, row.alpha.value(), 30);
require_equal(__LINE__, row.beta.value(), "IceCream"); require_equal(__LINE__, row.beta.value(), "IceCream");
require_equal(__LINE__, row.gamma.value(), true); require_equal(__LINE__, row.gamma, true);
} }
} }
catch (std::exception& e) catch (std::exception& e)

View File

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

View File

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

View File

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

View File

@ -78,10 +78,8 @@ int DateTime(int, char*[])
for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) 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 == sqlpp::nullopt, true);
require_equal(__LINE__, row.colDayPoint.value(), ::sqlpp::chrono::day_point{}); require_equal(__LINE__, row.colTimePoint == sqlpp::nullopt, true);
require_equal(__LINE__, row.colTimePoint.is_null(), true);
require_equal(__LINE__, row.colTimePoint.value(), ::sqlpp::chrono::microsecond_point{});
} }
db(update(tab).set(tab.colDayPoint = today, tab.colTimePoint = now).unconditionally()); 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 (\ db.execute("CREATE TABLE tab_sample (\
alpha bigint(20) DEFAULT NULL,\ alpha bigint(20) DEFAULT NULL,\
beta varchar(255) DEFAULT NULL,\ beta varchar(255) DEFAULT NULL,\
gamma bool DEFAULT NULL\ gamma bool\
)"); )");
const auto tab = TabSample{}; const auto tab = TabSample{};

View File

@ -41,6 +41,13 @@
#include <iostream> #include <iostream>
#include <vector> #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) SQLPP_ALIAS_PROVIDER(left)
namespace sql = sqlpp::sqlite3; namespace sql = sqlpp::sqlite3;
@ -55,7 +62,7 @@ int DynamicSelect(int, char*[])
db.execute("CREATE TABLE tab_sample (\ db.execute("CREATE TABLE tab_sample (\
alpha bigint(20) DEFAULT NULL,\ alpha bigint(20) DEFAULT NULL,\
beta varchar(255) DEFAULT NULL,\ beta varchar(255) DEFAULT NULL,\
gamma bool DEFAULT NULL\ gamma bool\
)"); )");
const auto tab = TabSample{}; const auto tab = TabSample{};

View File

@ -39,15 +39,22 @@ namespace sql = sqlpp::sqlite3;
const auto fp = FpSample{}; 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> template <typename L, typename R>
auto require_equal(int line, const L& l, const R& r) -> void auto require_equal(int line, const L& l, const R& r) -> void
{ {
if (l != r) if (l != r)
{ {
std::cerr << line << ": "; std::cerr << line << ": ";
serialize(::sqlpp::wrap_operand_t<L>{l}, std::cerr); std::cerr << l;
std::cerr << " != "; std::cerr << " != ";
serialize(::sqlpp::wrap_operand_t<R>{r}, std::cerr); std::cerr << r;
throw std::runtime_error("Unexpected result"); throw std::runtime_error("Unexpected result");
} }
} }

View File

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

View File

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

View File

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

View File

@ -37,6 +37,13 @@
namespace sql = sqlpp::sqlite3; namespace sql = sqlpp::sqlite3;
const auto tab = TabSample{}; 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*[]) int Union(int, char*[])
{ {
sql::connection_config config; sql::connection_config config;
@ -48,7 +55,7 @@ int Union(int, char*[])
db.execute(R"(CREATE TABLE tab_sample ( db.execute(R"(CREATE TABLE tab_sample (
alpha INTEGER PRIMARY KEY, alpha INTEGER PRIMARY KEY,
beta varchar(255) DEFAULT NULL, 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()); 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; namespace sql = sqlpp::sqlite3;
const auto tab = TabSample{}; 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*[]) int With(int, char*[])
{ {
#if SQLITE_VERSION_NUMBER >= 3008003 #if SQLITE_VERSION_NUMBER >= 3008003
@ -51,7 +58,7 @@ int With(int, char*[])
db.execute(R"(CREATE TABLE tab_sample ( db.execute(R"(CREATE TABLE tab_sample (
alpha INTEGER PRIMARY KEY, alpha INTEGER PRIMARY KEY,
beta varchar(255) DEFAULT NULL, 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)); auto a = sqlpp::cte(sqlpp::alias::a).as(select(all_of(tab)).from(tab).where(tab.alpha > 3));