sqlitebasestatement.h 12.9 KB
Newer Older
1 2
/****************************************************************************
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
5 6 7 8 9 10 11
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 24 25
**
****************************************************************************/

hjk's avatar
hjk committed
26
#pragma once
27

Marco Bubke's avatar
Marco Bubke committed
28 29 30
#include "sqliteglobal.h"

#include "sqliteexception.h"
31

32
#include <utils/smallstringvector.h>
33

Marco Bubke's avatar
Marco Bubke committed
34 35
#include <utils/optional.h>

Marco Bubke's avatar
Marco Bubke committed
36
#include <cstdint>
Marco Bubke's avatar
Marco Bubke committed
37
#include <memory>
Marco Bubke's avatar
Marco Bubke committed
38 39 40 41
#include <type_traits>
#include <tuple>

using std::int64_t;
42 43 44 45

struct sqlite3_stmt;
struct sqlite3;

Marco Bubke's avatar
Marco Bubke committed
46 47
namespace Sqlite {

Marco Bubke's avatar
Marco Bubke committed
48 49
class Database;
class DatabaseBackend;
50

Marco Bubke's avatar
Marco Bubke committed
51
class SQLITE_EXPORT BaseStatement
52
{
Marco Bubke's avatar
Marco Bubke committed
53 54
public:
    explicit BaseStatement(Utils::SmallStringView sqlStatement, Database &database);
55

Marco Bubke's avatar
Marco Bubke committed
56
    static void deleteCompiledStatement(sqlite3_stmt *m_compiledStatement);
57 58 59

    bool next() const;
    void step() const;
60
    void execute() const;
61 62
    void reset() const;

Marco Bubke's avatar
Marco Bubke committed
63 64 65 66 67 68
    int fetchIntValue(int column) const;
    long fetchLongValue(int column) const;
    long long fetchLongLongValue(int column) const;
    double fetchDoubleValue(int column) const;
    Utils::SmallString fetchSmallStringValue(int column) const;
    Utils::PathString fetchPathStringValue(int column) const;
69
    template<typename Type>
Marco Bubke's avatar
Marco Bubke committed
70
    Type fetchValue(int column) const;
71
    int columnCount() const;
72
    Utils::SmallStringVector columnNames() const;
73

Marco Bubke's avatar
Marco Bubke committed
74 75 76 77
    void bind(int index, int fetchValue);
    void bind(int index, long long fetchValue);
    void bind(int index, double fetchValue);
    void bind(int index, Utils::SmallStringView fetchValue);
78

Marco Bubke's avatar
Marco Bubke committed
79 80 81 82 83 84 85 86 87 88
    void bind(int index, uint value)
    {
        bind(index, static_cast<long long>(value));
    }

    void bind(int index, long value)
    {
        bind(index, static_cast<long long>(value));
    }

Marco Bubke's avatar
Marco Bubke committed
89 90 91 92 93 94 95 96 97 98 99
    template <typename Type>
    void bind(Utils::SmallStringView name, Type fetchValue);

    int bindingIndexForName(Utils::SmallStringView name) const;

    void prepare(Utils::SmallStringView sqlStatement);
    void waitForUnlockNotify() const;

    sqlite3 *sqliteDatabaseHandle() const;
    TextEncoding databaseTextEncoding();

100 101 102 103
    [[noreturn]] void checkForStepError(int resultCode) const;
    [[noreturn]] void checkForResetError(int resultCode) const;
    [[noreturn]] void checkForPrepareError(int resultCode) const;
    [[noreturn]] void checkForBindingError(int resultCode) const;
Marco Bubke's avatar
Marco Bubke committed
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
    void setIfIsReadyToFetchValues(int resultCode) const;
    void checkIfIsReadyToFetchValues() const;
    void checkColumnsAreValid(const std::vector<int> &columns) const;
    void checkColumnIsValid(int column) const;
    void checkBindingName(int index) const;
    void setBindingParameterCount();
    void setColumnCount();
    bool isReadOnlyStatement() const;
    [[noreturn]] void throwStatementIsBusy(const char *whatHasHappened) const;
    [[noreturn]] void throwStatementHasError(const char *whatHasHappened) const;
    [[noreturn]] void throwStatementIsMisused(const char *whatHasHappened) const;
    [[noreturn]] void throwConstraintPreventsModification(const char *whatHasHappened) const;
    [[noreturn]] void throwNoValuesToFetch(const char *whatHasHappened) const;
    [[noreturn]] void throwInvalidColumnFetched(const char *whatHasHappened) const;
    [[noreturn]] void throwBindingIndexIsOutOfRange(const char *whatHasHappened) const;
    [[noreturn]] void throwWrongBingingName(const char *whatHasHappened) const;
    [[noreturn]] void throwUnknowError(const char *whatHasHappened) const;
    [[noreturn]] void throwBingingTooBig(const char *whatHasHappened) const;

    QString columnName(int column) const;

    Database &database() const;

private:
    std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt*)> m_compiledStatement;
    Database &m_database;
    int m_bindingParameterCount;
    int m_columnCount;
    mutable bool m_isReadyToFetchValues;
};

extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, int value);
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long value);
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long long value);
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, double value);
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);

template <> SQLITE_EXPORT int BaseStatement::fetchValue<int>(int column) const;
template <> SQLITE_EXPORT long BaseStatement::fetchValue<long>(int column) const;
template <> SQLITE_EXPORT long long BaseStatement::fetchValue<long long>(int column) const;
template <> SQLITE_EXPORT double BaseStatement::fetchValue<double>(int column) const;
extern template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue<Utils::SmallString>(int column) const;
extern template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathString>(int column) const;

template <typename BaseStatement>
class SQLITE_EXPORT StatementImplementation : public BaseStatement
{

public:
    using BaseStatement::BaseStatement;

Marco Bubke's avatar
Marco Bubke committed
155 156 157 158
    void bindValues()
    {
    }

Marco Bubke's avatar
Marco Bubke committed
159
    template<typename... ValueType>
160
    void bindValues(const ValueType&... values)
161 162 163 164
    {
        bindValuesByIndex(1, values...);
    }

Marco Bubke's avatar
Marco Bubke committed
165
    template<typename... ValueType>
166
    void write(const ValueType&... values)
167 168
    {
        bindValuesByIndex(1, values...);
Marco Bubke's avatar
Marco Bubke committed
169
        BaseStatement::execute();
170 171
    }

Marco Bubke's avatar
Marco Bubke committed
172
    template<typename... ValueType>
173
    void bindNameValues(const ValueType&... values)
174 175 176 177
    {
        bindValuesByName(values...);
    }

Marco Bubke's avatar
Marco Bubke committed
178
    template<typename... ValueType>
179
    void writeNamed(const ValueType&... values)
180 181
    {
        bindValuesByName(values...);
Marco Bubke's avatar
Marco Bubke committed
182
        BaseStatement::execute();
183 184
    }

Marco Bubke's avatar
Marco Bubke committed
185
    template <typename ResultType,
Marco Bubke's avatar
Marco Bubke committed
186 187
              int ResultTypeCount = 1>
    std::vector<ResultType> values(std::size_t reserveSize)
Marco Bubke's avatar
Marco Bubke committed
188
    {
Marco Bubke's avatar
Marco Bubke committed
189
        Resetter resetter{*this};
Marco Bubke's avatar
Marco Bubke committed
190
        std::vector<ResultType> resultValues;
Marco Bubke's avatar
Marco Bubke committed
191 192
        resultValues.reserve(reserveSize);

Marco Bubke's avatar
Marco Bubke committed
193
        while (BaseStatement::next())
Marco Bubke's avatar
Marco Bubke committed
194
           emplaceBackValues<ResultTypeCount>(resultValues);
Marco Bubke's avatar
Marco Bubke committed
195 196 197 198 199

        return resultValues;
    }

