Commit 52a911b9 authored by Marco Bubke's avatar Marco Bubke

Sqlite: Cleanup table and column handling

Using values instead of pointers makes the handling much easier. We can
remove ColumnDefinition too, and use SqliteColumn instead.

Change-Id: I224db9cc569c4dfb6e2746179b02096904bfbccb
Reviewed-by: Tim Jenssen's avatarTim Jenssen <tim.jenssen@qt.io>
parent a41183f6
/****************************************************************************
**
** 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 "columndefinition.h"
namespace Sqlite {
} // namespace Sqlite
/****************************************************************************
**
** 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.
**
****************************************************************************/
#pragma once
#include "sqliteglobal.h"
#include <utils/smallstring.h>
#include <vector>
namespace Sqlite {
class ColumnDefinition
{
public:
void setName(Utils::SmallString &&name)
{
m_name = std::move(name);
}
const Utils::SmallString &name() const
{
return m_name;
}
void setType(ColumnType type)
{
m_type = type;
}
ColumnType type() const
{
return m_type;
}
Utils::SmallString typeString() const
{
switch (m_type) {
case ColumnType::None: return {};
case ColumnType::Numeric: return "NUMERIC";
case ColumnType::Integer: return "INTEGER";
case ColumnType::Real: return "REAL";
case ColumnType::Text: return "TEXT";
}
Q_UNREACHABLE();
}
void setIsPrimaryKey(bool isPrimaryKey)
{
m_isPrimaryKey = isPrimaryKey;
}
bool isPrimaryKey() const
{
return m_isPrimaryKey;
}
private:
Utils::SmallString m_name;
ColumnType m_type;
bool m_isPrimaryKey = false;
};
using ColumnDefinitions = std::vector<ColumnDefinition>;
} // namespace Sqlite
......@@ -40,25 +40,20 @@ void CreateTableSqlStatementBuilder::setTable(Utils::SmallString &&tableName)
this->m_tableName = std::move(tableName);
}
void CreateTableSqlStatementBuilder::addColumnDefinition(Utils::SmallString &&columnName,
ColumnType columnType,
bool isPrimaryKey)
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallString &&columnName,
ColumnType columnType,
IsPrimaryKey isPrimaryKey)
{
m_sqlStatementBuilder.clear();
ColumnDefinition columnDefinition;
columnDefinition.setName(std::move(columnName));
columnDefinition.setType(columnType);
columnDefinition.setIsPrimaryKey(isPrimaryKey);
m_columnDefinitions.push_back(columnDefinition);
m_columns.emplace_back(std::move(columnName), columnType, isPrimaryKey);
}
void CreateTableSqlStatementBuilder::setColumnDefinitions(ColumnDefinitions &&columnDefinitions)
void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns)
{
m_sqlStatementBuilder.clear();
m_columnDefinitions = std::move(columnDefinitions);
m_columns = std::move(columns);
}
void CreateTableSqlStatementBuilder::setUseWithoutRowId(bool useWithoutRowId)
......@@ -69,7 +64,7 @@ void CreateTableSqlStatementBuilder::setUseWithoutRowId(bool useWithoutRowId)
void CreateTableSqlStatementBuilder::clear()
{
m_sqlStatementBuilder.clear();
m_columnDefinitions.clear();
m_columns.clear();
m_tableName.clear();
m_useWithoutRowId = false;
}
......@@ -77,7 +72,7 @@ void CreateTableSqlStatementBuilder::clear()
void CreateTableSqlStatementBuilder::clearColumns()
{
m_sqlStatementBuilder.clear();
m_columnDefinitions.clear();
m_columns.clear();
}
Utils::SmallStringView CreateTableSqlStatementBuilder::sqlStatement() const
......@@ -90,17 +85,17 @@ Utils::SmallStringView CreateTableSqlStatementBuilder::sqlStatement() const
bool CreateTableSqlStatementBuilder::isValid() const
{
return m_tableName.hasContent() && !m_columnDefinitions.empty();
return m_tableName.hasContent() && !m_columns.empty();
}
void CreateTableSqlStatementBuilder::bindColumnDefinitions() const
{
Utils::SmallStringVector columnDefinitionStrings;
for (const ColumnDefinition &columnDefinition : m_columnDefinitions) {
Utils::SmallString columnDefinitionString = {columnDefinition.name(), " ", columnDefinition.typeString()};
for (const SqliteColumn &columns : m_columns) {
Utils::SmallString columnDefinitionString = {columns.name(), " ", columns.typeString()};
if (columnDefinition.isPrimaryKey())
if (columns.isPrimaryKey())
columnDefinitionString.append(" PRIMARY KEY");
columnDefinitionStrings.push_back(columnDefinitionString);
......
......@@ -25,11 +25,9 @@
#pragma once
#include "columndefinition.h"
#include "sqlitecolumn.h"
#include "sqlstatementbuilder.h"
#include <vector>
namespace Sqlite {
class SQLITE_EXPORT CreateTableSqlStatementBuilder
......@@ -38,8 +36,10 @@ public:
CreateTableSqlStatementBuilder();
void setTable(Utils::SmallString &&tableName);
void addColumnDefinition(Utils::SmallString &&columnName, ColumnType columnType, bool isPrimaryKey = false);
void setColumnDefinitions(ColumnDefinitions &&columnDefinitions);
void addColumn(Utils::SmallString &&columnName,
ColumnType columnType,
IsPrimaryKey isPrimaryKey = IsPrimaryKey::No);
void setColumns(const SqliteColumns &columns);
void setUseWithoutRowId(bool useWithoutRowId);
void clear();
......@@ -56,7 +56,7 @@ protected:
private:
mutable SqlStatementBuilder m_sqlStatementBuilder;
Utils::SmallString m_tableName;
ColumnDefinitions m_columnDefinitions;
SqliteColumns m_columns;
bool m_useWithoutRowId;
};
......
......@@ -11,7 +11,6 @@ unix:!bsd: LIBS += -ldl
include(../3rdparty/sqlite/sqlite.pri)
SOURCES += \
$$PWD/columndefinition.cpp \
$$PWD/createtablesqlstatementbuilder.cpp \
$$PWD/sqlitedatabasebackend.cpp \
$$PWD/sqliteexception.cpp \
......@@ -29,7 +28,6 @@ SOURCES += \
$$PWD/sqlitetable.cpp \
$$PWD/sqlitecolumn.cpp
HEADERS += \
$$PWD/columndefinition.h \
$$PWD/createtablesqlstatementbuilder.h \
$$PWD/sqlitedatabasebackend.h \
$$PWD/sqliteexception.h \
......
......@@ -25,28 +25,30 @@
#pragma once
#include "columndefinition.h"
#include "utf8string.h"
#include "sqliteglobal.h"
#include <QObject>
#include <utils/smallstring.h>
namespace Sqlite {
class SqliteColumn
{
public:
SqliteColumn()
: m_type(ColumnType::Numeric),
m_isPrimaryKey(false)
{
SqliteColumn() = default;
}
SqliteColumn(Utils::SmallString &&name,
ColumnType type = ColumnType::Numeric,
IsPrimaryKey isPrimaryKey = IsPrimaryKey::No)
: m_name(std::move(name)),
m_type(type),
m_isPrimaryKey(isPrimaryKey)
{}
void clear()
{
m_name.clear();
m_type = ColumnType::Numeric;
m_isPrimaryKey = false;
m_isPrimaryKey = IsPrimaryKey::No;
}
void setName(Utils::SmallString &&newName)
......@@ -69,31 +71,42 @@ public:
return m_type;
}
void setIsPrimaryKey(bool isPrimaryKey)
void setIsPrimaryKey(IsPrimaryKey isPrimaryKey)
{
m_isPrimaryKey = isPrimaryKey;
}
bool isPrimaryKey() const
{
return m_isPrimaryKey;
return m_isPrimaryKey == IsPrimaryKey::Yes;
}
ColumnDefinition columnDefintion() const
Utils::SmallString typeString() const
{
ColumnDefinition columnDefinition;
columnDefinition.setName(m_name.clone());
columnDefinition.setType(m_type);
columnDefinition.setIsPrimaryKey(m_isPrimaryKey);
switch (m_type) {
case ColumnType::None: return {};
case ColumnType::Numeric: return "NUMERIC";
case ColumnType::Integer: return "INTEGER";
case ColumnType::Real: return "REAL";
case ColumnType::Text: return "TEXT";
}
Q_UNREACHABLE();
}
return columnDefinition;
friend bool operator==(const SqliteColumn &first, const SqliteColumn &second)
{
return first.m_name == second.m_name
&& first.m_type == second.m_type
&& first.m_isPrimaryKey == second.m_isPrimaryKey;
}
private:
Utils::SmallString m_name;
ColumnType m_type;
bool m_isPrimaryKey;
ColumnType m_type = ColumnType::Numeric;
IsPrimaryKey m_isPrimaryKey = IsPrimaryKey::No;
};
using SqliteColumns = std::vector<SqliteColumn>;
} // namespace Sqlite
......@@ -35,11 +35,6 @@ SqliteDatabase::SqliteDatabase()
{
}
SqliteDatabase::~SqliteDatabase()
{
qDeleteAll(m_sqliteTables);
}
void SqliteDatabase::open()
{
m_databaseBackend.open(m_databaseFilePath);
......@@ -65,13 +60,14 @@ bool SqliteDatabase::isOpen() const
return m_isOpen;
}
void SqliteDatabase::addTable(SqliteTable *newSqliteTable)
SqliteTable &SqliteDatabase::addTable()
{
newSqliteTable->setSqliteDatabase(this);
m_sqliteTables.push_back(newSqliteTable);
m_sqliteTables.emplace_back(*this);
return m_sqliteTables.back();
}
const std::vector<SqliteTable *> &SqliteDatabase::tables() const
const std::vector<SqliteTable> &SqliteDatabase::tables() const
{
return m_sqliteTables;
}
......@@ -113,8 +109,8 @@ void SqliteDatabase::execute(Utils::SmallStringView sqlStatement)
void SqliteDatabase::initializeTables()
{
for (SqliteTable *table: tables())
table->initialize();
for (SqliteTable &table : m_sqliteTables)
table.initialize();
}
SqliteDatabaseBackend &SqliteDatabase::backend()
......
......@@ -27,6 +27,7 @@
#include "sqlitedatabasebackend.h"
#include "sqliteglobal.h"
#include "sqlitetable.h"
#include <utils/smallstring.h>
......@@ -34,9 +35,6 @@
namespace Sqlite {
class SqliteTable;
class SqliteDatabaseBackend;
class SQLITE_EXPORT SqliteDatabase
{
friend class SqliteAbstractTransaction;
......@@ -45,7 +43,12 @@ class SQLITE_EXPORT SqliteDatabase
public:
SqliteDatabase();
~SqliteDatabase();
SqliteDatabase(const SqliteDatabase &) = delete;
bool operator=(const SqliteDatabase &) = delete;
SqliteDatabase(SqliteDatabase &&) = delete;
bool operator=(SqliteDatabase &&) = delete;
void open();
void open(Utils::PathString &&databaseFilePath);
......@@ -53,8 +56,8 @@ public:
bool isOpen() const;
void addTable(SqliteTable *newSqliteTable);
const std::vector<SqliteTable *> &tables() const;
SqliteTable &addTable();
const std::vector<SqliteTable> &tables() const;
void setDatabaseFilePath(Utils::PathString &&databaseFilePath);
const Utils::PathString &databaseFilePath() const;
......@@ -75,7 +78,7 @@ private:
private:
SqliteDatabaseBackend m_databaseBackend;
std::vector<SqliteTable*> m_sqliteTables;
std::vector<SqliteTable> m_sqliteTables;
Utils::PathString m_databaseFilePath;
JournalMode m_journalMode;
bool m_isOpen = false;
......
......@@ -41,8 +41,11 @@ public:
SqliteDatabaseBackend(SqliteDatabase &database);
~SqliteDatabaseBackend();
SqliteDatabaseBackend(const SqliteDatabase &database) = delete;
SqliteDatabase &operator=(const SqliteDatabase &database) = delete;
SqliteDatabaseBackend(const SqliteDatabase &) = delete;
SqliteDatabase &operator=(const SqliteDatabase &) = delete;
SqliteDatabaseBackend(SqliteDatabase &&) = delete;
SqliteDatabase &operator=(SqliteDatabase &&) = delete;
void setMmapSize(qint64 defaultSize, qint64 maximumSize);
void activateMultiThreading();
......
......@@ -37,7 +37,8 @@
# define SQLITE_EXPORT Q_DECL_IMPORT
#endif
enum class ColumnType {
enum class ColumnType : char
{
Numeric,
Integer,
Real,
......@@ -45,11 +46,19 @@ enum class ColumnType {
None
};
enum class ColumnConstraint {
enum class IsPrimaryKey : char
{
No,
Yes
};
enum class ColumnConstraint : char
{
PrimaryKey
};
enum class JournalMode {
enum class JournalMode : char
{
Delete,
Truncate,
Persist,
......@@ -57,7 +66,8 @@ enum class JournalMode {
Wal
};
enum TextEncoding {
enum TextEncoding : char
{
Utf8,
Utf16le,
Utf16be,
......
......@@ -33,52 +33,6 @@
namespace Sqlite {
SqliteTable::SqliteTable()
: m_withoutRowId(false)
{
}
SqliteTable::~SqliteTable()
{
qDeleteAll(m_sqliteColumns);
}
void SqliteTable::setName(Utils::SmallString &&name)
{
m_tableName = std::move(name);
}
Utils::SmallStringView SqliteTable::name() const
{
return m_tableName;
}
void SqliteTable::setUseWithoutRowId(bool useWithoutWorId)
{
m_withoutRowId = useWithoutWorId;
}
bool SqliteTable::useWithoutRowId() const
{
return m_withoutRowId;
}
void SqliteTable::addColumn(SqliteColumn *newColumn)
{
m_sqliteColumns.push_back(newColumn);
}
const std::vector<SqliteColumn *> &SqliteTable::columns() const
{
return m_sqliteColumns;
}
void SqliteTable::setSqliteDatabase(SqliteDatabase *database)
{
m_sqliteDatabase = database;
}
void SqliteTable::initialize()
{
try {
......@@ -86,10 +40,10 @@ void SqliteTable::initialize()
createTableSqlStatementBuilder.setTable(m_tableName.clone());
createTableSqlStatementBuilder.setUseWithoutRowId(m_withoutRowId);
createTableSqlStatementBuilder.setColumnDefinitions(createColumnDefintions());
createTableSqlStatementBuilder.setColumns(m_sqliteColumns);
SqliteImmediateTransaction transaction(*m_sqliteDatabase);
m_sqliteDatabase->execute(createTableSqlStatementBuilder.sqlStatement());
SqliteImmediateTransaction transaction(m_sqliteDatabase);
m_sqliteDatabase.execute(createTableSqlStatementBuilder.sqlStatement());
transaction.commit();
m_isReady = true;
......@@ -99,19 +53,4 @@ void SqliteTable::initialize()
}
}
bool SqliteTable::isReady() const
{
return m_isReady;
}
ColumnDefinitions SqliteTable::createColumnDefintions() const
{
ColumnDefinitions columnDefintions;
for (SqliteColumn *sqliteColumn : m_sqliteColumns)
columnDefintions.push_back(sqliteColumn->columnDefintion());
return columnDefintions;
}
} // namespace Sqlite
......@@ -26,47 +26,75 @@
#pragma once
#include "sqliteglobal.h"
#include "columndefinition.h"
#include "utf8string.h"
#include <QObject>
#include <QVector>
#include "sqlitecolumn.h"
namespace Sqlite {
class SqliteColumn;
class SqliteDatabase;
class SQLITE_EXPORT SqliteTable
class SqliteTable
{
public:
SqliteTable();
~SqliteTable();
void setName(Utils::SmallString &&name);
Utils::SmallStringView name() const;
void setUseWithoutRowId(bool useWithoutWorId);
bool useWithoutRowId() const;
void addColumn(SqliteColumn *newColumn);
const std::vector<SqliteColumn *> &columns() const;
void setSqliteDatabase(SqliteDatabase *database);
SqliteTable(SqliteDatabase &m_sqliteDatabase)
: m_sqliteDatabase(m_sqliteDatabase)
{
}
void setName(Utils::SmallString &&name)
{
m_tableName = std::move(name);
}
Utils::SmallStringView name() const
{
return m_tableName;
}
void setUseWithoutRowId(bool useWithoutWorId)
{
m_withoutRowId = useWithoutWorId;
}
bool useWithoutRowId() const
{
return m_withoutRowId;
}
SqliteColumn &addColumn(Utils::SmallString &&name,
ColumnType type = ColumnType::Numeric,
IsPrimaryKey isPrimaryKey = IsPrimaryKey::No)
{
m_sqliteColumns.emplace_back(std::move(name), type, isPrimaryKey);
return m_sqliteColumns.back();
}
const SqliteColumns &columns() const
{
return m_sqliteColumns;
}
bool isReady() const
{
return m_isReady;
}
void initialize();
bool isReady() const;
private:
ColumnDefinitions createColumnDefintions() const;
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_isReady == second.m_isReady
&& first.m_sqliteColumns == second.m_sqliteColumns;
}
private:
std::vector<SqliteColumn*> m_sqliteColumns;
Utils::SmallString m_tableName;
SqliteDatabase *m_sqliteDatabase;
bool m_withoutRowId;
SqliteColumns m_sqliteColumns;
SqliteDatabase &m_sqliteDatabase;
bool m_withoutRowId = false;
bool m_isReady = false;
};
......
......@@ -30,18 +30,17 @@
namespace {
using Sqlite::ColumnDefinition;
using Sqlite::ColumnDefinitions;
using Sqlite::SqliteColumn;
using Sqlite::SqliteColumns;
using Sqlite::SqlStatementBuilderException;
class CreateTableSqlStatementBuilder : public ::testing::Test
{
protected:
void bindValues();
static ColumnDefinitions createColumnDefintions();
static ColumnDefinition createColumnDefintion(Utils::SmallString name,
ColumnType type,
bool isPrimaryKey = false);
static SqliteColumns createColumns();
protected:
Sqlite::CreateTableSqlStatementBuilder builder;
};
......@@ -88,7 +87,7 @@ TEST_F(CreateTableSqlStatementBuilder, AddColumnToExistingColumns)
{
bindValues();
builder.addColumnDefinition("number2", ColumnType::Real);
builder.addColumn("number2", ColumnType::Real);
ASSERT_THAT(builder.sqlStatement(),
"CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC, number2 REAL)");}
......@@ -118,8 +117,8 @@ TEST_F(CreateTableSqlStatementBuilder, ClearColumnsAndAddColumnNewColumns)
bindValues();
builder.clearColumns();
builder.addColumnDefinition("name3", ColumnType::Text);
builder.addColumnDefinition("number3", ColumnType::Real);
builder.addColumn("name3", ColumnType::Text);
builder.addColumn("number3", ColumnType::Real);
ASSERT_THAT(builder.sqlStatement(),
"CREATE TABLE IF NOT EXISTS test(name3 TEXT, number3 REAL)");
......@@ -140,7 +139,7 @@ TEST_F(CreateTableSqlStatementBuilder, SetColumnDefinitions)
builder.clear();
builder.setTable("test");