Skip to content

Commit a6d48f1

Browse files
committed
Simplify interface and implementation of SqliteTableModel
This simplifies the usage and the implementation of the SqliteTableModel a bit by making the two operating modes it supports (manual query and interactive query) more obvious in its public interface as well as simplifying the control flow in the private implementation.
1 parent e54664d commit a6d48f1

File tree

5 files changed

+39
-73
lines changed

5 files changed

+39
-73
lines changed

src/RowCache.h

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,6 @@ class RowCache
6161
/// to remove already-loaded rows from both ends.
6262
void smallestNonAvailableRange (size_t & row_begin, size_t & row_end) const;
6363

64-
/// \returns whether this cache object is marked as initialised
65-
bool initialised() const
66-
{
67-
return is_initialised;
68-
}
69-
70-
/// mark the cache object as initialized. This is reset by the clear() function
71-
void setInitialised()
72-
{
73-
is_initialised = true;
74-
}
75-
7664
private:
7765
/// a single segment containing contiguous entries
7866
struct Segment
@@ -89,9 +77,6 @@ class RowCache
8977
using Segments = std::vector<Segment>;
9078
Segments segments;
9179

92-
// Set to true when the cache is first initialised no matter whether it contains any data or represents an empty table
93-
bool is_initialised;
94-
9580
// ------------------------------------------------------------------------------
9681

9782
/// \returns first segment that definitely cannot contain 'pos',
@@ -127,7 +112,6 @@ class RowCache
127112

128113
template <typename T>
129114
RowCache<T>::RowCache ()
130-
: is_initialised(false)
131115
{
132116
}
133117

@@ -250,7 +234,6 @@ void RowCache<T>::erase (size_t pos)
250234
template <typename T>
251235
void RowCache<T>::clear ()
252236
{
253-
is_initialised = false;
254237
segments.clear();
255238
}
256239