    template <typename ResultType,
Marco Bubke's avatar
Marco Bubke committed
200
              int ResultTypeCount = 1,
Marco Bubke's avatar
Marco Bubke committed
201
              typename... QueryTypes>
Marco Bubke's avatar
Marco Bubke committed
202
    std::vector<ResultType> values(std::size_t reserveSize, const QueryTypes&... queryValues)
Marco Bubke's avatar
Marco Bubke committed
203
    {
Marco Bubke's avatar
Marco Bubke committed
204
        Resetter resetter{*this};
Marco Bubke's avatar
Marco Bubke committed
205
        std::vector<ResultType> resultValues;
Marco Bubke's avatar
Marco Bubke committed
206 207 208 209
        resultValues.reserve(reserveSize);

        bindValues(queryValues...);

Marco Bubke's avatar
Marco Bubke committed
210
        while (BaseStatement::next())
Marco Bubke's avatar
Marco Bubke committed
211
           emplaceBackValues<ResultTypeCount>(resultValues);
Marco Bubke's avatar
Marco Bubke committed
212 213 214 215 216

        return resultValues;
    }

    template <typename ResultType,
Marco Bubke's avatar
Marco Bubke committed
217
              int ResultTypeCount = 1,
Marco Bubke's avatar
Marco Bubke committed
218
              typename QueryElementType>
Marco Bubke's avatar
Marco Bubke committed
219
    std::vector<ResultType> values(std::size_t reserveSize,
Marco Bubke's avatar
Marco Bubke committed
220
                                   const std::vector<QueryElementType> &queryValues)
Marco Bubke's avatar
Marco Bubke committed
221
    {
Marco Bubke's avatar
Marco Bubke committed
222
        std::vector<ResultType> resultValues;
Marco Bubke's avatar
Marco Bubke committed
223 224 225
        resultValues.reserve(reserveSize);

        for (const QueryElementType &queryValue : queryValues) {
Marco Bubke's avatar
Marco Bubke committed
226
            Resetter resetter{*this};
Marco Bubke's avatar
Marco Bubke committed
227 228
            bindValues(queryValue);

Marco Bubke's avatar
Marco Bubke committed
229
            while (BaseStatement::next())
Marco Bubke's avatar
Marco Bubke committed
230
                emplaceBackValues<ResultTypeCount>(resultValues);
Marco Bubke's avatar
Marco Bubke committed
231 232 233 234 235 236
        }

        return resultValues;
    }

    template <typename ResultType,
Marco Bubke's avatar
Marco Bubke committed
237
              int ResultTypeCount = 1,
Marco Bubke's avatar
Marco Bubke committed
238
              typename... QueryElementTypes>
Marco Bubke's avatar
Marco Bubke committed
239
    std::vector<ResultType> values(std::size_t reserveSize,
Marco Bubke's avatar
Marco Bubke committed
240
                                   const std::vector<std::tuple<QueryElementTypes...>> &queryTuples)
Marco Bubke's avatar
Marco Bubke committed
241 242 243 244 245 246
    {
        using Container = std::vector<ResultType>;
        Container resultValues;
        resultValues.reserve(reserveSize);

        for (const auto &queryTuple : queryTuples) {
Marco Bubke's avatar
Marco Bubke committed
247
            Resetter resetter{*this};
Marco Bubke's avatar
Marco Bubke committed
248 249
            bindTupleValues(queryTuple);

Marco Bubke's avatar
Marco Bubke committed
250
            while (BaseStatement::next())
Marco Bubke's avatar
Marco Bubke committed
251
                emplaceBackValues<ResultTypeCount>(resultValues);
Marco Bubke's avatar
Marco Bubke committed
252 253 254 255 256 257
        }

        return resultValues;
    }

