Sqlite: Move result count to class declaration

It move the magic number of column results to the sql statement
and improves the mock a little bit.

Change-Id: I101067444cf27ec5dea0c72de7fd484a7e8710f0
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2021-03-24 18:10:55 +01:00
parent eb516063d3
commit 7785a3a651
58 changed files with 1038 additions and 1967 deletions

View File

@@ -30,15 +30,15 @@ add_qtc_library(Sqlite
sqliteexception.cpp sqliteexception.h
sqliteglobal.cpp sqliteglobal.h
sqliteindex.h
sqlitereadstatement.cpp sqlitereadstatement.h
sqlitereadwritestatement.cpp sqlitereadwritestatement.h
sqlitereadstatement.h
sqlitereadwritestatement.h
sqlitesessionchangeset.cpp sqlitesessionchangeset.h
sqlitesessions.cpp sqlitesessions.h
sqlitetable.h
sqlitetransaction.h
sqlitetransaction.h
sqlitevalue.h
sqlitewritestatement.cpp sqlitewritestatement.h
sqlitewritestatement.h
sqlstatementbuilder.cpp sqlstatementbuilder.h
sqlstatementbuilderexception.h
tableconstraints.h

View File

@@ -15,11 +15,8 @@ SOURCES += \
$$PWD/sqlitedatabasebackend.cpp \
$$PWD/sqliteexception.cpp \
$$PWD/sqliteglobal.cpp \
$$PWD/sqlitereadstatement.cpp \
$$PWD/sqlitereadwritestatement.cpp \
$$PWD/sqlitesessionchangeset.cpp \
$$PWD/sqlitesessions.cpp \
$$PWD/sqlitewritestatement.cpp \
$$PWD/sqlstatementbuilder.cpp \
$$PWD/utf8string.cpp \
$$PWD/utf8stringvector.cpp \

View File

@@ -10,12 +10,9 @@ SOURCES += \
sqlitedatabaseconnectionproxy.cpp \
sqliteexception.cpp \
sqliteglobal.cpp \
sqlitereadstatement.cpp \
sqlitereadwritestatement.cpp \
sqlitestatement.cpp \
sqlitetransaction.cpp \
sqliteworkerthread.cpp \
sqlitewritestatement.cpp \
sqlstatementbuilder.cpp \
utf8string.cpp \
utf8stringvector.cpp \

View File

@@ -159,7 +159,7 @@ extern template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<U
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>
template<typename BaseStatement, int ResultCount>
class StatementImplementation : public BaseStatement
{
@@ -192,18 +192,15 @@ public:
resetter.reset();
}
template <typename ResultType,
int ResultTypeCount = 1>
template<typename ResultType>
std::vector<ResultType> values(std::size_t reserveSize)
{
BaseStatement::checkColumnCount(ResultTypeCount);
Resetter resetter{*this};
std::vector<ResultType> resultValues;
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
while (BaseStatement::next())
emplaceBackValues<ResultTypeCount>(resultValues);
emplaceBackValues(resultValues);
setMaximumResultCount(resultValues.size());
@@ -212,11 +209,9 @@ public:
return resultValues;
}
template<typename ResultType, int ResultTypeCount = 1, typename... QueryTypes>
template<typename ResultType, typename... QueryTypes>
auto values(std::size_t reserveSize, const QueryTypes &...queryValues)
{
BaseStatement::checkColumnCount(ResultTypeCount);
Resetter resetter{*this};
std::vector<ResultType> resultValues;
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
@@ -224,7 +219,7 @@ public:
bindValues(queryValues...);
while (BaseStatement::next())
emplaceBackValues<ResultTypeCount>(resultValues);
emplaceBackValues(resultValues);
setMaximumResultCount(resultValues.size());
@@ -233,66 +228,16 @@ public:
return resultValues;
}
template<typename ResultType, int ResultTypeCount = 1, typename QueryElementType>
auto values(std::size_t reserveSize, const std::vector<QueryElementType> &queryValues)
{
BaseStatement::checkColumnCount(ResultTypeCount);
std::vector<ResultType> resultValues;
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
for (const QueryElementType &queryValue : queryValues) {
Resetter resetter{*this};
bindValues(queryValue);
while (BaseStatement::next())
emplaceBackValues<ResultTypeCount>(resultValues);
setMaximumResultCount(resultValues.size());
resetter.reset();
}
return resultValues;
}
template<typename ResultType, int ResultTypeCount = 1, typename... QueryElementTypes>
auto values(std::size_t reserveSize,
const std::vector<std::tuple<QueryElementTypes...>> &queryTuples)
{
BaseStatement::checkColumnCount(ResultTypeCount);
using Container = std::vector<ResultType>;
Container resultValues;
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
for (const auto &queryTuple : queryTuples) {
Resetter resetter{*this};
bindTupleValues(queryTuple);
while (BaseStatement::next())
emplaceBackValues<ResultTypeCount>(resultValues);
setMaximumResultCount(resultValues.size());
resetter.reset();
}
return resultValues;
}
template<typename ResultType, int ResultTypeCount = 1, typename... QueryTypes>
template<typename ResultType, typename... QueryTypes>
auto value(const QueryTypes &...queryValues)
{
BaseStatement::checkColumnCount(ResultTypeCount);
Resetter resetter{*this};
Utils::optional<ResultType> resultValue;
bindValues(queryValues...);
if (BaseStatement::next())
resultValue = assignValue<Utils::optional<ResultType>, ResultTypeCount>();
resultValue = assignValue<Utils::optional<ResultType>>();
resetter.reset();
@@ -311,17 +256,15 @@ public:
return statement.template fetchValue<Type>(0);
}
template<int ResultTypeCount = 1, typename Callable, typename... QueryTypes>
template<typename Callable, typename... QueryTypes>
void readCallback(Callable &&callable, const QueryTypes &...queryValues)
{
BaseStatement::checkColumnCount(ResultTypeCount);
Resetter resetter{*this};
bindValues(queryValues...);
while (BaseStatement::next()) {
auto control = callCallable<ResultTypeCount>(callable);
auto control = callCallable(callable);
if (control == CallbackControl::Abort)
break;
@@ -333,14 +276,12 @@ public:
template<int ResultTypeCount = 1, typename Container, typename... QueryTypes>
void readTo(Container &container, const QueryTypes &...queryValues)
{
BaseStatement::checkColumnCount(ResultTypeCount);
Resetter resetter{*this};
bindValues(queryValues...);
while (BaseStatement::next())
emplaceBackValues<ResultTypeCount>(container);
emplaceBackValues(container);
resetter.reset();
}
@@ -399,18 +340,21 @@ private:
int column;
};
template <typename ContainerType,
int... ColumnIndices>
constexpr int resultCount(int localResultCount) const
{
return ResultCount < 0 ? localResultCount : ResultCount;
}
template<typename ContainerType, int... ColumnIndices>
void emplaceBackValues(ContainerType &container, std::integer_sequence<int, ColumnIndices...>)
{
container.emplace_back(ValueGetter(*this, ColumnIndices)...);
}
template <int ResultTypeCount,
typename ContainerType>
template<typename ContainerType>
void emplaceBackValues(ContainerType &container)
{
emplaceBackValues(container, std::make_integer_sequence<int, ResultTypeCount>{});
emplaceBackValues(container, std::make_integer_sequence<int, ResultCount>{});
}
template <typename ResultOptionalType,
@@ -420,11 +364,10 @@ private:
return ResultOptionalType(Utils::in_place, ValueGetter(*this, ColumnIndices)...);
}
template <typename ResultOptionalType,
int ResultTypeCount>
template<typename ResultOptionalType>
ResultOptionalType assignValue()
{
return assignValue<ResultOptionalType>(std::make_integer_sequence<int, ResultTypeCount>{});
return assignValue<ResultOptionalType>(std::make_integer_sequence<int, ResultCount>{});
}
template<typename Callable, int... ColumnIndices>
@@ -433,10 +376,10 @@ private:
return std::invoke(callable, ValueGetter(*this, ColumnIndices)...);
}
template<int ResultTypeCount, typename Callable>
template<typename Callable>
CallbackControl callCallable(Callable &&callable)
{
return callCallable(callable, std::make_integer_sequence<int, ResultTypeCount>{});
return callCallable(callable, std::make_integer_sequence<int, ResultCount>{});
}
template<typename ValueType>