src/RowLoader.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ RowLoader::RowLoader (std::function<std::shared_ptr<sqlite3>(void)> db_getter_,
2727
, cache_mutex(cache_mutex_), cache_data(cache_data_)
2828
, query()
2929
, countQuery()
30+
, first_chunk_loaded(false)
3031
, num_tasks(0)
3132
, pDb(nullptr)
3233
, stop_requested(false)
@@ -39,6 +40,7 @@ void RowLoader::setQuery (const QString& new_query, const QString& newCountQuery
3940
{
4041
std::lock_guard<std::mutex> lk(m);
4142
query = new_query;
43+
first_chunk_loaded = false;
4244
if (newCountQuery.isEmpty())
4345
// If it is a normal query - hopefully starting with SELECT - just do a COUNT on it and return the results
4446
countQuery = QString("SELECT COUNT(*) FROM (%1);").arg(rtrimChar(query, ';'));
@@ -255,9 +257,9 @@ void RowLoader::process (Task & t)
255257
// - this is the first batch of data we load for this query
256258
// - we got exactly the number of rows back we queried (which indicates there might be more rows)
257259
// If there is no need to query the row count this means the number of rows we just got is the total row count.
258-
if(!cache_data.initialised())
260+
if(!first_chunk_loaded)
259261
{
260-
cache_data.setInitialised();
262+
first_chunk_loaded = true;
261263
if(row == t.row_end)
262264
triggerRowCountDetermination(t.token);
263265
else

src/RowLoader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ class RowLoader : public QThread
8181

8282
mutable std::future<void> row_counter;
8383

84+
bool first_chunk_loaded;
85+
8486
size_t num_tasks;
8587
std::shared_ptr<sqlite3> pDb; //< exclusive access while held...
8688

src/sqlitetablemodel.cpp

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,7 @@ void SqliteTableModel::reset()
107107
{
108108
beginResetModel();
109109

110-
// We first clear the cache here in order to unset the cache initialised flag,
111-
// then call the clearCache function to deal with the clean up
112-
// TODO This whole resetting and clearing should be refactored
113-
m_cache.clear();
114110
clearCache();
115-
116111
m_sQuery.clear();
117112
m_query.clear();
118113
m_table_of_query.reset();
@@ -133,16 +128,14 @@ void SqliteTableModel::setQuery(const sqlb::Query& query)
133128
m_query = query;
134129
m_table_of_query = m_db.getObjectByName<sqlb::Table>(query.table());
135130

136-
// The first column is the rowid column and therefore is always of type integer
137-
m_vDataTypes.emplace_back(SQLITE_INTEGER);
138-
139131
// Get the data types of all other columns as well as the column names
140132
// Set the row id columns
141133
if(m_table_of_query && m_table_of_query->fields.size()) // It is a table and parsing was OK
142134
{
143135
sqlb::StringVector rowids = m_table_of_query->rowidColumns();
144136
m_query.setRowIdColumns(rowids);
145137

138+
m_vDataTypes.emplace_back(SQLITE_INTEGER); // TODO This is not necessarily true for tables without ROWID or with multiple PKs
146139
m_headers.push_back(sqlb::joinStringVector(rowids, ","));
147140

148141
// Store field names and affinity data types
@@ -154,44 +147,31 @@ void SqliteTableModel::setQuery(const sqlb::Query& query)
154147
} else {
155148
// 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
156149
// information we retrieve it from SQLite using an extra query.
157-
// NOTE: It would be nice to eventually get rid of this piece here. As soon as the grammar parser is good enough...
158150

159-
std::string sColumnQuery = "SELECT * FROM " + query.table().toString() + ";";
160151
if(m_query.rowIdColumns().empty())
161152
m_query.setRowIdColumn("_rowid_");
162-
m_headers.emplace_back("_rowid_");
163-
auto columns = getColumns(nullptr, sColumnQuery, m_vDataTypes);
164-
m_headers.insert(m_headers.end(), columns.begin(), columns.end());
153+
154+
getColumnNames("SELECT _rowid_,* FROM " + query.table().toString());
165155
}
166156

167157
// Tell the query object about the column names
168158
m_query.setColumNames(m_headers);
169159

170160
// Apply new query and update view
171-
buildQuery();
161+
updateAndRunQuery();
172162
}
173163

174-
void SqliteTableModel::setQuery(const QString& sQuery, const QString& sCountQuery, bool clearHeaders)
164+
void SqliteTableModel::setQuery(const QString& sQuery)
175165
{
176-
// clear
177-
if(clearHeaders)
178-
reset();
179-
else
180-
clearCache();
181-
182-
if(!m_db.isOpen())
183-
return;
166+
// Reset
167+
reset();
184168

185169
m_sQuery = sQuery.trimmed();
186170
removeCommentsFromQuery(m_sQuery);
187171

188-
worker->setQuery(m_sQuery, sCountQuery);
172+
getColumnNames(sQuery.toStdString());
189173

190-
if(clearHeaders)
191-
{
192-
auto columns = getColumns(worker->getDb(), sQuery.toStdString(), m_vDataTypes);
193-
m_headers.insert(m_headers.end(), columns.begin(), columns.end());
194-
}
174+
worker->setQuery(m_sQuery, QString());
195175

196176
// now fetch the first entries
197177
triggerCacheLoad(static_cast<int>(m_chunkSize / 2) - 1);
@@ -606,7 +586,7 @@ void SqliteTableModel::sort(const std::vector<sqlb::SortedColumn>& columns)
606586

607587
// Set the new query (but only if a table has already been set
608588
if(!m_query.table().isEmpty())
609-
buildQuery();
589+
updateAndRunQuery();
610590
}
611591

612592
SqliteTableModel::Row SqliteTableModel::makeDefaultCacheEntry () const
@@ -728,9 +708,19 @@ QModelIndex SqliteTableModel::dittoRecord(int old_row)
728708
return index(new_row, static_cast<int>(firstEditedColumn));
729709
}
730710

731-
void SqliteTableModel::buildQuery()
711+
void SqliteTableModel::updateAndRunQuery()
732712
{
733-
setQuery(QString::fromStdString(m_query.buildQuery(true)), QString::fromStdString(m_query.buildCountQuery()), false);
713+
clearCache();
714+
715+
// Update the query
716+
m_sQuery = QString::fromStdString(m_query.buildQuery(true));
717+
QString sCountQuery = QString::fromStdString(m_query.buildCountQuery());
718+
worker->setQuery(m_sQuery, sCountQuery);
719+
720+
// now fetch the first entries
721+
triggerCacheLoad(static_cast<int>(m_chunkSize / 2) - 1);
722+
723+
emit layoutChanged();
734724
}
735725

736726
void SqliteTableModel::removeCommentsFromQuery(QString& query)
@@ -797,28 +787,24 @@ void SqliteTableModel::removeCommentsFromQuery(QString& query)
797787
}
798788
}
799789

800-
std::vector<std::string> SqliteTableModel::getColumns(std::shared_ptr<sqlite3> pDb, const std::string& sQuery, std::vector<int>& fieldsTypes) const
790+
void SqliteTableModel::getColumnNames(const std::string& sQuery)
801791
{
802-
if(!pDb)
803-
pDb = m_db.get(tr("retrieving list of columns"));
792+
auto pDb = m_db.get(tr("retrieving list of columns"));
804793

805794
sqlite3_stmt* stmt;
806-
std::vector<std::string> listColumns;
807795
if(sqlite3_prepare_v2(pDb.get(), sQuery.c_str(), static_cast<int>(sQuery.size()), &stmt, nullptr) == SQLITE_OK)
808796
{
809797
int columns = sqlite3_column_count(stmt);
810798
for(int i = 0; i < columns; ++i)
811799
{
812-
listColumns.push_back(sqlite3_column_name(stmt, i));
813-
fieldsTypes.push_back(sqlite3_column_type(stmt, i));
800+
m_headers.push_back(sqlite3_column_name(stmt, i));
801+
m_vDataTypes.push_back(sqlite3_column_type(stmt, i));
814802
}
815803
}
816804
sqlite3_finalize(stmt);
817-
818-
return listColumns;
819805
}
820806

821-
void addCondFormatToMap(std::map<size_t, std::vector<CondFormat>>& mCondFormats, size_t column, const CondFormat& condFormat)
807+
static void addCondFormatToMap(std::map<size_t, std::vector<CondFormat>>& mCondFormats, size_t column, const CondFormat& condFormat)
822808
{
823809
// If the condition is already present in the vector, update that entry and respect the order, since two entries with the same
824810
// condition do not make sense.
@@ -864,7 +850,7 @@ void SqliteTableModel::updateFilter(size_t column, const QString& value)
864850
m_query.where()[column] = whereClause;
865851

866852
// Build the new query
867-
buildQuery();
853+
updateAndRunQuery();
868854
}
869855

870856
void SqliteTableModel::updateGlobalFilter(const std::vector<QString>& values)
@@ -875,7 +861,7 @@ void SqliteTableModel::updateGlobalFilter(const std::vector<QString>& values)
875861
m_query.setGlobalWhere(filters);
876862

877863
// Build the new query
878-
buildQuery();
864+
updateAndRunQuery();
879865
}
880866