    template <typename ResultType,
Marco Bubke's avatar
Marco Bubke committed
258
              int ResultTypeCount = 1,
Marco Bubke's avatar
Marco Bubke committed
259
              typename... QueryTypes>
Marco Bubke's avatar
Marco Bubke committed
260
    Utils::optional<ResultType> value(const QueryTypes&... queryValues)
Marco Bubke's avatar
Marco Bubke committed
261
    {
Marco Bubke's avatar
Marco Bubke committed
262
        Resetter resetter{*this};
Marco Bubke's avatar
Marco Bubke committed
263
        Utils::optional<ResultType> resultValue;
Marco Bubke's avatar
Marco Bubke committed
264 265 266

        bindValues(queryValues...);

Marco Bubke's avatar
Marco Bubke committed
267
        if (BaseStatement::next())
Marco Bubke's avatar
Marco Bubke committed
268
           resultValue = assignValue<Utils::optional<ResultType>, ResultTypeCount>();
Marco Bubke's avatar
Marco Bubke committed
269

Marco Bubke's avatar
Marco Bubke committed
270
        return resultValue;
Marco Bubke's avatar
Marco Bubke committed
271
    }
272 273

    template <typename Type>
Marco Bubke's avatar
Marco Bubke committed
274 275 276
    static Type toValue(Utils::SmallStringView sqlStatement, Database &database)
    {
        StatementImplementation statement(sqlStatement, database);
277

Marco Bubke's avatar
Marco Bubke committed
278
        statement.next();
279

Marco Bubke's avatar
Marco Bubke committed
280 281
        return statement.template fetchValue<Type>(0);
    }
282 283


Marco Bubke's avatar
Marco Bubke committed
284 285 286 287 288 289
private:
    struct Resetter
    {
        Resetter(StatementImplementation &statement)
            : statement(statement)
        {}
290

Marco Bubke's avatar
Marco Bubke committed
291 292 293 294
        ~Resetter()
        {
            statement.reset();
        }
295

Marco Bubke's avatar
Marco Bubke committed
296 297
        StatementImplementation &statement;
    };
298

Marco Bubke's avatar
Marco Bubke committed
299
    struct ValueGetter
Marco Bubke's avatar
Marco Bubke committed
300
    {
Marco Bubke's avatar
Marco Bubke committed
301
        ValueGetter(StatementImplementation &statement, int column)
Marco Bubke's avatar
Marco Bubke committed
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
            : statement(statement),
              column(column)
        {}

        operator int()
        {
            return statement.fetchIntValue(column);
        }

        operator long()
        {
            return statement.fetchLongValue(column);
        }

        operator long long()
        {
            return statement.fetchLongLongValue(column);
        }

        operator double()
        {
            return statement.fetchDoubleValue(column);
        }

        operator  Utils::SmallString()
        {
            return statement.fetchSmallStringValue(column);
        }

        operator  Utils::PathString()
        {
            return statement.fetchPathStringValue(column);
        }

Marco Bubke's avatar
Marco Bubke committed
336
        StatementImplementation &statement;
Marco Bubke's avatar
Marco Bubke committed
337 338 339
        int column;
    };

Marco Bubke's avatar
Marco Bubke committed
340 341
    template <typename ContainerType,
              int... ColumnIndices>
Marco Bubke's avatar
Marco Bubke committed
342
    void emplaceBackValues(ContainerType &container, std::integer_sequence<int, ColumnIndices...>)
Marco Bubke's avatar
Marco Bubke committed
343
    {
Marco Bubke's avatar
Marco Bubke committed
344
        container.emplace_back(ValueGetter(*this, ColumnIndices)...);
Marco Bubke's avatar
Marco Bubke committed
345 346
    }

Marco Bubke's avatar
Marco Bubke committed
347 348 349
    template <int ResultTypeCount,
              typename ContainerType>
    void emplaceBackValues(ContainerType &container)
Marco Bubke's avatar
Marco Bubke committed
350
    {
Marco Bubke's avatar
Marco Bubke committed
351
        emplaceBackValues(container, std::make_integer_sequence<int, ResultTypeCount>{});
Marco Bubke's avatar
Marco Bubke committed
352 353
    }

Marco Bubke's avatar
Marco Bubke committed
354
    template <typename ResultOptionalType,
Marco Bubke's avatar
Marco Bubke committed
355
              int... ColumnIndices>
Marco Bubke's avatar
Marco Bubke committed
356
    ResultOptionalType assignValue(std::integer_sequence<int, ColumnIndices...>)
Marco Bubke's avatar
Marco Bubke committed
357
    {
Marco Bubke's avatar
Marco Bubke committed
358
        return ResultOptionalType(Utils::in_place, ValueGetter(*this, ColumnIndices)...);
Marco Bubke's avatar
Marco Bubke committed
359 360
    }

Marco Bubke's avatar
Marco Bubke committed
361 362 363
    template <typename ResultOptionalType,
              int ResultTypeCount>
    ResultOptionalType assignValue()
Marco Bubke's avatar
Marco Bubke committed
364
    {
Marco Bubke's avatar
Marco Bubke committed
365
        return assignValue<ResultOptionalType>(std::make_integer_sequence<int, ResultTypeCount>{});
Marco Bubke's avatar
Marco Bubke committed
366 367
    }

Marco Bubke's avatar
Marco Bubke committed
368
    template<typename ValueType>
369
    void bindValuesByIndex(int index, const ValueType &value)
370
    {
Marco Bubke's avatar
Marco Bubke committed
371
        BaseStatement::bind(index, value);
372 373
    }

Marco Bubke's avatar
Marco Bubke committed
374
    template<typename ValueType, typename... ValueTypes>
375
    void bindValuesByIndex(int index, const ValueType &value, const ValueTypes&... values)
376
    {
Marco Bubke's avatar
Marco Bubke committed
377
        BaseStatement::bind(index, value);
378 379 380
        bindValuesByIndex(index + 1, values...);
    }

Marco Bubke's avatar
Marco Bubke committed
381
    template<typename ValueType>
382
    void bindValuesByName(Utils::SmallStringView name, const ValueType &value)
383
    {
Marco Bubke's avatar
Marco Bubke committed
384
       BaseStatement::bind(BaseStatement::bindingIndexForName(name), value);
385 386
    }

Marco Bubke's avatar
Marco Bubke committed
387
    template<typename ValueType, typename... ValueTypes>
388
    void bindValuesByName(Utils::SmallStringView name, const ValueType &value, const ValueTypes&... values)
389
    {
Marco Bubke's avatar
Marco Bubke committed
390
       BaseStatement::bind(BaseStatement::bindingIndexForName(name), value);
391 392 393
       bindValuesByName(values...);
    }

Marco Bubke's avatar
Marco Bubke committed
394 395
    template <typename TupleType, std::size_t... ColumnIndices>
    void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<ColumnIndices...>)
Marco Bubke's avatar
Marco Bubke committed
396
    {
Marco Bubke's avatar
Marco Bubke committed
397
        bindValues(std::get<ColumnIndices>(tuple)...);
Marco Bubke's avatar
Marco Bubke committed
398 399 400
    }

    template <typename TupleType,
Marco Bubke's avatar
Marco Bubke committed
401
              typename ColumnIndices = std::make_index_sequence<std::tuple_size<TupleType>::value>>
Marco Bubke's avatar
Marco Bubke committed
402 403
    void bindTupleValues(const TupleType &element)
    {
Marco Bubke's avatar
Marco Bubke committed
404
        bindTupleValuesElement(element, ColumnIndices());
Marco Bubke's avatar
Marco Bubke committed
405 406
    }

407
};
Marco Bubke's avatar
Marco Bubke committed
408 409

} // namespace Sqlite