summaryrefslogtreecommitdiff
path: root/include/boost/sqlite/blob.hpp
blob: cd82363b10f55e616a7ae9d58927e000ba94c057 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_SQLITE_BLOB_HPP
#define BOOST_SQLITE_BLOB_HPP

#include <boost/sqlite/detail/config.hpp>
#include <boost/sqlite/memory.hpp>
#include <boost/sqlite/error.hpp>
#include <type_traits>
#include <memory>
#include <cstring>

BOOST_SQLITE_BEGIN_NAMESPACE

struct connection ;

/// @brief a view to a binary large object  @ingroup reference
struct blob_view
{
    /// The data in the blob
    const void * data() const {return data_;}
    /// The size of the data int he blob, in bytes
    std::size_t size() const {return size_;}
    /// Construct a blob
    blob_view(const void * data, std::size_t size) : data_(data), size_(size) {}

    /// Construct an empty blob
    blob_view() = default;
    /// Construct a blob from some other blob-like structure.
    template<typename T>
    explicit blob_view(const T & value,
                       typename std::enable_if<
                           std::is_pointer<decltype(std::declval<T>().data())>::value
                        && std::is_convertible<decltype(std::declval<T>().size()), std::size_t>::value
                           >::type * = nullptr) : data_(value.data()), size_(value.size()) {}

    inline blob_view(const struct blob & b);
  private:
    const void * data_{nullptr};
    std::size_t size_{0u};
};

/// @brief Helper type to pass a blob full of zeroes without allocating extra memory. @ingroup reference
enum class zero_blob : sqlite3_uint64 {};

/// @brief An object that owns a binary large object. @ingroup reference
struct blob
{
    /// The data in the blob
    void * data() const {return impl_.get();}
    /// The size of the data int he blob, in bytes
    std::size_t size() const {return size_;}

    /// Create a blob from a blob_view
    explicit blob(blob_view bv)
    {
        impl_.reset(sqlite3_malloc(static_cast<int>(bv.size())));
        size_ = bv.size();
        std::memcpy(impl_.get(), bv.data(), size_);
    }
    /// Create an empty blob with size `n`.
    explicit blob(std::size_t n) : impl_(sqlite3_malloc(static_cast<int>(n))), size_(n) {}

    /// Construct an empty blob
    constexpr blob() = default;
    /// Release & take ownership of the blob.
    void * release() && {return std::move(impl_).release(); }
   private:
    unique_ptr<void> impl_;
    std::size_t size_{0u};
};

blob_view::blob_view(const blob & b) : data_(b.data()), size_(b.size()) {}

/// @brief an object that holds a binary large object. Can be obtained by using @ref blob_handle. @ingroup reference
struct blob_handle
{
    /// Default constructor
    blob_handle() = default;

    /// Construct from a handle. Takes owner ship
    explicit blob_handle(sqlite3_blob * blob) : blob_(blob) {}

    ///@{
    /// @brief Reopen on another row
    BOOST_SQLITE_DECL
    void reopen(sqlite3_int64 row_id, system::error_code & ec);
    BOOST_SQLITE_DECL
    void reopen(sqlite3_int64 row_id);
    ///@}

    ///@{
    /// @brief Read data from the blob
    BOOST_SQLITE_DECL
    void read_at(void *data, int len, int offset, system::error_code &ec);
    BOOST_SQLITE_DECL
    void read_at(void *data, int len, int offset);
    ///@}

    ///@{
    /// @brief Write data to the blob
    BOOST_SQLITE_DECL
    void write_at(const void *data, int len, int offset, system::error_code &ec);
    BOOST_SQLITE_DECL
    void write_at(const void *data, int len, int offset);
    ///@}

    /// The size of the blob
    std::size_t size() const {return static_cast<std::size_t>(sqlite3_blob_bytes(blob_.get()));}

    /// The handle of the blob
    using handle_type = sqlite3_blob*;
    /// Returns the handle of the blob
    handle_type handle() { return blob_.get(); }
    /// Release the owned handle.
    handle_type release() &&    { return blob_.release(); }
 private:
    struct deleter_
    {
        void operator()(sqlite3_blob *impl)
        {
          sqlite3_blob_close(impl);
        }
    };
    std::unique_ptr<sqlite3_blob, deleter_> blob_;
};

///@{
/// Open a blob for incremental access
BOOST_SQLITE_DECL
blob_handle open_blob(connection & conn,
                      cstring_ref db,
                      cstring_ref table,
                      cstring_ref column,
                      sqlite3_int64 row,
                      bool read_only,
                      system::error_code &ec,
                      error_info &ei);

BOOST_SQLITE_DECL
blob_handle open_blob(connection & conn,
                      cstring_ref db,
                      cstring_ref table,
                      cstring_ref column,
                      sqlite3_int64 row,
                      bool read_only = false);
///}@



BOOST_SQLITE_END_NAMESPACE


#endif //BOOST_SQLITE_BLOB_HPP