diff options
author | Marco Bubke <[email protected]> | 2017-08-17 15:33:25 +0200 |
---|---|---|
committer | Marco Bubke <[email protected]> | 2017-08-28 14:50:33 +0000 |
commit | 1a25b61576f82f4042cf57ad0c51a94bedbed77c (patch) | |
tree | db26c7bb8cd49530b71a895f3e4cb2c37b5f29d4 /src/libs/sqlite | |
parent | 8617f497bcb0c30ea83ef5afe1e40e8b5d3802b4 (diff) |
Sqlite: Improve Sqlite wrapper
It is now possible to read values at once.
for (auto [name, value] : statement.tupleValues<String, int>(1000, "foo", 20))
....
Change-Id: I3d4bc5218810b4620e1df625126aa490f30bbc71
Reviewed-by: Tim Jenssen <[email protected]>
Diffstat (limited to 'src/libs/sqlite')
-rw-r--r-- | src/libs/sqlite/createtablesqlstatementbuilder.cpp | 48 | ||||
-rw-r--r-- | src/libs/sqlite/createtablesqlstatementbuilder.h | 13 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitecolumn.h | 18 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitedatabase.cpp | 15 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitedatabase.h | 2 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitedatabasebackend.cpp | 8 | ||||
-rw-r--r-- | src/libs/sqlite/sqliteglobal.h | 11 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitereadstatement.h | 2 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitereadwritestatement.h | 2 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitestatement.cpp | 109 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitestatement.h | 335 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitetable.cpp | 24 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitetable.h | 40 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitetransaction.cpp | 40 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitetransaction.h | 55 | ||||
-rw-r--r-- | src/libs/sqlite/sqlstatementbuilder.cpp | 2 | ||||
-rw-r--r-- | src/libs/sqlite/sqlstatementbuilder.h | 6 |
17 files changed, 516 insertions, 214 deletions
diff --git a/src/libs/sqlite/createtablesqlstatementbuilder.cpp b/src/libs/sqlite/createtablesqlstatementbuilder.cpp index c543d28de39..dfdc779faad 100644 --- a/src/libs/sqlite/createtablesqlstatementbuilder.cpp +++ b/src/libs/sqlite/createtablesqlstatementbuilder.cpp @@ -28,12 +28,11 @@ namespace Sqlite { CreateTableSqlStatementBuilder::CreateTableSqlStatementBuilder() - : m_sqlStatementBuilder("CREATE TABLE IF NOT EXISTS $table($columnDefinitions)$withoutRowId"), - m_useWithoutRowId(false) + : m_sqlStatementBuilder("CREATE $temporaryTABLE $ifNotExits$table($columnDefinitions)$withoutRowId") { } -void CreateTableSqlStatementBuilder::setTable(Utils::SmallString &&tableName) +void CreateTableSqlStatementBuilder::setTableName(Utils::SmallString &&tableName) { m_sqlStatementBuilder.clear(); @@ -42,11 +41,11 @@ void CreateTableSqlStatementBuilder::setTable(Utils::SmallString &&tableName) void CreateTableSqlStatementBuilder::addColumn(Utils::SmallString &&columnName, ColumnType columnType, - IsPrimaryKey isPrimaryKey) + Contraint constraint) { m_sqlStatementBuilder.clear(); - m_columns.emplace_back(std::move(columnName), columnType, isPrimaryKey); + m_columns.emplace_back(std::move(columnName), columnType, constraint); } void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns) @@ -61,6 +60,16 @@ void CreateTableSqlStatementBuilder::setUseWithoutRowId(bool useWithoutRowId) m_useWithoutRowId = useWithoutRowId; } +void CreateTableSqlStatementBuilder::setUseIfNotExists(bool useIfNotExists) +{ + m_useIfNotExits = useIfNotExists; +} + +void CreateTableSqlStatementBuilder::setUseTemporaryTable(bool useTemporaryTable) +{ + m_useTemporaryTable = useTemporaryTable; +} + void CreateTableSqlStatementBuilder::clear() { m_sqlStatementBuilder.clear(); @@ -95,8 +104,11 @@ void CreateTableSqlStatementBuilder::bindColumnDefinitions() const for (const SqliteColumn &columns : m_columns) { Utils::SmallString columnDefinitionString = {columns.name(), " ", columns.typeString()}; - if (columns.isPrimaryKey()) - columnDefinitionString.append(" PRIMARY KEY"); + switch (columns.constraint()) { + case Contraint::PrimaryKey: columnDefinitionString.append(" PRIMARY KEY"); break; + case Contraint::Unique: columnDefinitionString.append(" UNIQUE"); break; + case Contraint::NoConstraint: break; + } columnDefinitionStrings.push_back(columnDefinitionString); } @@ -108,12 +120,34 @@ void CreateTableSqlStatementBuilder::bindAll() const { m_sqlStatementBuilder.bind("$table", m_tableName.clone()); + bindTemporary(); + bindIfNotExists(); bindColumnDefinitions(); + bindWithoutRowId(); +} +void CreateTableSqlStatementBuilder::bindWithoutRowId() const +{ if (m_useWithoutRowId) m_sqlStatementBuilder.bind("$withoutRowId", " WITHOUT ROWID"); else m_sqlStatementBuilder.bindEmptyText("$withoutRowId"); } +void CreateTableSqlStatementBuilder::bindIfNotExists() const +{ + if (m_useIfNotExits) + m_sqlStatementBuilder.bind("$ifNotExits", "IF NOT EXISTS "); + else + m_sqlStatementBuilder.bindEmptyText("$ifNotExits"); +} + +void CreateTableSqlStatementBuilder::bindTemporary() const +{ + if (m_useTemporaryTable) + m_sqlStatementBuilder.bind("$temporary", "TEMPORARY "); + else + m_sqlStatementBuilder.bindEmptyText("$temporary"); +} + } // namespace Sqlite diff --git a/src/libs/sqlite/createtablesqlstatementbuilder.h b/src/libs/sqlite/createtablesqlstatementbuilder.h index f33a8920a23..00c9ebd45a1 100644 --- a/src/libs/sqlite/createtablesqlstatementbuilder.h +++ b/src/libs/sqlite/createtablesqlstatementbuilder.h @@ -35,12 +35,14 @@ class SQLITE_EXPORT CreateTableSqlStatementBuilder public: CreateTableSqlStatementBuilder(); - void setTable(Utils::SmallString &&tableName); + void setTableName(Utils::SmallString &&tableName); void addColumn(Utils::SmallString &&columnName, ColumnType columnType, - IsPrimaryKey isPrimaryKey = IsPrimaryKey::No); + Contraint constraint = Contraint::NoConstraint); void setColumns(const SqliteColumns &columns); void setUseWithoutRowId(bool useWithoutRowId); + void setUseIfNotExists(bool useIfNotExists); + void setUseTemporaryTable(bool useTemporaryTable); void clear(); void clearColumns(); @@ -52,12 +54,17 @@ public: protected: void bindColumnDefinitions() const; void bindAll() const; + void bindWithoutRowId() const; + void bindIfNotExists() const; + void bindTemporary() const; private: mutable SqlStatementBuilder m_sqlStatementBuilder; Utils::SmallString m_tableName; SqliteColumns m_columns; - bool m_useWithoutRowId; + bool m_useWithoutRowId = false; + bool m_useIfNotExits = false; + bool m_useTemporaryTable = false; }; } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitecolumn.h b/src/libs/sqlite/sqlitecolumn.h index c16333ce231..e25ee68b2d7 100644 --- a/src/libs/sqlite/sqlitecolumn.h +++ b/src/libs/sqlite/sqlitecolumn.h @@ -38,17 +38,17 @@ public: SqliteColumn(Utils::SmallString &&name, ColumnType type = ColumnType::Numeric, - IsPrimaryKey isPrimaryKey = IsPrimaryKey::No) + Contraint constraint = Contraint::NoConstraint) : m_name(std::move(name)), m_type(type), - m_isPrimaryKey(isPrimaryKey) + m_constraint(constraint) {} void clear() { m_name.clear(); m_type = ColumnType::Numeric; - m_isPrimaryKey = IsPrimaryKey::No; + m_constraint = Contraint::NoConstraint; } void setName(Utils::SmallString &&newName) @@ -71,14 +71,14 @@ public: return m_type; } - void setIsPrimaryKey(IsPrimaryKey isPrimaryKey) + void setContraint(Contraint constraint) { - m_isPrimaryKey = isPrimaryKey; + m_constraint = constraint; } - bool isPrimaryKey() const + Contraint constraint() const { - return m_isPrimaryKey == IsPrimaryKey::Yes; + return m_constraint; } Utils::SmallString typeString() const @@ -98,13 +98,13 @@ public: { return first.m_name == second.m_name && first.m_type == second.m_type - && first.m_isPrimaryKey == second.m_isPrimaryKey; + && first.m_constraint == second.m_constraint; } private: Utils::SmallString m_name; ColumnType m_type = ColumnType::Numeric; - IsPrimaryKey m_isPrimaryKey = IsPrimaryKey::No; + Contraint m_constraint = Contraint::NoConstraint; }; using SqliteColumns = std::vector<SqliteColumn>; diff --git a/src/libs/sqlite/sqlitedatabase.cpp b/src/libs/sqlite/sqlitedatabase.cpp index ec2379c61c1..4d53eecb35a 100644 --- a/src/libs/sqlite/sqlitedatabase.cpp +++ b/src/libs/sqlite/sqlitedatabase.cpp @@ -26,6 +26,7 @@ #include "sqlitedatabase.h" #include "sqlitetable.h" +#include "sqlitetransaction.h" namespace Sqlite { @@ -34,6 +35,12 @@ SqliteDatabase::SqliteDatabase() { } +SqliteDatabase::SqliteDatabase(Utils::PathString &&databaseFilePath) + : m_databaseBackend(*this) +{ + open(std::move(databaseFilePath)); +} + void SqliteDatabase::open() { m_databaseBackend.open(m_databaseFilePath, m_openMode); @@ -61,7 +68,7 @@ bool SqliteDatabase::isOpen() const SqliteTable &SqliteDatabase::addTable() { - m_sqliteTables.emplace_back(*this); + m_sqliteTables.emplace_back(); return m_sqliteTables.back(); } @@ -118,8 +125,12 @@ void SqliteDatabase::execute(Utils::SmallStringView sqlStatement) void SqliteDatabase::initializeTables() { + SqliteImmediateTransaction<SqliteDatabase> transaction(*this); + for (SqliteTable &table : m_sqliteTables) - table.initialize(); + table.initialize(*this); + + transaction.commit(); } SqliteDatabaseBackend &SqliteDatabase::backend() diff --git a/src/libs/sqlite/sqlitedatabase.h b/src/libs/sqlite/sqlitedatabase.h index 2e178a0190c..0ac340bb129 100644 --- a/src/libs/sqlite/sqlitedatabase.h +++ b/src/libs/sqlite/sqlitedatabase.h @@ -37,12 +37,14 @@ namespace Sqlite { class SQLITE_EXPORT SqliteDatabase { + template <typename Database> friend class SqliteAbstractTransaction; friend class SqliteStatement; friend class SqliteBackend; public: SqliteDatabase(); + SqliteDatabase(Utils::PathString &&databaseFilePath); SqliteDatabase(const SqliteDatabase &) = delete; bool operator=(const SqliteDatabase &) = delete; diff --git a/src/libs/sqlite/sqlitedatabasebackend.cpp b/src/libs/sqlite/sqlitedatabasebackend.cpp index 79eed32eab4..6ea70f30ada 100644 --- a/src/libs/sqlite/sqlitedatabasebackend.cpp +++ b/src/libs/sqlite/sqlitedatabasebackend.cpp @@ -38,14 +38,6 @@ #include "sqlite3.h" -#if defined(Q_OS_DARWIN) && defined(Q_CC_GNU) -#define QTC_THREAD_LOCAL __thread -#else -#define QTC_THREAD_LOCAL thread_local -#endif - -#define SIZE_OF_BYTEARRAY_ARRAY(array) sizeof(array)/sizeof(QByteArray) - namespace Sqlite { SqliteDatabaseBackend::SqliteDatabaseBackend(SqliteDatabase &database) diff --git a/src/libs/sqlite/sqliteglobal.h b/src/libs/sqlite/sqliteglobal.h index cb5208df5ff..af9d9ac36c0 100644 --- a/src/libs/sqlite/sqliteglobal.h +++ b/src/libs/sqlite/sqliteglobal.h @@ -37,6 +37,8 @@ # define SQLITE_EXPORT Q_DECL_IMPORT #endif +namespace Sqlite { + enum class ColumnType : char { Numeric, @@ -46,10 +48,11 @@ enum class ColumnType : char None }; -enum class IsPrimaryKey : char +enum class Contraint : char { - No, - Yes + NoConstraint, + PrimaryKey, + Unique }; enum class ColumnConstraint : char @@ -84,3 +87,5 @@ enum TextEncoding : char #endif }; + +} // namespace Sqlite diff --git a/src/libs/sqlite/sqlitereadstatement.h b/src/libs/sqlite/sqlitereadstatement.h index 55bd5c15fbb..d0c88602811 100644 --- a/src/libs/sqlite/sqlitereadstatement.h +++ b/src/libs/sqlite/sqlitereadstatement.h @@ -37,6 +37,8 @@ public: using SqliteStatement::next; using SqliteStatement::reset; using SqliteStatement::value; + using SqliteStatement::structValues; + using SqliteStatement::tupleValues; using SqliteStatement::text; using SqliteStatement::values; using SqliteStatement::columnCount; diff --git a/src/libs/sqlite/sqlitereadwritestatement.h b/src/libs/sqlite/sqlitereadwritestatement.h index 8f93ff85bed..d53614bcc02 100644 --- a/src/libs/sqlite/sqlitereadwritestatement.h +++ b/src/libs/sqlite/sqlitereadwritestatement.h @@ -48,6 +48,8 @@ public: using SqliteStatement::value; using SqliteStatement::text; using SqliteStatement::values; + using SqliteStatement::structValues; + using SqliteStatement::tupleValues; using SqliteStatement::columnCount; using SqliteStatement::columnNames; using SqliteStatement::toValue; diff --git a/src/libs/sqlite/sqlitestatement.cpp b/src/libs/sqlite/sqlitestatement.cpp index fee0130acc7..4c4a458a968 100644 --- a/src/libs/sqlite/sqlitestatement.cpp +++ b/src/libs/sqlite/sqlitestatement.cpp @@ -29,13 +29,11 @@ #include "sqlitedatabasebackend.h" #include "sqliteexception.h" -#include <QMutex> -#include <QtGlobal> -#include <QVariant> -#include <QWaitCondition> - #include "sqlite3.h" +#include <condition_variable> +#include <mutex> + #if defined(__GNUC__) # pragma GCC diagnostic ignored "-Wignored-qualifiers" #endif @@ -61,8 +59,8 @@ void SqliteStatement::deleteCompiledStatement(sqlite3_stmt *compiledStatement) sqlite3_finalize(compiledStatement); } -class UnlockNotification { - +class UnlockNotification +{ public: static void unlockNotifyCallBack(void **arguments, int argumentCount) { @@ -74,27 +72,24 @@ public: void wakeupWaitCondition() { - mutex.lock(); - fired = 1; - waitCondition.wakeAll(); - mutex.unlock(); + { + std::lock_guard<std::mutex> lock(m_mutex); + m_fired = 1; + } + m_waitCondition.notify_all(); } void wait() { - mutex.lock(); + std::unique_lock<std::mutex> lock(m_mutex); - if (!fired) { - waitCondition.wait(&mutex); - } - - mutex.unlock(); + m_waitCondition.wait(lock, [&] () { return m_fired; }); } private: - bool fired = false; - QWaitCondition waitCondition; - QMutex mutex; + bool m_fired = false; + std::condition_variable m_waitCondition; + std::mutex m_mutex; }; void SqliteStatement::waitForUnlockNotify() const @@ -143,6 +138,7 @@ void SqliteStatement::step() const void SqliteStatement::execute() const { next(); + reset(); } int SqliteStatement::columnCount() const @@ -168,7 +164,7 @@ void SqliteStatement::bind(int index, int value) throwException("SqliteStatement::bind: cant' bind 32 bit integer!"); } -void SqliteStatement::bind(int index, qint64 value) +void SqliteStatement::bind(int index, long long value) { int resultCode = sqlite3_bind_int64(m_compiledStatement.get(), index, value); if (resultCode != SQLITE_OK) @@ -198,7 +194,8 @@ void SqliteStatement::bind(Utils::SmallStringView name, Type value) } template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, int value); -template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, qint64 value); +template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long value); +template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long long value); template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, double value); template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text); @@ -363,21 +360,23 @@ SqliteDatabase &SqliteStatement::database() const return m_database; } -static Utils::SmallString textForColumn(sqlite3_stmt *sqlStatment, int column) +template <typename StringType> +static StringType textForColumn(sqlite3_stmt *sqlStatment, int column) { const char *text = reinterpret_cast<const char*>(sqlite3_column_text(sqlStatment, column)); std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column)); - return Utils::SmallString(text, size); + return StringType(text, size); } -static Utils::SmallString convertToTextForColumn(sqlite3_stmt *sqlStatment, int column) +template <typename StringType> +static StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column) { int dataType = sqlite3_column_type(sqlStatment, column); switch (dataType) { case SQLITE_INTEGER: case SQLITE_FLOAT: - case SQLITE3_TEXT: return textForColumn(sqlStatment, column); + case SQLITE3_TEXT: return textForColumn<StringType>(sqlStatment, column); case SQLITE_BLOB: case SQLITE_NULL: return {}; } @@ -394,7 +393,13 @@ int SqliteStatement::value<int>(int column) const } template<> -qint64 SqliteStatement::value<qint64>(int column) const +long SqliteStatement::value<long>(int column) const +{ + return long(value<long long>(column)); +} + +template<> +long long SqliteStatement::value<long long>(int column) const { checkIfIsReadyToFetchValues(); checkColumnIsValid(column); @@ -409,14 +414,17 @@ double SqliteStatement::value<double>(int column) const return sqlite3_column_double(m_compiledStatement.get(), column); } -template<> -Utils::SmallString SqliteStatement::value<Utils::SmallString>(int column) const +template<typename StringType> +StringType SqliteStatement::value(int column) const { checkIfIsReadyToFetchValues(); checkColumnIsValid(column); - return convertToTextForColumn(m_compiledStatement.get(), column); + return convertToTextForColumn<StringType>(m_compiledStatement.get(), column); } +template SQLITE_EXPORT Utils::SmallString SqliteStatement::value<Utils::SmallString>(int column) const; +template SQLITE_EXPORT Utils::PathString SqliteStatement::value<Utils::PathString>(int column) const; + Utils::SmallString SqliteStatement::text(int column) const { return value<Utils::SmallString>(column); @@ -434,45 +442,6 @@ ContainerType SqliteStatement::columnValues(const std::vector<int> &columnIndice return valueContainer; } -template <typename ContainerType> -ContainerType SqliteStatement::values(const std::vector<int> &columns, int size) const -{ - checkColumnsAreValid(columns); - - ContainerType resultValues; - resultValues.reserve(typename ContainerType::size_type(size)); - - reset(); - - while (next()) { - auto values = columnValues<ContainerType>(columns); - std::move(values.begin(), values.end(), std::back_inserter(resultValues)); - } - - return resultValues; -} - -template SQLITE_EXPORT Utils::SmallStringVector SqliteStatement::values<Utils::SmallStringVector>(const std::vector<int> &columnIndices, int size) const; - -template <typename ContainerType> -ContainerType SqliteStatement::values(int column) const -{ - typedef typename ContainerType::value_type ElementType; - ContainerType resultValues; - - reset(); - - while (next()) { - resultValues.push_back(value<ElementType>(column)); - } - - return resultValues; -} - -template SQLITE_EXPORT std::vector<qint64> SqliteStatement::values<std::vector<qint64>>(int column) const; -template SQLITE_EXPORT std::vector<double> SqliteStatement::values<std::vector<double>>(int column) const; -template SQLITE_EXPORT Utils::SmallStringVector SqliteStatement::values<Utils::SmallStringVector>(int column) const; - template <typename Type> Type SqliteStatement::toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database) { @@ -484,7 +453,7 @@ Type SqliteStatement::toValue(Utils::SmallStringView sqlStatement, SqliteDatabas } template SQLITE_EXPORT int SqliteStatement::toValue<int>(Utils::SmallStringView sqlStatement, SqliteDatabase &database); -template SQLITE_EXPORT qint64 SqliteStatement::toValue<qint64>(Utils::SmallStringView sqlStatement, SqliteDatabase &database); +template SQLITE_EXPORT long long SqliteStatement::toValue<long long>(Utils::SmallStringView sqlStatement, SqliteDatabase &database); template SQLITE_EXPORT double SqliteStatement::toValue<double>(Utils::SmallStringView sqlStatement, SqliteDatabase &database); template SQLITE_EXPORT Utils::SmallString SqliteStatement::toValue<Utils::SmallString>(Utils::SmallStringView sqlStatement, SqliteDatabase &database); diff --git a/src/libs/sqlite/sqlitestatement.h b/src/libs/sqlite/sqlitestatement.h index 5f74c267ef3..09c75c16d97 100644 --- a/src/libs/sqlite/sqlitestatement.h +++ b/src/libs/sqlite/sqlitestatement.h @@ -31,8 +31,12 @@ #include <utils/smallstringvector.h> -#include <type_traits> +#include <cstdint> #include <memory> +#include <type_traits> +#include <tuple> + +using std::int64_t; struct sqlite3_stmt; struct sqlite3; @@ -61,31 +65,45 @@ protected: Utils::SmallStringVector columnNames() const; void bind(int index, int value); - void bind(int index, qint64 value); + void bind(int index, long long value); void bind(int index, double value); void bind(int index, Utils::SmallStringView value); - template<typename ... Values> - void bindValues(Values ... values) + 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)); + } + + void bindValues() + { + } + + template<typename... Values> + void bindValues(Values... values) { bindValuesByIndex(1, values...); } - template<typename ... Values> - void write(Values ... values) + template<typename... Values> + void write(Values... values) { bindValuesByIndex(1, values...); execute(); } - template<typename ... Values> - void bindNameValues(Values ... values) + template<typename... Values> + void bindNameValues(Values... values) { bindValuesByName(values...); } - template<typename ... Values> - void writeNamed(Values ... values) + template<typename... Values> + void writeNamed(Values... values) { bindValuesByName(values...); execute(); @@ -99,11 +117,231 @@ protected: void setBindingColumnNames(const Utils::SmallStringVector &bindingColumnNames); const Utils::SmallStringVector &bindingColumnNames() const; - template <typename ContainerType> - ContainerType values(const std::vector<int> &columns, int size = 0) const; + template <typename... ResultType> + std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize) + { + using Container = std::vector<std::tuple<ResultType...>>; + Container resultValues; + resultValues.reserve(reserveSize); - template <typename ContainerType> - ContainerType values(int column = 0) const; + while (next()) + emplaceTupleValues<Container, ResultType...>(resultValues); + + reset(); + + return resultValues; + } + + template <typename... ResultType, + typename... QueryType> + std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize, const QueryType&... queryValues) + { + using Container = std::vector<std::tuple<ResultType...>>; + Container resultValues; + resultValues.reserve(reserveSize); + + bindValues(queryValues...); + + while (next()) + emplaceTupleValues<Container, ResultType...>(resultValues); + + reset(); + + return resultValues; + } + + template <typename... ResultType, + typename... ElementType> + std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize, + const std::vector<std::tuple<ElementType...>> &queryTuples) + { + using Container = std::vector<std::tuple<ResultType...>>; + Container resultValues; + resultValues.reserve(reserveSize); + + for (const auto &queryTuple : queryTuples) { + bindTupleValues(queryTuple); + + while (next()) + emplaceTupleValues<Container, ResultType...>(resultValues); + + reset(); + } + + return resultValues; + } + + template <typename... ResultType, + typename QueryElementType> + std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize, + const std::vector<QueryElementType> &queryValues) + { + using Container = std::vector<std::tuple<ResultType...>>; + Container resultValues; + resultValues.reserve(reserveSize); + + for (const QueryElementType &queryValue : queryValues) { + bindValues(queryValue); + + while (next()) + emplaceTupleValues<Container, ResultType...>(resultValues); + + reset(); + } + + return resultValues; + } + + template <typename ResultType, + typename... ResultEntryType> + std::vector<ResultType> structValues(std::size_t reserveSize) + { + using Container = std::vector<ResultType>; + Container resultValues; + resultValues.reserve(reserveSize); + + while (next()) + pushBackStructValues<Container, ResultEntryType...>(resultValues); + + reset(); + + return resultValues; + } + + template <typename ResultType, + typename... ResultEntryType, + typename... QueryType> + std::vector<ResultType> structValues(std::size_t reserveSize, const QueryType&... queryValues) + { + using Container = std::vector<ResultType>; + Container resultValues; + resultValues.reserve(reserveSize); + + bindValues(queryValues...); + + while (next()) + pushBackStructValues<Container, ResultEntryType...>(resultValues); + + reset(); + + return resultValues; + } + + template <typename ResultType, + typename... ResultEntryType, + typename QueryElementType> + std::vector<ResultType> structValues(std::size_t reserveSize, + const std::vector<QueryElementType> &queryValues) + { + using Container = std::vector<ResultType>; + Container resultValues; + resultValues.reserve(reserveSize); + + for (const QueryElementType &queryValue : queryValues) { + bindValues(queryValue); + + while (next()) + pushBackStructValues<Container, ResultEntryType...>(resultValues); + + reset(); + } + + return resultValues; + } + + template <typename ResultType, + typename... ResultEntryType, + typename... QueryElementType> + std::vector<ResultType> structValues(std::size_t reserveSize, + const std::vector<std::tuple<QueryElementType...>> &queryTuples) + { + using Container = std::vector<ResultType>; + Container resultValues; + resultValues.reserve(reserveSize); + + for (const auto &queryTuple : queryTuples) { + bindTupleValues(queryTuple); + + while (next()) + pushBackStructValues<Container, ResultEntryType...>(resultValues); + + reset(); + } + + return resultValues; + } + + template <typename ResultType, + typename... ElementType> + std::vector<ResultType> values(std::size_t reserveSize) + { + std::vector<ResultType> resultValues; + resultValues.reserve(reserveSize); + + while (next()) + resultValues.push_back(value<ResultType>(0)); + + reset(); + + return resultValues; + } + + template <typename ResultType, + typename... ElementType> + std::vector<ResultType> values(std::size_t reserveSize, + const std::vector<std::tuple<ElementType...>> &queryTuples) + { + std::vector<ResultType> resultValues; + resultValues.reserve(reserveSize); + + for (const auto &queryTuple : queryTuples) { + bindTupleValues(queryTuple); + + while (next()) + resultValues.push_back(value<ResultType>(0)); + + reset(); + } + + return resultValues; + } + + template <typename ResultType, + typename ElementType> + std::vector<ResultType> values(std::size_t reserveSize, + const std::vector<ElementType> &queryValues) + { + std::vector<ResultType> resultValues; + resultValues.reserve(reserveSize); + + for (const ElementType &queryValue : queryValues) { + bindValues(queryValue); + + while (next()) + resultValues.push_back(value<ResultType>(0)); + + reset(); + } + + return resultValues; + } + + template <typename ResultType, + typename... QueryType> + std::vector<ResultType> values(std::size_t reserveSize, const QueryType&... queryValues) + { + std::vector<ResultType> resultValues; + resultValues.reserve(reserveSize); + + bindValues(queryValues...); + + while (next()) + resultValues.push_back(value<ResultType>(0)); + + reset(); + + return resultValues; + } template <typename Type> static Type toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database); @@ -141,14 +379,45 @@ protected: SqliteDatabaseBackend &databaseBackend); private: + template <typename Container, + typename... ResultType, + int... Index> + void emplaceTupleValues(Container &container, std::integer_sequence<int, Index...>) + { + container.emplace_back(value<ResultType>(Index)...); + } + + template <typename Container, + typename... ResultType> + void emplaceTupleValues(Container &container) + { + emplaceTupleValues<Container, ResultType...>(container, std::make_integer_sequence<int, sizeof...(ResultType)>{}); + } + + template <typename Container, + typename... ResultEntryType, + int... Index> + void pushBackStructValues(Container &container, std::integer_sequence<int, Index...>) + { + using ResultType = typename Container::value_type; + container.push_back(ResultType{value<ResultEntryType>(Index)...}); + } + + template <typename Container, + typename... ResultEntryType> + void pushBackStructValues(Container &container) + { + pushBackStructValues<Container, ResultEntryType...>(container, std::make_integer_sequence<int, sizeof...(ResultEntryType)>{}); + } + template<typename Type> void bindValuesByIndex(int index, Type value) { bind(index, value); } - template<typename Type, typename ... Value> - void bindValuesByIndex(int index, Type value, Value ... values) + template<typename Type, typename... Value> + void bindValuesByIndex(int index, Type value, Value... values) { bind(index, value); bindValuesByIndex(index + 1, values...); @@ -160,13 +429,26 @@ private: bind(bindingIndexForName(name), value); } - template<typename Type, typename ... Values> - void bindValuesByName(Utils::SmallStringView name, Type value, Values ... values) + template<typename Type, typename... Values> + void bindValuesByName(Utils::SmallStringView name, Type value, Values... values) { bind(bindingIndexForName(name), value); bindValuesByName(values...); } + template <typename TupleType, std::size_t... Index> + void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<Index...>) + { + bindValues(std::get<Index>(tuple)...); + } + + template <typename TupleType, + typename Indices = std::make_index_sequence<std::tuple_size<TupleType>::value>> + void bindTupleValues(const TupleType &element) + { + bindTupleValuesElement(element, Indices()); + } + private: std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt*)> m_compiledStatement; Utils::SmallStringVector m_bindingColumnNames; @@ -176,4 +458,21 @@ private: mutable bool m_isReadyToFetchValues; }; +extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, int value); +extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long value); +extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long long value); +extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, double value); +extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text); + +extern template SQLITE_EXPORT int SqliteStatement::toValue<int>(Utils::SmallStringView sqlStatement, SqliteDatabase &database); +extern template SQLITE_EXPORT long long SqliteStatement::toValue<long long>(Utils::SmallStringView sqlStatement, SqliteDatabase &database); +extern template SQLITE_EXPORT double SqliteStatement::toValue<double>(Utils::SmallStringView sqlStatement, SqliteDatabase &database); +extern template SQLITE_EXPORT Utils::SmallString SqliteStatement::toValue<Utils::SmallString>(Utils::SmallStringView sqlStatement, SqliteDatabase &database); + +template <> SQLITE_EXPORT int SqliteStatement::value<int>(int column) const; +template <> SQLITE_EXPORT long SqliteStatement::value<long>(int column) const; +template <> SQLITE_EXPORT long long SqliteStatement::value<long long>(int column) const; +template <> SQLITE_EXPORT double SqliteStatement::value<double>(int column) const; +extern template SQLITE_EXPORT Utils::SmallString SqliteStatement::value<Utils::SmallString>(int column) const; +extern template SQLITE_EXPORT Utils::PathString SqliteStatement::value<Utils::PathString>(int column) const; } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitetable.cpp b/src/libs/sqlite/sqlitetable.cpp index dc987f44772..99b0e95938c 100644 --- a/src/libs/sqlite/sqlitetable.cpp +++ b/src/libs/sqlite/sqlitetable.cpp @@ -25,32 +25,8 @@ #include "sqlitetable.h" -#include "sqlitecolumn.h" -#include "sqlitedatabase.h" -#include "createtablesqlstatementbuilder.h" -#include "sqlitewritestatement.h" -#include "sqlitetransaction.h" - namespace Sqlite { -void SqliteTable::initialize() -{ - try { - CreateTableSqlStatementBuilder createTableSqlStatementBuilder; - - createTableSqlStatementBuilder.setTable(m_tableName.clone()); - createTableSqlStatementBuilder.setUseWithoutRowId(m_withoutRowId); - createTableSqlStatementBuilder.setColumns(m_sqliteColumns); - - SqliteImmediateTransaction transaction(m_sqliteDatabase); - m_sqliteDatabase.execute(createTableSqlStatementBuilder.sqlStatement()); - transaction.commit(); - - m_isReady = true; - } catch (const SqliteException &exception) { - exception.printWarning(); - } -} } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitetable.h b/src/libs/sqlite/sqlitetable.h index 62b6b41cb3f..d591f39a59f 100644 --- a/src/libs/sqlite/sqlitetable.h +++ b/src/libs/sqlite/sqlitetable.h @@ -25,8 +25,10 @@ #pragma once +#include "createtablesqlstatementbuilder.h" #include "sqliteglobal.h" #include "sqlitecolumn.h" +#include "sqliteexception.h" namespace Sqlite { @@ -35,11 +37,6 @@ class SqliteDatabase; class SqliteTable { public: - SqliteTable(SqliteDatabase &m_sqliteDatabase) - : m_sqliteDatabase(m_sqliteDatabase) - { - } - void setName(Utils::SmallString &&name) { m_tableName = std::move(name); @@ -60,11 +57,16 @@ public: return m_withoutRowId; } + void setUseIfNotExists(bool useIfNotExists) + { + m_useIfNotExists = useIfNotExists; + } + SqliteColumn &addColumn(Utils::SmallString &&name, ColumnType type = ColumnType::Numeric, - IsPrimaryKey isPrimaryKey = IsPrimaryKey::No) + Contraint constraint = Contraint::NoConstraint) { - m_sqliteColumns.emplace_back(std::move(name), type, isPrimaryKey); + m_sqliteColumns.emplace_back(std::move(name), type, constraint); return m_sqliteColumns.back(); } @@ -79,13 +81,31 @@ public: return m_isReady; } - void initialize(); + template <typename Database> + void initialize(Database &database) + { + try { + CreateTableSqlStatementBuilder builder; + + builder.setTableName(m_tableName.clone()); + builder.setUseWithoutRowId(m_withoutRowId); + builder.setUseIfNotExists(m_useIfNotExists); + builder.setColumns(m_sqliteColumns); + + database.execute(builder.sqlStatement()); + + m_isReady = true; + + } catch (const SqliteException &exception) { + exception.printWarning(); + } + } friend bool operator==(const SqliteTable &first, const SqliteTable &second) { return first.m_tableName == second.m_tableName - && &first.m_sqliteDatabase == &second.m_sqliteDatabase && first.m_withoutRowId == second.m_withoutRowId + && first.m_useIfNotExists == second.m_useIfNotExists && first.m_isReady == second.m_isReady && first.m_sqliteColumns == second.m_sqliteColumns; } @@ -93,8 +113,8 @@ public: private: Utils::SmallString m_tableName; SqliteColumns m_sqliteColumns; - SqliteDatabase &m_sqliteDatabase; bool m_withoutRowId = false; + bool m_useIfNotExists = false; bool m_isReady = false; }; diff --git a/src/libs/sqlite/sqlitetransaction.cpp b/src/libs/sqlite/sqlitetransaction.cpp index dd790ee5529..2ee17131c25 100644 --- a/src/libs/sqlite/sqlitetransaction.cpp +++ b/src/libs/sqlite/sqlitetransaction.cpp @@ -31,44 +31,4 @@ namespace Sqlite { -SqliteAbstractTransaction::~SqliteAbstractTransaction() -{ - if (!m_isAlreadyCommited) - m_databaseBackend.execute("ROLLBACK"); -} - -void SqliteAbstractTransaction::commit() -{ - m_databaseBackend.execute("COMMIT"); - m_isAlreadyCommited = true; -} - -SqliteAbstractTransaction::SqliteAbstractTransaction(SqliteDatabaseBackend &backend) - : m_databaseBackend(backend) -{ -} - -SqliteAbstractTransaction::SqliteAbstractTransaction(SqliteDatabase &database) - : SqliteAbstractTransaction(database.backend()) -{ -} - -SqliteTransaction::SqliteTransaction(SqliteDatabase &database) - : SqliteAbstractTransaction(database) -{ - m_databaseBackend.execute("BEGIN"); -} - -SqliteImmediateTransaction::SqliteImmediateTransaction(SqliteDatabase &database) - : SqliteAbstractTransaction(database) -{ - m_databaseBackend.execute("BEGIN IMMEDIATE"); -} - -SqliteExclusiveTransaction::SqliteExclusiveTransaction(SqliteDatabase &database) - : SqliteAbstractTransaction(database) -{ - m_databaseBackend.execute("BEGIN EXCLUSIVE"); -} - } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitetransaction.h b/src/libs/sqlite/sqlitetransaction.h index 994fbe2b1f5..373b33fd8a9 100644 --- a/src/libs/sqlite/sqlitetransaction.h +++ b/src/libs/sqlite/sqlitetransaction.h @@ -32,43 +32,66 @@ namespace Sqlite { class SqliteDatabaseBackend; class SqliteDatabase; -class SQLITE_EXPORT SqliteAbstractTransaction +template <typename Database> +class SqliteAbstractTransaction { public: - virtual ~SqliteAbstractTransaction(); - - void commit(); - -protected: - SqliteAbstractTransaction(SqliteDatabaseBackend &backend); - SqliteAbstractTransaction(SqliteDatabase &database); + virtual ~SqliteAbstractTransaction() + { + if (!m_isAlreadyCommited) + m_database.execute("ROLLBACK"); + } + + void commit() + { + m_database.execute("COMMIT"); + m_isAlreadyCommited = true; + } protected: - SqliteDatabaseBackend &m_databaseBackend; + SqliteAbstractTransaction(Database &database) + : m_database(database) + { + } private: + Database &m_database; bool m_isAlreadyCommited = false; }; - -class SQLITE_EXPORT SqliteTransaction final : public SqliteAbstractTransaction +template <typename Database> +class SqliteTransaction final : public SqliteAbstractTransaction<Database> { public: - SqliteTransaction(SqliteDatabase &database); + SqliteTransaction(Database &database) + : SqliteAbstractTransaction<Database>(database) + { + database.execute("BEGIN"); + } }; -class SQLITE_EXPORT SqliteImmediateTransaction final : public SqliteAbstractTransaction +template <typename Database> +class SqliteImmediateTransaction final : public SqliteAbstractTransaction<Database> { public: - SqliteImmediateTransaction(SqliteDatabase &database); + SqliteImmediateTransaction(Database &database) + : SqliteAbstractTransaction<Database>(database) + { + database.execute("BEGIN IMMEDIATE"); + } }; -class SQLITE_EXPORT SqliteExclusiveTransaction final : public SqliteAbstractTransaction +template <typename Database> +class SqliteExclusiveTransaction final : public SqliteAbstractTransaction<Database> { public: - SqliteExclusiveTransaction(SqliteDatabase &database); + SqliteExclusiveTransaction(Database &database) + : SqliteAbstractTransaction<Database>(database) + { + database.execute("BEGIN EXCLUSIVE"); + } }; diff --git a/src/libs/sqlite/sqlstatementbuilder.cpp b/src/libs/sqlite/sqlstatementbuilder.cpp index 4104d8c1f0c..cfa08a2b7b3 100644 --- a/src/libs/sqlite/sqlstatementbuilder.cpp +++ b/src/libs/sqlite/sqlstatementbuilder.cpp @@ -33,7 +33,7 @@ namespace Sqlite { -SqlStatementBuilder::SqlStatementBuilder(Utils::SmallString &&sqlTemplate) +SqlStatementBuilder::SqlStatementBuilder(Utils::SmallStringView sqlTemplate) : m_sqlTemplate(std::move(sqlTemplate)) { } diff --git a/src/libs/sqlite/sqlstatementbuilder.h b/src/libs/sqlite/sqlstatementbuilder.h index c24e0b9ed94..670455dc41a 100644 --- a/src/libs/sqlite/sqlstatementbuilder.h +++ b/src/libs/sqlite/sqlstatementbuilder.h @@ -38,7 +38,7 @@ class SQLITE_EXPORT SqlStatementBuilder { using BindingPair = std::pair<Utils::SmallString, Utils::SmallString>; public: - SqlStatementBuilder(Utils::SmallString &&m_sqlTemplate); + SqlStatementBuilder(Utils::SmallStringView m_sqlTemplate); void bindEmptyText(Utils::SmallString &&name); void bind(Utils::SmallString &&name, Utils::SmallString &&text); @@ -79,8 +79,8 @@ protected: Q_NORETURN static void throwException(const char *whatHasHappened, const char *errorMessage); private: - Utils::SmallString m_sqlTemplate; - mutable Utils::SmallString m_sqlStatement; + Utils::BasicSmallString<510> m_sqlTemplate; + mutable Utils::BasicSmallString<510> m_sqlStatement; mutable std::vector<BindingPair> m_bindings; }; |