summaryrefslogtreecommitdiff
path: root/subprojects/boost-sqlite/include/boost/sqlite/connection.hpp
blob: 0f6ccf83741c29a71046ce86c35e3b67c75fa667 (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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// 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_CONNECTION_HPP
#define BOOST_SQLITE_CONNECTION_HPP

#include <boost/sqlite/detail/config.hpp>
#include <boost/sqlite/error.hpp>
#include <boost/sqlite/resultset.hpp>
#include <boost/sqlite/statement.hpp>
#include <memory>
#include <boost/system/system_error.hpp>

BOOST_SQLITE_BEGIN_NAMESPACE

template<typename T, bool Strict>
struct static_resultset;

constexpr static cstring_ref in_memory = ":memory:";

/** @brief main object for a connection to a database.
  @ingroup reference

  @par Example
  @code{.cpp}
    sqlite::connection conn;
    conn.connect("./my-database.db");
    conn.prepare("insert into log (text) values ($1)").execute(std::make_tuple("booting up"));
  @endcode

 */
struct connection
{
    /// The handle of the connection
    using handle_type = sqlite3*;
    /// Returns the handle
    handle_type handle() const { return impl_.get(); }
    /// Release the owned handle.
    handle_type release() &&    { return impl_.release(); }

    ///Default constructor
    connection() = default;
    /// Construct the connection from a handle.
    explicit connection(handle_type handle, bool take_ownership = true) : impl_(handle, take_ownership) {}
    /// Move constructor.
    connection(connection && ) = default;
    /// Move assign operator.
    connection& operator=(connection && ) = default;

    /// Construct a connection and connect it to `filename`. `flags` is set by `SQLITE_OPEN_*` flags. @see https://www.sqlite.org/c3ref/c_open_autoproxy.html
    connection(cstring_ref filename,
               int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) { connect(filename, flags); }

#if defined(BOOST_WINDOWS_API)
    template<typename Path,
             typename = std::enable_if_t<
                 std::is_same<typename Path::string_type, std::wstring>::value &&
                 std::is_constructible<cstring_ref, decltype(std::declval<Path>().string())>::value
             >>
    explicit connection(const Path & pth) : connection(pth.string()) {}
#endif
    ///@{
    /// Connect the database to `filename`.  `flags` is set by `SQLITE_OPEN_*` flags.
    BOOST_SQLITE_DECL void connect(cstring_ref filename, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
    BOOST_SQLITE_DECL void connect(cstring_ref filename, int flags, system::error_code & ec);
    ///@}

#if defined(BOOST_WINDOWS_API)
    template<typename Path,
             typename = std::enable_if_t<
                 std::is_same<typename Path::string_type, std::wstring>::value &&
                 std::is_constructible<cstring_ref, decltype(std::declval<Path>().string())>::value
             >>
    void connect(const Path & pth, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
    {
        connect(pth.string(), flags);
    }


    template<typename Path,
             typename = std::enable_if_t<
                 std::is_same<typename Path::string_type, std::wstring>::value &&
                 std::is_constructible<cstring_ref, decltype(std::declval<Path>().string())>::value
             >>
    void connect(const Path & pth, int flags, system::error_code & ec)
    {
        connect(pth.string(), flags, ec);
    }
#endif

    ///@{
    /// Close the database connection.
    BOOST_SQLITE_DECL void close();
    BOOST_SQLITE_DECL void close(system::error_code & ec, error_info & ei);
    ///@}

    /// Check if the database holds a valid handle.
    bool valid() const {return impl_ != nullptr;}


    ///@{
    /// Perform a query without parameters. Can only execute a single statement.
    BOOST_SQLITE_DECL resultset query(
            core::string_view q,
            system::error_code & ec,
            error_info & ei);

    BOOST_SQLITE_DECL resultset query(core::string_view q);

    template<typename T, bool Strict = false>
    static_resultset<T, Strict> query(
        core::string_view q,
        system::error_code & ec,
        error_info & ei)
    {
        static_resultset<T, Strict> tmp = query(q, ec, ei);
        if (ec)
            return {};
        tmp.check_columns_(ec, ei);
        if (ec)
            return {};

        return tmp;
    }

    template<typename T, bool Strict = false>
    static_resultset<T, Strict> query(core::string_view q)
    {
        system::error_code ec;
        error_info ei;
        auto tmp = query<T, Strict>(q, ec, ei);
        if (ec)
            throw_exception(system::system_error(ec, ei.message()));
        return tmp;
    }
    ///@}

    ///@{
    /// Perform a query without parametert, It execute a multiple statement.
    BOOST_SQLITE_DECL void execute(
        cstring_ref q,
        system::error_code & ec,
        error_info & ei);

    BOOST_SQLITE_DECL void execute(cstring_ref q);

    template<typename StringLike,
             typename = decltype(std::declval<const StringLike&>().c_str())>
    void execute(
        const StringLike& q,
        system::error_code & ec,
        error_info & ei)
    {
        execute(q.c_str(), ec, ei);
    }
    template<typename StringLike,
             typename = decltype(std::declval<const StringLike&>().c_str())>
    void execute(const StringLike & q) { execute(q.c_str());}
    ///@}

    ///@{
    /// Perform a query with parameters. Can only execute a single statement.
    BOOST_SQLITE_DECL statement prepare(
            core::string_view q,
            system::error_code & ec,
            error_info & ei);

    BOOST_SQLITE_DECL statement prepare(core::string_view q);
    ///@}

    /// Check if the database has the table
    bool has_table(
        cstring_ref table,
        cstring_ref db_name = "main") const
    {
      return sqlite3_table_column_metadata(impl_.get(), db_name.c_str(), table.c_str(),
                                           nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)
             == SQLITE_OK;
    }

    /// Check if the database has the table
    bool has_column(
        cstring_ref table,
        cstring_ref column,
        cstring_ref db_name = "main") const
    {
      return sqlite3_table_column_metadata(impl_.get(), db_name.c_str(), table.c_str(), column.c_str(),
                                           nullptr, nullptr, nullptr, nullptr, nullptr)
             == SQLITE_OK;
    }
 private:
    struct deleter_
    {
        deleter_(bool owned = true) : owned_(owned) {}
        bool owned_ = true;
        void operator()(sqlite3  *impl)
        {
            if (owned_)
              sqlite3_close_v2(impl);
        }
    };

    std::unique_ptr<sqlite3, deleter_> impl_{nullptr, deleter_{}};
};

BOOST_SQLITE_END_NAMESPACE


#endif //BOOST_SQLITE_CONNECTION_HPP