View File

@@ -47,11 +47,11 @@ public:
public:
Database &database;
ReadWriteStatement deferredBegin{"BEGIN", database};
ReadWriteStatement immediateBegin{"BEGIN IMMEDIATE", database};
ReadWriteStatement exclusiveBegin{"BEGIN EXCLUSIVE", database};
ReadWriteStatement commitBegin{"COMMIT", database};
ReadWriteStatement rollbackBegin{"ROLLBACK", database};
ReadWriteStatement<> deferredBegin{"BEGIN", database};
ReadWriteStatement<> immediateBegin{"BEGIN IMMEDIATE", database};
ReadWriteStatement<> exclusiveBegin{"BEGIN EXCLUSIVE", database};
ReadWriteStatement<> commitBegin{"COMMIT", database};
ReadWriteStatement<> rollbackBegin{"ROLLBACK", database};
Sessions sessions{database, "main", "databaseSessions"};
};

View File

@@ -42,8 +42,10 @@ namespace Sqlite {
using namespace std::chrono_literals;
template<int ResultCount>
class ReadStatement;
class WriteStatement;
template<int ResultCount>
class ReadWriteStatement;
class SQLITE_EXPORT Database final : public TransactionInterface, public DatabaseInterface
@@ -54,9 +56,11 @@ class SQLITE_EXPORT Database final : public TransactionInterface, public Databas
public:
using MutexType = std::mutex;
using ReadStatement = Sqlite::ReadStatement;
template<int ResultCount>
using ReadStatement = Sqlite::ReadStatement<ResultCount>;
using WriteStatement = Sqlite::WriteStatement;
using ReadWriteStatement = Sqlite::ReadWriteStatement;
template<int ResultCount = 0>
using ReadWriteStatement = Sqlite::ReadWriteStatement<ResultCount>;
using BusyHandler = DatabaseBackend::BusyHandler;
Database();

View File

@@ -128,7 +128,9 @@ sqlite3 *DatabaseBackend::sqliteDatabaseHandle() const
void DatabaseBackend::setPragmaValue(Utils::SmallStringView pragmaKey, Utils::SmallStringView newPragmaValue)
{
execute(Utils::SmallString{"PRAGMA ", pragmaKey, "='", newPragmaValue, "'"});
ReadWriteStatement<1>{Utils::SmallString{"PRAGMA ", pragmaKey, "='", newPragmaValue, "'"},
m_database}
.execute();
Utils::SmallString pragmeValueInDatabase = toValue<Utils::SmallString>("PRAGMA " + pragmaKey);
checkPragmaValue(pragmeValueInDatabase, newPragmaValue);
@@ -172,7 +174,7 @@ void DatabaseBackend::setLastInsertedRowId(int64_t rowId)
void DatabaseBackend::execute(Utils::SmallStringView sqlStatement)
{
try {
ReadWriteStatement statement(sqlStatement, m_database);
ReadWriteStatement<0> statement(sqlStatement, m_database);
statement.execute();
} catch (StatementIsBusy &) {
execute(sqlStatement);
@@ -454,7 +456,7 @@ template <typename Type>
Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement)
{
try {
ReadWriteStatement statement(sqlStatement, m_database);
ReadWriteStatement<1> statement(sqlStatement, m_database);
statement.next();

View File

@@ -1,45 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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
** 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.
**
** 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.
**
****************************************************************************/
#include "sqlitereadstatement.h"
#include "sqlite3.h"
namespace Sqlite {
ReadStatement::ReadStatement(Utils::SmallStringView sqlStatement,
Database &database)
: StatementImplementation(sqlStatement, database)
{
checkIsReadOnlyStatement();
}
void ReadStatement::checkIsReadOnlyStatement()
{
if (!isReadOnlyStatement())
throw NotReadOnlySqlStatement("SqliteStatement::SqliteReadStatement: is not read only statement!");
}
} // namespace Sqlite

View File

@@ -29,19 +29,37 @@
namespace Sqlite {
class SQLITE_EXPORT ReadStatement final : protected StatementImplementation<BaseStatement>
template<int ResultCount>
class ReadStatement final : protected StatementImplementation<BaseStatement, ResultCount>
{
public:
explicit ReadStatement(Utils::SmallStringView sqlStatement, Database &database);
using Base = StatementImplementation<BaseStatement, ResultCount>;
using StatementImplementation::readCallback;
using StatementImplementation::readTo;
using StatementImplementation::toValue;
using StatementImplementation::value;
using StatementImplementation::values;
public:
ReadStatement(Utils::SmallStringView sqlStatement, Database &database)
: Base{sqlStatement, database}
{
checkIsReadOnlyStatement();
Base::checkColumnCount(ResultCount);
}
using Base::readCallback;
using Base::readTo;
using Base::toValue;
using Base::value;
using Base::values;
protected:
void checkIsReadOnlyStatement();
void checkIsReadOnlyStatement()
{
if (!Base::isReadOnlyStatement())
throw NotReadOnlySqlStatement(
"SqliteStatement::SqliteReadStatement: is not read only statement!");
}
};
template<int ResultCount>
ReadStatement(ReadStatement<ResultCount> &) -> ReadStatement<ResultCount>;
template<int ResultCount>
ReadStatement(const ReadStatement<ResultCount> &) -> ReadStatement<ResultCount>;
} // namespace Sqlite

View File

@@ -1,36 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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
** 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.
**
** 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.
**
****************************************************************************/
#include "sqlitereadwritestatement.h"
namespace Sqlite {
ReadWriteStatement::ReadWriteStatement(Utils::SmallStringView sqlStatement,
Database &database)
: StatementImplementation(sqlStatement, database)
{
}
} // namespace Sqlite

View File

@@ -29,20 +29,26 @@
namespace Sqlite {
class SQLITE_EXPORT ReadWriteStatement final : protected StatementImplementation<BaseStatement>
template<int ResultCount = 0>
class ReadWriteStatement final : protected StatementImplementation<BaseStatement, ResultCount>
{
friend class DatabaseBackend;
using Base = StatementImplementation<BaseStatement, ResultCount>;
public:
ReadWriteStatement(Utils::SmallStringView sqlStatement, Database &database);
ReadWriteStatement(Utils::SmallStringView sqlStatement, Database &database)
: Base{sqlStatement, database}
{
Base::checkColumnCount(ResultCount);
}
using StatementImplementation::execute;
using StatementImplementation::readCallback;
using StatementImplementation::readTo;
using StatementImplementation::toValue;
using StatementImplementation::value;
using StatementImplementation::values;
using StatementImplementation::write;
using Base::execute;
using Base::readCallback;
using Base::readTo;
using Base::toValue;
using Base::value;
using Base::values;
using Base::write;
};
} // namespace Sqlite

View File

@@ -127,10 +127,10 @@ void Internal::SessionsBase::createSessionTable(Database &database)
void Sessions::revert()
{
ReadStatement selectChangeSets{Utils::PathString{"SELECT changeset FROM ",
sessionsTableName,
" ORDER BY id DESC"},
database};
ReadStatement<1> selectChangeSets{Utils::PathString{"SELECT changeset FROM ",
sessionsTableName,
" ORDER BY id DESC"},
database};
auto changeSets = selectChangeSets.values<SessionChangeSet>(1024);
@@ -151,10 +151,10 @@ void Sessions::revert()
void Sessions::apply()
{
ReadStatement selectChangeSets{Utils::PathString{"SELECT changeset FROM ",
sessionsTableName,
" ORDER BY id"},
database};
ReadStatement<1> selectChangeSets{Utils::PathString{"SELECT changeset FROM ",
sessionsTableName,
" ORDER BY id"},
database};
auto changeSets = selectChangeSets.values<SessionChangeSet>(1024);
@@ -187,10 +187,10 @@ void Sessions::deleteAll()
SessionChangeSets Sessions::changeSets() const
{
ReadStatement selectChangeSets{Utils::PathString{"SELECT changeset FROM ",
sessionsTableName,
" ORDER BY id DESC"},
database};
ReadStatement<1> selectChangeSets{Utils::PathString{"SELECT changeset FROM ",
sessionsTableName,
" ORDER BY id DESC"},
database};
return selectChangeSets.values<SessionChangeSet>(1024);
}

View File

@@ -1,43 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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
** 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.
**
** 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.
**
****************************************************************************/
#include "sqlitewritestatement.h"
namespace Sqlite {
WriteStatement::WriteStatement(Utils::SmallStringView sqlStatement,
Database &database)
: StatementImplementation(sqlStatement, database)
{
checkIsWritableStatement();
}
void WriteStatement::checkIsWritableStatement()
{
if (isReadOnlyStatement())
throw NotWriteSqlStatement("SqliteStatement::SqliteWriteStatement: is not a writable statement!");
}
} // namespace Sqlite

View File

@@ -29,17 +29,28 @@
namespace Sqlite {
class SQLITE_EXPORT WriteStatement : protected StatementImplementation<BaseStatement>
class WriteStatement : protected StatementImplementation<BaseStatement, -1>
{
public:
explicit WriteStatement(Utils::SmallStringView sqlStatement, Database &database);
using Base = StatementImplementation<BaseStatement, -1>;
public:
WriteStatement(Utils::SmallStringView sqlStatement, Database &database)
: StatementImplementation(sqlStatement, database)
{
checkIsWritableStatement();
}
using StatementImplementation::execute;
using StatementImplementation::database;
using StatementImplementation::execute;
using StatementImplementation::write;
protected:
void checkIsWritableStatement();
void checkIsWritableStatement()
{
if (Base::isReadOnlyStatement())
throw NotWriteSqlStatement(
"SqliteStatement::SqliteWriteStatement: is not a writable statement!");
}
};
} // namespace Sqlite