2015-06-01 18:51:55 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:58:39 +01:00
|
|
|
** 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.
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** 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.
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2016-03-18 07:55:01 +01:00
|
|
|
#pragma once
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2015-06-16 12:38:04 +02:00
|
|
|
#include "sqliteglobal.h"
|
|
|
|
|
|
2020-09-16 13:44:43 +02:00
|
|
|
#include "sqliteblob.h"
|
2015-06-16 12:38:04 +02:00
|
|
|
#include "sqliteexception.h"
|
2021-05-06 15:27:51 +00:00
|
|
|
#include "sqlitetransaction.h"
|
2020-04-27 20:01:38 +02:00
|
|
|
#include "sqlitevalue.h"
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2017-07-27 15:59:54 +02:00
|
|
|
#include <utils/smallstringvector.h>
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2017-09-21 11:43:24 +02:00
|
|
|
#include <utils/optional.h>
|
2020-05-26 20:31:41 +02:00
|
|
|
#include <utils/span.h>
|
2017-09-21 11:43:24 +02:00
|
|
|
|
2017-08-17 15:33:25 +02:00
|
|
|
#include <cstdint>
|
2021-05-06 15:27:51 +00:00
|
|
|
#include <exception>
|
2021-02-10 15:25:00 +01:00
|
|
|
#include <functional>
|
2015-06-16 12:38:04 +02:00
|
|
|
#include <memory>
|
2017-08-17 15:33:25 +02:00
|
|
|
#include <tuple>
|
2021-02-10 15:25:00 +01:00
|
|
|
#include <type_traits>
|
2017-08-17 15:33:25 +02:00
|
|
|
|
|
|
|
|
using std::int64_t;
|
2015-06-01 18:51:55 +02:00
|
|
|
|
|
|
|
|
struct sqlite3_stmt;
|
|
|
|
|
struct sqlite3;
|
|
|
|
|
|
2017-07-26 16:02:24 +02:00
|
|
|
namespace Sqlite {
|
|
|
|
|
|
2017-09-18 10:21:45 +02:00
|
|
|
class Database;
|
|
|
|
|
class DatabaseBackend;
|
2017-07-26 18:43:07 +02:00
|
|
|
|
2021-01-13 13:23:46 +01:00
|
|
|
enum class Type : char { Invalid, Integer, Float, Text, Blob, Null };
|
|
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
class SQLITE_EXPORT BaseStatement
|
2015-06-01 18:51:55 +02:00
|
|
|
{
|
2017-09-21 11:43:59 +02:00
|
|
|
public:
|
|
|
|
|
explicit BaseStatement(Utils::SmallStringView sqlStatement, Database &database);
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2018-03-12 14:08:18 +01:00
|
|
|
BaseStatement(const BaseStatement &) = delete;
|
|
|
|
|
BaseStatement &operator=(const BaseStatement &) = delete;
|
|
|
|
|
|
2017-07-26 16:02:24 +02:00
|
|
|
static void deleteCompiledStatement(sqlite3_stmt *m_compiledStatement);
|
2015-06-01 18:51:55 +02:00
|
|
|
|
|
|
|
|
bool next() const;
|
|
|
|
|
void step() const;
|
|
|
|
|
void reset() const;
|
|
|
|
|
|
2021-01-13 13:23:46 +01:00
|
|
|
Type fetchType(int column) const;
|
2017-09-21 11:43:24 +02:00
|
|
|
int fetchIntValue(int column) const;
|
|
|
|
|
long fetchLongValue(int column) const;
|
|
|
|
|
long long fetchLongLongValue(int column) const;
|
|
|
|
|
double fetchDoubleValue(int column) const;
|
2017-10-18 13:37:34 +02:00
|
|
|
Utils::SmallStringView fetchSmallStringViewValue(int column) const;
|
2020-04-27 20:01:38 +02:00
|
|
|
ValueView fetchValueView(int column) const;
|
2020-09-16 13:44:43 +02:00
|
|
|
BlobView fetchBlobValue(int column) const;
|
2015-06-01 18:51:55 +02:00
|
|
|
template<typename Type>
|
2017-09-21 11:43:24 +02:00
|
|
|
Type fetchValue(int column) const;
|
2015-06-01 18:51:55 +02:00
|
|
|
int columnCount() const;
|
|
|
|
|
|
2020-05-14 12:50:34 +02:00
|
|
|
void bind(int index, NullValue);
|
2020-12-21 17:23:34 +01:00
|
|
|
void bind(int index, int value);
|
|
|
|
|
void bind(int index, long long value);
|
|
|
|
|
void bind(int index, double value);
|
2020-05-16 14:27:41 +02:00
|
|
|
void bind(int index, void *pointer);
|
2020-12-21 17:23:34 +01:00
|
|
|
void bind(int index, Utils::span<int> values);
|
|
|
|
|
void bind(int index, Utils::span<long long> values);
|
|
|
|
|
void bind(int index, Utils::span<double> values);
|
|
|
|
|
void bind(int index, Utils::span<const char *> values);
|
|
|
|
|
void bind(int index, Utils::SmallStringView value);
|
|
|
|
|
void bind(int index, const Value &value);
|
2021-05-06 15:27:51 +00:00
|
|
|
void bind(int index, ValueView value);
|
2020-09-16 13:44:43 +02:00
|
|
|
void bind(int index, BlobView blobView);
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2020-04-27 20:01:38 +02:00
|
|
|
void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }
|
2017-08-17 15:33:25 +02:00
|
|
|
|
|
|
|
|
void bind(int index, long value)
|
|
|
|
|
{
|
|
|
|
|
bind(index, static_cast<long long>(value));
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
void prepare(Utils::SmallStringView sqlStatement);
|
|
|
|
|
void waitForUnlockNotify() const;
|
|
|
|
|
|
|
|
|
|
sqlite3 *sqliteDatabaseHandle() const;
|
|
|
|
|
|
2017-10-16 12:57:35 +02:00
|
|
|
[[noreturn]] void checkForStepError(int resultCode) const;
|
|
|
|
|
[[noreturn]] void checkForResetError(int resultCode) const;
|
|
|
|
|
[[noreturn]] void checkForPrepareError(int resultCode) const;
|
|
|
|
|
[[noreturn]] void checkForBindingError(int resultCode) const;
|
2017-09-21 11:43:59 +02:00
|
|
|
void setIfIsReadyToFetchValues(int resultCode) const;
|
2020-05-27 00:09:19 +02:00
|
|
|
void checkColumnCount(int columnCount) const;
|
2017-09-21 11:43:59 +02:00
|
|
|
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;
|
2020-06-16 00:05:33 +02:00
|
|
|
[[noreturn]] void throwInputOutputError(const char *whatHasHappened) const;
|
2017-09-21 11:43:59 +02:00
|
|
|
[[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;
|
2020-06-16 00:05:33 +02:00
|
|
|
[[noreturn]] void throwTooBig(const char *whatHasHappened) const;
|
|
|
|
|
[[noreturn]] void throwSchemaChangeError(const char *whatHasHappened) const;
|
|
|
|
|
[[noreturn]] void throwCannotWriteToReadOnlyConnection(const char *whatHasHappened) const;
|
|
|
|
|
[[noreturn]] void throwProtocolError(const char *whatHasHappened) const;
|
|
|
|
|
[[noreturn]] void throwDatabaseExceedsMaximumFileSize(const char *whatHasHappened) const;
|
|
|
|
|
[[noreturn]] void throwDataTypeMismatch(const char *whatHasHappened) const;
|
|
|
|
|
[[noreturn]] void throwConnectionIsLocked(const char *whatHasHappened) const;
|
|
|
|
|
[[noreturn]] void throwExecutionInterrupted(const char *whatHasHappened) const;
|
|
|
|
|
[[noreturn]] void throwDatabaseIsCorrupt(const char *whatHasHappened) const;
|
|
|
|
|
[[noreturn]] void throwCannotOpen(const char *whatHasHappened) const;
|
2017-09-21 11:43:59 +02:00
|
|
|
|
|
|
|
|
QString columnName(int column) const;
|
|
|
|
|
|
|
|
|
|
Database &database() const;
|
|
|
|
|
|
2018-03-12 14:08:18 +01:00
|
|
|
protected:
|
|
|
|
|
~BaseStatement() = default;
|
|
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
private:
|
2020-05-27 00:09:19 +02:00
|
|
|
std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt *)> m_compiledStatement;
|
2017-09-21 11:43:59 +02:00
|
|
|
Database &m_database;
|
|
|
|
|
int m_bindingParameterCount;
|
|
|
|
|
int m_columnCount;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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;
|
2017-10-18 13:37:34 +02:00
|
|
|
extern template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(int column) const;
|
2017-09-21 11:43:59 +02:00
|
|
|
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;
|
|
|
|
|
|
2021-03-24 18:10:55 +01:00
|
|
|
template<typename BaseStatement, int ResultCount>
|
2018-03-12 14:08:18 +01:00
|
|
|
class StatementImplementation : public BaseStatement
|
2017-09-21 11:43:59 +02:00
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
struct Resetter;
|
2017-09-21 11:43:59 +02:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
using BaseStatement::BaseStatement;
|
|
|
|
|
|
2018-04-04 10:41:11 +02:00
|
|
|
void execute()
|
|
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
Resetter resetter{this};
|
2018-04-04 10:41:11 +02:00
|
|
|
BaseStatement::next();
|
|
|
|
|
resetter.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 14:11:33 +02:00
|
|
|
void bindValues() {}
|
2017-08-17 15:33:25 +02:00
|
|
|
|
2017-08-21 12:00:27 +02:00
|
|
|
template<typename... ValueType>
|
2017-09-18 15:53:51 +02:00
|
|
|
void bindValues(const ValueType&... values)
|
Sqlite: Add variadic bind and write functions
You can now write
SqliteWriteStatement statement("UPDATE test SET name=?, number=?
WHERE rowid=?", database);
statement.write("see", 7.23, 1);
and
SqliteWriteStatement statement("UPDATE test SET name=@name, number=@number
WHERE rowid=@id", database);
statement.writeNamed("@name", "see", "@number", 7.23, "@id", 1);
This is more type safe than using variants and performant too.
Change-Id: Ie1ed2a6d326b956be5c4ec056214f3f5b1531f45
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
2017-07-31 19:44:39 +02:00
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
bindValuesByIndex(1, values...);
|
Sqlite: Add variadic bind and write functions
You can now write
SqliteWriteStatement statement("UPDATE test SET name=?, number=?
WHERE rowid=?", database);
statement.write("see", 7.23, 1);
and
SqliteWriteStatement statement("UPDATE test SET name=@name, number=@number
WHERE rowid=@id", database);
statement.writeNamed("@name", "see", "@number", 7.23, "@id", 1);
This is more type safe than using variants and performant too.
Change-Id: Ie1ed2a6d326b956be5c4ec056214f3f5b1531f45
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
2017-07-31 19:44:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-21 12:00:27 +02:00
|
|
|
template<typename... ValueType>
|
2017-09-18 15:53:51 +02:00
|
|
|
void write(const ValueType&... values)
|
Sqlite: Add variadic bind and write functions
You can now write
SqliteWriteStatement statement("UPDATE test SET name=?, number=?
WHERE rowid=?", database);
statement.write("see", 7.23, 1);
and
SqliteWriteStatement statement("UPDATE test SET name=@name, number=@number
WHERE rowid=@id", database);
statement.writeNamed("@name", "see", "@number", 7.23, "@id", 1);
This is more type safe than using variants and performant too.
Change-Id: Ie1ed2a6d326b956be5c4ec056214f3f5b1531f45
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
2017-07-31 19:44:39 +02:00
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
Resetter resetter{this};
|
|
|
|
|
bindValuesByIndex(1, values...);
|
2018-04-04 10:41:11 +02:00
|
|
|
BaseStatement::next();
|
|
|
|
|
resetter.reset();
|
Sqlite: Add variadic bind and write functions
You can now write
SqliteWriteStatement statement("UPDATE test SET name=?, number=?
WHERE rowid=?", database);
statement.write("see", 7.23, 1);
and
SqliteWriteStatement statement("UPDATE test SET name=@name, number=@number
WHERE rowid=@id", database);
statement.writeNamed("@name", "see", "@number", 7.23, "@id", 1);
This is more type safe than using variants and performant too.
Change-Id: Ie1ed2a6d326b956be5c4ec056214f3f5b1531f45
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
2017-07-31 19:44:39 +02:00
|
|
|
}
|
|
|
|
|
|
2021-03-24 18:10:55 +01:00
|
|
|
template<typename ResultType>
|
2017-09-21 11:43:24 +02:00
|
|
|
std::vector<ResultType> values(std::size_t reserveSize)
|
2017-08-17 15:33:25 +02:00
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
Resetter resetter{this};
|
2017-09-21 11:43:24 +02:00
|
|
|
std::vector<ResultType> resultValues;
|
2020-05-16 14:47:01 +02:00
|
|
|
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
2017-08-17 15:33:25 +02:00
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
while (BaseStatement::next())
|
2021-03-24 18:10:55 +01:00
|
|
|
emplaceBackValues(resultValues);
|
2020-05-16 14:47:01 +02:00
|
|
|
|
|
|
|
|
setMaximumResultCount(resultValues.size());
|
2017-08-17 15:33:25 +02:00
|
|
|
|
2017-10-23 13:26:32 +02:00
|
|
|
resetter.reset();
|
|
|
|
|
|
2017-08-17 15:33:25 +02:00
|
|
|
return resultValues;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-24 18:10:55 +01:00
|
|
|
template<typename ResultType, typename... QueryTypes>
|
2021-03-18 11:21:04 +01:00
|
|
|
auto values(std::size_t reserveSize, const QueryTypes &...queryValues)
|
2017-08-17 15:33:25 +02:00
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
Resetter resetter{this};
|
2017-09-21 11:43:24 +02:00
|
|
|
std::vector<ResultType> resultValues;
|
2020-05-16 14:47:01 +02:00
|
|
|
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
2017-08-17 15:33:25 +02:00
|
|
|
|
|
|
|
|
bindValues(queryValues...);
|
|
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
while (BaseStatement::next())
|
2021-03-24 18:10:55 +01:00
|
|
|
emplaceBackValues(resultValues);
|
2020-05-16 14:47:01 +02:00
|
|
|
|
|
|
|
|
setMaximumResultCount(resultValues.size());
|
2017-08-17 15:33:25 +02:00
|
|
|
|
2017-10-23 13:26:32 +02:00
|
|
|
resetter.reset();
|
|
|
|
|
|
2017-08-17 15:33:25 +02:00
|
|
|
return resultValues;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-24 18:10:55 +01:00
|
|
|
template<typename ResultType, typename... QueryTypes>
|
2021-03-18 11:21:04 +01:00
|
|
|
auto value(const QueryTypes &...queryValues)
|
2017-08-17 15:33:25 +02:00
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
Resetter resetter{this};
|
2017-09-21 11:43:24 +02:00
|
|
|
Utils::optional<ResultType> resultValue;
|
2017-08-17 15:33:25 +02:00
|
|
|
|
|
|
|
|
bindValues(queryValues...);
|
|
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
if (BaseStatement::next())
|
2021-05-06 15:27:51 +00:00
|
|
|
resultValue = createOptionalValue<Utils::optional<ResultType>>();
|
2017-08-17 15:33:25 +02:00
|
|
|
|
2017-10-23 13:26:32 +02:00
|
|
|
resetter.reset();
|
|
|
|
|
|
2017-09-21 11:43:24 +02:00
|
|
|
return resultValue;
|
2017-08-17 15:33:25 +02:00
|
|
|
}
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2021-03-18 11:21:04 +01:00
|
|
|
template<typename Type>
|
|
|
|
|
static auto toValue(Utils::SmallStringView sqlStatement, Database &database)
|
2017-09-21 11:43:59 +02:00
|
|
|
{
|
|
|
|
|
StatementImplementation statement(sqlStatement, database);
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2020-05-27 00:09:19 +02:00
|
|
|
statement.checkColumnCount(1);
|
|
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
statement.next();
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
return statement.template fetchValue<Type>(0);
|
|
|
|
|
}
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2021-03-24 18:10:55 +01:00
|
|
|
template<typename Callable, typename... QueryTypes>
|
2021-02-10 15:25:00 +01:00
|
|
|
void readCallback(Callable &&callable, const QueryTypes &...queryValues)
|
|
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
Resetter resetter{this};
|
2021-02-10 15:25:00 +01:00
|
|
|
|
|
|
|
|
bindValues(queryValues...);
|
|
|
|
|
|
|
|
|
|
while (BaseStatement::next()) {
|
2021-03-24 18:10:55 +01:00
|
|
|
auto control = callCallable(callable);
|
2021-02-10 15:25:00 +01:00
|
|
|
|
|
|
|
|
if (control == CallbackControl::Abort)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resetter.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 15:27:51 +00:00
|
|
|
template<typename Container, typename... QueryTypes>
|
2021-02-10 15:52:58 +01:00
|
|
|
void readTo(Container &container, const QueryTypes &...queryValues)
|
|
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
Resetter resetter{this};
|
2021-02-10 15:52:58 +01:00
|
|
|
|
|
|
|
|
bindValues(queryValues...);
|
|
|
|
|
|
|
|
|
|
while (BaseStatement::next())
|
2021-03-24 18:10:55 +01:00
|
|
|
emplaceBackValues(container);
|
2021-02-10 15:52:58 +01:00
|
|
|
|
|
|
|
|
resetter.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 15:27:51 +00:00
|
|
|
template<typename ResultType, typename... QueryTypes>
|
|
|
|
|
auto range(const QueryTypes &...queryValues)
|
|
|
|
|
{
|
|
|
|
|
return SqliteResultRange<ResultType>{*this, queryValues...};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ResultType, typename... QueryTypes>
|
|
|
|
|
auto rangeWithTransaction(const QueryTypes &...queryValues)
|
|
|
|
|
{
|
|
|
|
|
return SqliteResultRangeWithTransaction<ResultType>{*this, queryValues...};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ResultType>
|
|
|
|
|
class BaseSqliteResultRange
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
class SqliteResultIteratator
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using iterator_category = std::input_iterator_tag;
|
|
|
|
|
using difference_type = int;
|
|
|
|
|
using value_type = ResultType;
|
|
|
|
|
using pointer = ResultType *;
|
|
|
|
|
using reference = ResultType &;
|
|
|
|
|
|
|
|
|
|
SqliteResultIteratator(StatementImplementation &statement)
|
|
|
|
|
: m_statement{statement}
|
|
|
|
|
, m_hasNext{m_statement.next()}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
SqliteResultIteratator(StatementImplementation &statement, bool hasNext)
|
|
|
|
|
: m_statement{statement}
|
|
|
|
|
, m_hasNext{hasNext}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
SqliteResultIteratator &operator++()
|
|
|
|
|
{
|
|
|
|
|
m_hasNext = m_statement.next();
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void operator++(int) { m_hasNext = m_statement.next(); }
|
|
|
|
|
|
|
|
|
|
friend bool operator==(const SqliteResultIteratator &first,
|
|
|
|
|
const SqliteResultIteratator &second)
|
|
|
|
|
{
|
|
|
|
|
return first.m_hasNext == second.m_hasNext;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
friend bool operator!=(const SqliteResultIteratator &first,
|
|
|
|
|
const SqliteResultIteratator &second)
|
|
|
|
|
{
|
|
|
|
|
return !(first == second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value_type operator*() const { return m_statement.createValue<ResultType>(); }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
StatementImplementation &m_statement;
|
|
|
|
|
bool m_hasNext = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using value_type = ResultType;
|
|
|
|
|
using iterator = SqliteResultIteratator;
|
|
|
|
|
using const_iterator = iterator;
|
|
|
|
|
|
|
|
|
|
template<typename... QueryTypes>
|
|
|
|
|
BaseSqliteResultRange(StatementImplementation &statement, const QueryTypes &...queryValues)
|
|
|
|
|
: m_statement{statement}
|
|
|
|
|
{
|
|
|
|
|
statement.bindValues(queryValues...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BaseSqliteResultRange(BaseSqliteResultRange &) = delete;
|
|
|
|
|
BaseSqliteResultRange &operator=(BaseSqliteResultRange &) = delete;
|
|
|
|
|
|
|
|
|
|
BaseSqliteResultRange(BaseSqliteResultRange &&other)
|
|
|
|
|
: m_statement{std::move(other.resetter)}
|
|
|
|
|
{}
|
|
|
|
|
BaseSqliteResultRange &operator=(BaseSqliteResultRange &&) = delete;
|
|
|
|
|
|
|
|
|
|
iterator begin() & { return iterator{m_statement}; }
|
|
|
|
|
iterator end() & { return iterator{m_statement, false}; }
|
|
|
|
|
|
|
|
|
|
const_iterator begin() const & { return iterator{m_statement}; }
|
|
|
|
|
const_iterator end() const & { return iterator{m_statement, false}; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
StatementImplementation &m_statement;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename ResultType>
|
|
|
|
|
class SqliteResultRange : public BaseSqliteResultRange<ResultType>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
template<typename... QueryTypes>
|
|
|
|
|
SqliteResultRange(StatementImplementation &statement, const QueryTypes &...queryValues)
|
|
|
|
|
: BaseSqliteResultRange<ResultType>{statement}
|
|
|
|
|
, resetter{&statement}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
statement.bindValues(queryValues...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~SqliteResultRange()
|
|
|
|
|
{
|
|
|
|
|
if (!std::uncaught_exceptions())
|
|
|
|
|
resetter.reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Resetter resetter;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename ResultType>
|
|
|
|
|
class SqliteResultRangeWithTransaction : public BaseSqliteResultRange<ResultType>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
template<typename... QueryTypes>
|
|
|
|
|
SqliteResultRangeWithTransaction(StatementImplementation &statement,
|
|
|
|
|
const QueryTypes &...queryValues)
|
|
|
|
|
: BaseSqliteResultRange<ResultType>{statement}
|
|
|
|
|
, m_transaction{statement.database()}
|
|
|
|
|
, resetter{&statement}
|
|
|
|
|
{
|
|
|
|
|
statement.bindValues(queryValues...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~SqliteResultRangeWithTransaction()
|
|
|
|
|
{
|
|
|
|
|
if (!std::uncaught_exceptions()) {
|
|
|
|
|
resetter.reset();
|
|
|
|
|
m_transaction.commit();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
DeferredTransaction m_transaction;
|
|
|
|
|
Resetter resetter;
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-12 14:08:18 +01:00
|
|
|
protected:
|
|
|
|
|
~StatementImplementation() = default;
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
private:
|
|
|
|
|
struct Resetter
|
|
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
Resetter(StatementImplementation *statement)
|
2017-09-21 11:43:59 +02:00
|
|
|
: statement(statement)
|
|
|
|
|
{}
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2021-05-06 15:27:51 +00:00
|
|
|
Resetter(Resetter &) = delete;
|
|
|
|
|
Resetter &operator=(Resetter &) = delete;
|
|
|
|
|
|
|
|
|
|
Resetter(Resetter &&other)
|
|
|
|
|
: statement{std::exchange(other.statement, nullptr)}
|
|
|
|
|
{}
|
|
|
|
|
|
2017-10-23 13:26:32 +02:00
|
|
|
void reset()
|
|
|
|
|
{
|
|
|
|
|
try {
|
2021-05-06 15:27:51 +00:00
|
|
|
if (statement)
|
|
|
|
|
statement->reset();
|
2017-10-23 13:26:32 +02:00
|
|
|
} catch (...) {
|
2021-05-06 15:27:51 +00:00
|
|
|
statement = nullptr;
|
2017-10-23 13:26:32 +02:00
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 15:27:51 +00:00
|
|
|
statement = nullptr;
|
2017-10-23 13:26:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~Resetter() noexcept
|
2017-09-21 11:43:59 +02:00
|
|
|
{
|
2017-10-23 13:26:32 +02:00
|
|
|
try {
|
2021-05-06 15:27:51 +00:00
|
|
|
if (statement)
|
|
|
|
|
statement->reset();
|
2017-10-23 13:26:32 +02:00
|
|
|
} catch (...) {
|
|
|
|
|
}
|
2017-09-21 11:43:59 +02:00
|
|
|
}
|
Sqlite: Add variadic bind and write functions
You can now write
SqliteWriteStatement statement("UPDATE test SET name=?, number=?
WHERE rowid=?", database);
statement.write("see", 7.23, 1);
and
SqliteWriteStatement statement("UPDATE test SET name=@name, number=@number
WHERE rowid=@id", database);
statement.writeNamed("@name", "see", "@number", 7.23, "@id", 1);
This is more type safe than using variants and performant too.
Change-Id: Ie1ed2a6d326b956be5c4ec056214f3f5b1531f45
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
2017-07-31 19:44:39 +02:00
|
|
|
|
2021-05-06 15:27:51 +00:00
|
|
|
StatementImplementation *statement;
|
2017-09-21 11:43:59 +02:00
|
|
|
};
|
2017-07-26 18:43:07 +02:00
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
struct ValueGetter
|
2017-09-21 11:43:24 +02:00
|
|
|
{
|
2017-09-21 11:43:59 +02:00
|
|
|
ValueGetter(StatementImplementation &statement, int column)
|
2020-04-27 20:01:38 +02:00
|
|
|
: statement(statement)
|
|
|
|
|
, column(column)
|
2017-09-21 11:43:24 +02:00
|
|
|
{}
|
|
|
|
|
|
2020-04-27 20:01:38 +02:00
|
|
|
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::SmallStringView() { return statement.fetchSmallStringViewValue(column); }
|
2020-09-16 13:44:43 +02:00
|
|
|
operator BlobView() { return statement.fetchBlobValue(column); }
|
2020-04-27 20:01:38 +02:00
|
|
|
operator ValueView() { return statement.fetchValueView(column); }
|
2017-09-21 11:43:24 +02:00
|
|
|
|
2017-09-21 11:43:59 +02:00
|
|
|
StatementImplementation &statement;
|
2017-09-21 11:43:24 +02:00
|
|
|
int column;
|
|
|
|
|
};
|
|
|
|
|
|
2021-05-06 15:27:51 +00:00
|
|
|
constexpr int resultCount(int localResultCount) const
|
|
|
|
|
{
|
|
|
|
|
return ResultCount < 0 ? localResultCount : ResultCount;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-24 18:10:55 +01:00
|
|
|
template<typename ContainerType, int... ColumnIndices>
|
2017-09-21 11:43:24 +02:00
|
|
|
void emplaceBackValues(ContainerType &container, std::integer_sequence<int, ColumnIndices...>)
|
2017-08-17 15:33:25 +02:00
|
|
|
{
|
2017-09-21 11:43:24 +02:00
|
|
|
container.emplace_back(ValueGetter(*this, ColumnIndices)...);
|
2017-08-17 15:33:25 +02:00
|
|
|
}
|
|
|
|
|
|
2021-03-24 18:10:55 +01:00
|
|
|
template<typename ContainerType>
|
2017-09-21 11:43:24 +02:00
|
|
|
void emplaceBackValues(ContainerType &container)
|
2017-08-17 15:33:25 +02:00
|
|
|
{
|
2021-03-24 18:10:55 +01:00
|
|
|
emplaceBackValues(container, std::make_integer_sequence<int, ResultCount>{});
|
2017-08-17 15:33:25 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-06 15:27:51 +00:00
|
|
|
template<typename ResultOptionalType, int... ColumnIndices>
|
|
|
|
|
ResultOptionalType createOptionalValue(std::integer_sequence<int, ColumnIndices...>)
|
2017-08-17 15:33:25 +02:00
|
|
|
{
|
2017-09-21 11:43:24 +02:00
|
|
|
return ResultOptionalType(Utils::in_place, ValueGetter(*this, ColumnIndices)...);
|
2017-08-17 15:33:25 +02:00
|
|
|
}
|
|
|
|
|
|
2021-03-24 18:10:55 +01:00
|
|
|
template<typename ResultOptionalType>
|
2021-05-06 15:27:51 +00:00
|
|
|
ResultOptionalType createOptionalValue()
|
|
|
|
|
{
|
|
|
|
|
return createOptionalValue<ResultOptionalType>(std::make_integer_sequence<int, ResultCount>{});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ResultType, int... ColumnIndices>
|
|
|
|
|
ResultType createValue(std::integer_sequence<int, ColumnIndices...>)
|
|
|
|
|
{
|
|
|
|
|
return ResultType{ValueGetter(*this, ColumnIndices)...};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ResultType>
|
|
|
|
|
ResultType createValue()
|
2017-08-17 15:33:25 +02:00
|
|
|
{
|
2021-05-06 15:27:51 +00:00
|
|
|
return createValue<ResultType>(std::make_integer_sequence<int, ResultCount>{});
|
2017-08-17 15:33:25 +02:00
|
|
|
}
|
|
|
|
|
|
2021-02-10 15:25:00 +01:00
|
|
|
template<typename Callable, int... ColumnIndices>
|
|
|
|
|
CallbackControl callCallable(Callable &&callable, std::integer_sequence<int, ColumnIndices...>)
|
|
|
|
|
{
|
|
|
|
|
return std::invoke(callable, ValueGetter(*this, ColumnIndices)...);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-24 18:10:55 +01:00
|
|
|
template<typename Callable>
|
2021-02-10 15:25:00 +01:00
|
|
|
CallbackControl callCallable(Callable &&callable)
|
|
|
|
|
{
|
2021-03-24 18:10:55 +01:00
|
|
|
return callCallable(callable, std::make_integer_sequence<int, ResultCount>{});
|
2021-02-10 15:25:00 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-06 15:27:51 +00:00
|
|
|
template<typename ValueType>
|
|
|
|
|
void bindValuesByIndex(int index, const ValueType &value)
|
|
|
|
|
{
|
|
|
|
|
BaseStatement::bind(index, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ValueType, typename... ValueTypes>
|
|
|
|
|
void bindValuesByIndex(int index, const ValueType &value, const ValueTypes &...values)
|
|
|
|
|
{
|
|
|
|
|
BaseStatement::bind(index, value);
|
|
|
|
|
bindValuesByIndex(index + 1, values...);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-16 14:47:01 +02:00
|
|
|
void setMaximumResultCount(std::size_t count)
|
|
|
|
|
{
|
|
|
|
|
m_maximumResultCount = std::max(m_maximumResultCount, count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
std::size_t m_maximumResultCount = 0;
|
2015-06-01 18:51:55 +02:00
|
|
|
};
|
2017-07-26 16:02:24 +02:00
|
|
|
|
|
|
|
|
} // namespace Sqlite
|