881867
void SqliteTableModel::clearCache()
@@ -893,13 +879,7 @@ void SqliteTableModel::clearCache()
893879
endRemoveRows();
894880
}
895881

896-
// We want to clear the cache contents here but keep the initialised flag.
897-
// This is a bit hacky but the easiest way to achieve this. In the long term
898-
// we might want to change this whole concept of clearing and resetting.
899-
const bool cache_initialised = m_cache.initialised();
900882
m_cache.clear();
901-
if(cache_initialised)
902-
m_cache.setInitialised();
903883

904884
m_currentRowCount = 0;
905885
m_rowCountAvailable = RowCount::Unknown;
@@ -971,7 +951,7 @@ void SqliteTableModel::setPseudoPk(std::vector<std::string> pseudoPk)
971951
if(m_headers.size())
972952
m_headers[0] = sqlb::joinStringVector(pseudoPk, ",");
973953

974-
buildQuery();
954+
updateAndRunQuery();
975955
}
976956

977957
bool SqliteTableModel::hasPseudoPk() const

src/sqlitetablemodel.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class SqliteTableModel : public QAbstractTableModel
8080
QModelIndex dittoRecord(int old_row);
8181

8282
/// configure for browsing results of specified query
83-
void setQuery(const QString& sQuery, const QString& sCountQuery = QString(), bool clearHeaders = true);
83+
void setQuery(const QString& sQuery);
8484

8585
std::string query() const { return m_sQuery.toStdString(); }
8686
std::string customQuery(bool withRowid) const { return m_query.buildQuery(withRowid); }
@@ -165,10 +165,9 @@ public slots:
165165
void handleFinishedFetch(int life_id, unsigned int fetched_row_begin, unsigned int fetched_row_end);
166166
void handleRowCountComplete(int life_id, int num_rows);
167167

168-
void buildQuery();
168+
void updateAndRunQuery();
169169

170-
/// \param pDb connection to query; if null, obtains it from 'm_db'.
171-
std::vector<std::string> getColumns(std::shared_ptr<sqlite3> pDb, const std::string& sQuery, std::vector<int>& fieldsTypes) const;
170+
void getColumnNames(const std::string& sQuery);
172171

173172
QByteArray encode(const QByteArray& str) const;
174173
QByteArray decode(const QByteArray& str) const;

0 commit comments

Comments
 (0)