Some more optimisations in SqliteTableModel

This improves the performance of a couple of often called functions in
SqliteTableModel some more.
This commit is contained in:
Martin Kleusberg
2019-10-05 17:45:33 +02:00
parent 6f7fb74809
commit fad8a847ae
5 changed files with 47 additions and 55 deletions

View File

@@ -213,7 +213,7 @@ void AddRecordDialog::populateFields()
tbitem->setText(kName, QString::fromStdString(f.name()));
tbitem->setText(kType, QString::fromStdString(f.type()));
tbitem->setData(kType, Qt::UserRole, QString::fromStdString(f.affinity()));
tbitem->setData(kType, Qt::UserRole, f.affinity());
// NOT NULL fields are indicated in bold.
if (f.notnull()) {
@@ -303,7 +303,7 @@ void AddRecordDialog::updateSqlText()
fields << sqlb::escapeIdentifier(item->text(kName));
value.toDouble(&isNumeric);
// If it has a numeric format and has no text affinity, do not quote it.
if (isNumeric && item->data(kType, Qt::UserRole).toString() != "TEXT")
if (isNumeric && item->data(kType, Qt::UserRole).toInt() != sqlb::Field::TextAffinity)
vals << value.toString();
else
vals << QString("'%1'").arg(value.toString().replace("'", "''"));

View File

@@ -323,17 +323,17 @@ bool Field::isBlob() const
return false;
}
std::string Field::affinity() const
Field::Affinity Field::affinity() const
{
if (isInteger()) return "INTEGER";
if (isInteger()) return IntegerAffinity;
if (isText()) return "TEXT";
if (isText()) return TextAffinity;
if (isBlob()) return "BLOB";
if (isBlob()) return BlobAffinity;
if (isReal()) return "REAL";
if (isReal() || isNumeric()) return FloatAffinity;
return "NUMERIC";
return BlobAffinity;
}
Table::Table(const Table& table)

View File

@@ -296,8 +296,16 @@ public:
bool isReal() const;
bool isNumeric() const;
// Type affinity of the column according to SQLite3 rules
std::string affinity() const;
// Type affinity of the column according to SQLite3 rules.
// The Affinity enum values match the SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_BLOB, and SQLITE_TEXT constants
enum Affinity
{
IntegerAffinity = 1,
FloatAffinity = 2,
TextAffinity = 3,
BlobAffinity = 4,
};
Affinity affinity() const;
const std::string& name() const { return m_name; }
const std::string& type() const { return m_type; }

View File

