diff --git a/src/RowLoader.cpp b/src/RowLoader.cpp index 6ce09cf2..66536491 100644 --- a/src/RowLoader.cpp +++ b/src/RowLoader.cpp @@ -26,6 +26,7 @@ RowLoader::RowLoader ( : db_getter(db_getter_), statement_logger(statement_logger_), headers(headers_) , cache_mutex(cache_mutex_), cache_data(cache_data_) , query() + , countQuery() , num_tasks(0) , pDb(nullptr) , stop_requested(false) @@ -34,10 +35,15 @@ RowLoader::RowLoader ( { } -void RowLoader::setQuery (QString new_query) +void RowLoader::setQuery (QString new_query, QString newCountQuery) { std::lock_guard lk(m); query = new_query; + if (newCountQuery.isEmpty()) + // If it is a normal query - hopefully starting with SELECT - just do a COUNT on it and return the results + countQuery = QString("SELECT COUNT(*) FROM (%1);").arg(rtrimChar(query, ';')); + else + countQuery = newCountQuery; } void RowLoader::triggerRowCountDetermination(int token) @@ -89,10 +95,8 @@ int RowLoader::countRows() return retval; } } else { - // If it is a normal query - hopefully starting with SELECT - just do a COUNT on it and return the results - QString sCountQuery = QString("SELECT COUNT(*) FROM (%1);").arg(rtrimChar(query, ';')); - statement_logger(sCountQuery); - QByteArray utf8Query = sCountQuery.toUtf8(); + statement_logger(countQuery); + QByteArray utf8Query = countQuery.toUtf8(); sqlite3_stmt* stmt; int status = sqlite3_prepare_v2(pDb.get(), utf8Query, utf8Query.size(), &stmt, nullptr); @@ -106,7 +110,7 @@ int RowLoader::countRows() } sqlite3_finalize(stmt); } else { - qWarning() << "Count query failed: " << sCountQuery; + qWarning() << "Count query failed: " << countQuery; } } diff --git a/src/RowLoader.h b/src/RowLoader.h index 1fae02fa..5fb11808 100644 --- a/src/RowLoader.h +++ b/src/RowLoader.h @@ -34,7 +34,7 @@ public: Cache & cache_data ); - void setQuery (QString); + void setQuery (QString new_query, QString newCountQuery = QString()); void triggerRowCountDetermination (int token); @@ -77,6 +77,7 @@ private: mutable std::condition_variable cv; QString query; + QString countQuery; mutable std::future row_counter; diff --git a/src/sql/Query.cpp b/src/sql/Query.cpp index 87db9cf2..e64e4545 100644 --- a/src/sql/Query.cpp +++ b/src/sql/Query.cpp @@ -18,6 +18,28 @@ void Query::clear() m_sort.clear(); } +std::string Query::buildWherePart() const +{ + std::string where; + if(m_where.size()) + { + where = "WHERE "; + + for(auto i=m_where.cbegin();i!=m_where.cend();++i) + { + const auto it = findSelectedColumnByName(m_column_names.at(i->first)); + std::string column = sqlb::escapeIdentifier(m_column_names.at(i->first)); + if(it != m_selected_columns.cend() && it->selector != column) + column = it->selector; + where += column + " " + i->second + " AND "; + } + + // Remove last ' AND ' + where.erase(where.size() - 5); + } + return where; +} + std::string Query::buildQuery(bool withRowid) const { // Selector and display formats @@ -40,23 +62,7 @@ std::string Query::buildQuery(bool withRowid) const } // Filter - std::string where; - if(m_where.size()) - { - where = "WHERE "; - - for(auto i=m_where.cbegin();i!=m_where.cend();++i) - { - const auto it = findSelectedColumnByName(m_column_names.at(i->first)); - std::string column = sqlb::escapeIdentifier(m_column_names.at(i->first)); - if(it != m_selected_columns.cend() && it->selector != column) - column = it->selector; - where += column + " " + i->second + " AND "; - } - - // Remove last ' AND ' - where.erase(where.size() - 5); - } + std::string where = buildWherePart(); // Sorting std::string order_by; @@ -72,6 +78,12 @@ std::string Query::buildQuery(bool withRowid) const return "SELECT " + selector + " FROM " + m_table.toString().toStdString() + " " + where + " " + order_by; } +std::string Query::buildCountQuery() const +{ + // Build simplest count query for this (filtered) table + return "SELECT COUNT(*) FROM " + m_table.toString().toStdString() + " " + buildWherePart(); +} + std::vector::iterator Query::findSelectedColumnByName(const std::string& name) { return std::find_if(m_selected_columns.begin(), m_selected_columns.end(), [name](const SelectedColumn& c) { diff --git a/src/sql/Query.h b/src/sql/Query.h index e5961da8..5420421e 100644 --- a/src/sql/Query.h +++ b/src/sql/Query.h @@ -48,6 +48,7 @@ public: void clear(); std::string buildQuery(bool withRowid) const; + std::string buildCountQuery() const; void setColumNames(const std::vector& column_names) { m_column_names = column_names; } std::vector columnNames() const { return m_column_names; } @@ -77,6 +78,7 @@ private: std::vector::iterator findSelectedColumnByName(const std::string& name); std::vector::const_iterator findSelectedColumnByName(const std::string& name) const; + std::string buildWherePart() const; }; } diff --git a/src/sqlitetablemodel.cpp b/src/sqlitetablemodel.cpp index 941b6a86..f73a2d1a 100644 --- a/src/sqlitetablemodel.cpp +++ b/src/sqlitetablemodel.cpp @@ -176,7 +176,7 @@ void SqliteTableModel::setQuery(const sqlb::Query& query) buildQuery(); } -void SqliteTableModel::setQuery(const QString& sQuery, bool dontClearHeaders) +void SqliteTableModel::setQuery(const QString& sQuery, const QString& sCountQuery, bool dontClearHeaders) { // clear if(!dontClearHeaders) @@ -190,7 +190,7 @@ void SqliteTableModel::setQuery(const QString& sQuery, bool dontClearHeaders) m_sQuery = sQuery.trimmed(); removeCommentsFromQuery(m_sQuery); - worker->setQuery(m_sQuery); + worker->setQuery(m_sQuery, sCountQuery); worker->triggerRowCountDetermination(m_lifeCounter); if(!dontClearHeaders) @@ -593,7 +593,7 @@ QModelIndex SqliteTableModel::dittoRecord(int old_row) void SqliteTableModel::buildQuery() { - setQuery(QString::fromStdString(m_query.buildQuery(true)), true); + setQuery(QString::fromStdString(m_query.buildQuery(true)), QString::fromStdString(m_query.buildCountQuery()), true); } void SqliteTableModel::removeCommentsFromQuery(QString& query) diff --git a/src/sqlitetablemodel.h b/src/sqlitetablemodel.h index 00a78076..350b5bde 100644 --- a/src/sqlitetablemodel.h +++ b/src/sqlitetablemodel.h @@ -77,7 +77,7 @@ public: QModelIndex dittoRecord(int old_row); /// configure for browsing results of specified query - void setQuery(const QString& sQuery, bool dontClearHeaders = false); + void setQuery(const QString& sQuery, const QString& sCountQuery = QString(), bool dontClearHeaders = false); QString query() const { return m_sQuery; } QString customQuery(bool withRowid) const { return QString::fromStdString(m_query.buildQuery(withRowid)); }