@@ -128,40 +128,24 @@ void SqliteTableModel::setQuery(const sqlb::Query& query)
m_vDataTypes.emplace_back(SQLITE_INTEGER);
// Get the data types of all other columns as well as the column names
bool allOk = false;
if(m_db.getObjectByName(query.table()) && m_db.getObjectByName(query.table())->type() == sqlb::Object::Types::Table)
sqlb::TablePtr t = m_db.getObjectByName<sqlb::Table>(query.table());
if(t && t->fields.size()) // It is a table and parsing was OK
{
sqlb::TablePtr t = m_db.getObjectByName<sqlb::Table>(query.table());
if(t && t->fields.size()) // parsing was OK
sqlb::StringVector rowids = t->rowidColumns();
m_query.setRowIdColumns(rowids);
m_headers.push_back(sqlb::joinStringVector(rowids, ","));
// Store field names and affinity data types
for(const sqlb::Field& fld : t->fields)
{
sqlb::StringVector rowids = t->rowidColumns();
m_query.setRowIdColumns(rowids);
m_headers.push_back(sqlb::joinStringVector(rowids, ","));
for(const auto& n : t->fieldNames())
m_headers.push_back(n);
// parse columns types
static QStringList dataTypes = QStringList()
<< "INTEGER"
<< "REAL"
<< "TEXT"
<< "BLOB";
for(const sqlb::Field& fld : t->fields)
{
QString name = QString::fromStdString(fld.type()).toUpper();
int colType = dataTypes.indexOf(name);
colType = (colType == -1) ? SQLITE_TEXT : colType + 1;
m_vDataTypes.push_back(colType);
}
allOk = true;
m_headers.push_back(fld.name());
m_vDataTypes.push_back(fld.affinity());
}
}
} else {
// If for one reason or another (either it's a view or we couldn't parse the table statement) we couldn't get the field
// information we retrieve it from SQLite using an extra query.
// NOTE: It would be nice to eventually get rid of this piece here. As soon as the grammar parser is good enough...
// If for one reason or another (either it's a view or we couldn't parse the table statement) we couldn't get the field
// information we retrieve it from SQLite using an extra query.
// NOTE: It would be nice to eventually get rid of this piece here. As soon as the grammar parser is good enough...
if(!allOk)
{
QString sColumnQuery = QString::fromUtf8("SELECT * FROM %1;").arg(QString::fromStdString(query.table().toString()));
if(m_query.rowIdColumns().empty())
m_query.setRowIdColumn("_rowid_");
@@ -266,15 +250,15 @@ QVariant SqliteTableModel::headerData(int section, Qt::Orientation orientation,
return plainHeader + sortIndicator;
}
}
return QString("%1").arg(section + 1);
return QString::number(section + 1);
}
else
return QString("%1").arg(section + 1);
return QString::number(section + 1);
}
QVariant SqliteTableModel::getMatchingCondFormat(size_t column, const QString& value, int role) const
{
if (m_mCondFormats.find(column) == m_mCondFormats.end())
if (!m_mCondFormats.count(column))
return QVariant();
bool isNumber;
@@ -330,7 +314,7 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
if(data.isNull())
{
return m_nullText;
} else if(nosync_isBinary(index)) {
} else if(isBinary(data)) {
return m_blobText;
} else {
if (data.length() > m_symbolLimit) {
@@ -346,7 +330,7 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
return decode(data);
} else if(role == Qt::FontRole) {
QFont font;
if(!row_available || data.isNull() || nosync_isBinary(index))
if(!row_available || data.isNull() || isBinary(data))
font.setItalic(true);
else {
// Unlock before querying from DB
@@ -361,9 +345,9 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
return QColor(100, 100, 100);
if(data.isNull())
return m_nullFgColour;
else if (nosync_isBinary(index))
else if (isBinary(data))
return m_binFgColour;
else if (m_mCondFormats.find(column) != m_mCondFormats.end()) {
else if (m_mCondFormats.count(column)) {
// Unlock before querying from DB
lock.unlock();
QVariant condFormatColor = getMatchingCondFormat(column, data, role);
@@ -377,9 +361,9 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
return QColor(255, 200, 200);
if(data.isNull())
return m_nullBgColour;
else if (nosync_isBinary(index))
else if (isBinary(data))
return m_binBgColour;
else if (m_mCondFormats.find(column) != m_mCondFormats.end()) {
else if (m_mCondFormats.count(column)) {
// Unlock before querying from DB
lock.unlock();
QVariant condFormatColor = getMatchingCondFormat(column, data, role);
@@ -883,18 +867,18 @@ void SqliteTableModel::clearCache()
bool SqliteTableModel::isBinary(const QModelIndex& index) const
{
QMutexLocker lock(&m_mutexDataCache);
return nosync_isBinary(index);
}
bool SqliteTableModel::nosync_isBinary(const QModelIndex& index) const
{
const size_t row = static_cast<size_t>(index.row());
if(!m_cache.count(row))
return false;
const auto & cached_row = m_cache.at(row);
return isBinary(cached_row.at(static_cast<size_t>(index.column())));
}
return !isTextOnly(cached_row.at(static_cast<size_t>(index.column())), m_encoding, true);
bool SqliteTableModel::isBinary(const QByteArray& data) const
{
return !isTextOnly(data, m_encoding, true);
}
QByteArray SqliteTableModel::encode(const QByteArray& str) const

View File

@@ -194,7 +194,7 @@ private:
Row makeDefaultCacheEntry () const;
bool nosync_isBinary(const QModelIndex& index) const;
bool isBinary(const QByteArray& index) const;
QString m_sQuery;
std::vector<int> m_vDataTypes;