Skip to content

Commit

Permalink
#5216 Fixed Query Executor to use Smart Execution Method when there i…
Browse files Browse the repository at this point in the history
…s a Virtual Table mentioned in the query, therefore enabling all advanced features of the Query Executor.
  • Loading branch information
pawelsalawa committed Jan 16, 2025
1 parent 39f98ab commit 4bca62a
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 66 deletions.
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### 3.4.15
- BUGFIX: #5218 Fixed Drag&Drop of items in the database list - a bug that was introduced in 3.4.14.
- BUGFIX: #5216 Fixed Query Executor to use Smart Execution Method when there is a Virtual Table mentioned in the query, therefore enabling all advanced features of the Query Executor.

### 3.4.14
- ADDED: #5190 Added support for optional ORDER BY and LIMIT clauses in UPDATE and DELETE statements.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "parser/ast/sqliteselect.h"
#include "selectresolver.h"
#include "parser/ast/sqlitecreatetable.h"
#include "parser/ast/sqlitecreatevirtualtable.h"
#include "schemaresolver.h"
#include "common/compatibility.h"
#include <QDebug>
Expand Down Expand Up @@ -112,48 +113,15 @@ QList<SqliteSelect*> QueryExecutorAddRowIds::getSubSelects(SqliteSelect::Core* c

QHash<QString,QString> QueryExecutorAddRowIds::getNextColNames(const SelectResolver::Table& table)
{
QHash<QString,QString> colNames;

SchemaResolver resolver(db);
SqliteQueryPtr query = resolver.getParsedObject(table.database, table.table, SchemaResolver::TABLE);
SqliteCreateTablePtr createTable = query.dynamicCast<SqliteCreateTable>();
if (!createTable)
{
qCritical() << "No CREATE TABLE object after parsing and casting in QueryExecutorAddRowIds::getNextColNames(). Cannot provide ROWID columns.";
return colNames;
}
QStringList rowIdCols = table.database.isNull() ?
resolver.getRowIdTableColumns(table.table) :
resolver.getRowIdTableColumns(table.database, table.table);

if (!createTable->withOutRowId)
{
// It's a regular ROWID table
colNames[getNextColName()] = "ROWID";
return colNames;
}

SqliteStatement* primaryKey = createTable->getPrimaryKey();
if (!primaryKey)
{
qCritical() << "WITHOUT ROWID table, but could not find // Co PRIMARY KEY in QueryExecutorAddRowIds::getNextColNames().";
return colNames;
}

SqliteCreateTable::Column::Constraint* columnConstr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(primaryKey);
if (columnConstr)
{
colNames[getNextColName()] = dynamic_cast<SqliteCreateTable::Column*>(columnConstr->parentStatement())->name;
return colNames;
}

SqliteCreateTable::Constraint* tableConstr = dynamic_cast<SqliteCreateTable::Constraint*>(primaryKey);
if (tableConstr)
{
for (SqliteIndexedColumn*& idxCol : tableConstr->indexedColumns)
colNames[getNextColName()] = idxCol->name;

return colNames;
}
QHash<QString,QString> colNames;
for (const QString& colName : rowIdCols)
colNames[getNextColName()] = colName;

qCritical() << "PRIMARY KEY that is neither table or column constraint. Should never happen (QueryExecutorAddRowIds::getNextColNames()).";
return colNames;
}

Expand Down
50 changes: 37 additions & 13 deletions SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1418,27 +1418,51 @@ SqliteCreateTablePtr SchemaResolver::resolveVirtualTableAsRegularTable(const QSt
return virtualTableAsRegularTable(database, table);
}

QStringList SchemaResolver::getWithoutRowIdTableColumns(const QString& table)
QStringList SchemaResolver::getRowIdTableColumns(const QString& table)
{
return getWithoutRowIdTableColumns("main", table);
return getRowIdTableColumns("main", table);
}

QStringList SchemaResolver::getWithoutRowIdTableColumns(const QString& database, const QString& table)
QStringList SchemaResolver::getRowIdTableColumns(const QString& database, const QString& table)
{
QStringList columns;
SqlQueryPtr results = db->exec(QString("PRAGMA %1.table_list(%2);")
.arg(database, wrapObjIfNeeded(table)));
if (results->isError())
{
qWarning() << "Could not get rowId column list using PRAGMA for db.table:" << database << "." << table << " (step 1), error was:" << results->getErrorText();
return QStringList();
}

SqliteQueryPtr query = getParsedObject(database, table, TABLE);
if (!query)
return columns;
if (!results->hasNext())
{
qWarning() << "Could not get rowId column list using PRAGMA for db.table:" << database << "." << table << " (step 1), no row was returned.";
return QStringList();
}

SqliteCreateTablePtr createTable = query.dynamicCast<SqliteCreateTable>();
if (!createTable)
return columns;
SqlResultsRowPtr row = results->next();
int withoutRowId = row->value("wr").toInt();
if (!withoutRowId)
return QStringList{"ROWID"};

// WITHOUT ROWID table
results = db->exec(QString("PRAGMA %1.table_info(%2);")
.arg(database, wrapObjIfNeeded(table)));

if (!createTable->withOutRowId)
return columns; // it's not WITHOUT ROWID table
if (results->isError())
{
qWarning() << "Could not get rowId column list using PRAGMA for db.table:" << database << "." << table << " (step 2), error was:" << results->getErrorText();
return QStringList();
}

return createTable->getPrimaryKeyColumns();
QStringList columns;
while (results->hasNext())
{
row = results->next();
int pk = row->value("pk").toInt();
if (pk)
columns << row->value("name").toString();
}
return columns;
}

QString SchemaResolver::getSqliteMasterDdl(bool temp)
Expand Down
4 changes: 2 additions & 2 deletions SQLiteStudio3/coreSQLiteStudio/schemaresolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ class API_EXPORT SchemaResolver
SqliteCreateTablePtr resolveVirtualTableAsRegularTable(const QString& table);
SqliteCreateTablePtr resolveVirtualTableAsRegularTable(const QString& database, const QString& table);

QStringList getWithoutRowIdTableColumns(const QString& table);
QStringList getWithoutRowIdTableColumns(const QString& database, const QString& table);
QStringList getRowIdTableColumns(const QString& table);
QStringList getRowIdTableColumns(const QString& database, const QString& table);

/**
* @brief getTableColumns Get column names for a table.
Expand Down
27 changes: 15 additions & 12 deletions SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1321,29 +1321,32 @@ void SqlQueryModel::readColumnDetails()
QHash<AliasedTable, SqlQueryModel::TableDetails> SqlQueryModel::readTableDetails()
{
QHash<AliasedTable, TableDetails> results;
SqliteQueryPtr query;
SqliteCreateTablePtr createTable;
SchemaResolver resolver(getDb());
QString database;
AliasedTable table;
QString columnName;

for (const QueryExecutor::SourceTablePtr& srcTable : queryExecutor->getSourceTables())
{
database = srcTable->database.isEmpty() ? "main" : srcTable->database;
QString database = srcTable->database.isEmpty() ? "main" : srcTable->database;

query = resolver.getParsedObject(database, srcTable->table, SchemaResolver::TABLE);
if (!query || !query.dynamicCast<SqliteCreateTable>())
SqliteQueryPtr query = resolver.getParsedObject(database, srcTable->table, SchemaResolver::TABLE);
if (!query)
{
qWarning() << "Could not get parsed table while reading table details in SqlQueryModel. Queried table was:"
<< database + "." + srcTable->table;
continue;
}
createTable = query.dynamicCast<SqliteCreateTable>();
SqliteCreateTablePtr createTable = query.dynamicCast<SqliteCreateTable>();
if (!createTable && resolver.isVirtualTable(database, srcTable->table))
createTable = resolver.resolveVirtualTableAsRegularTable(database, srcTable->table);

if (!createTable)
{
qWarning() << "Could not get parsed table while reading table details in SqlQueryModel. Neither as regular nor virtual table. Queried table was:"
<< database + "." + srcTable->table;
continue;
}

// Table details
TableDetails tableDetails;
table = {database, srcTable->table, srcTable->alias};
AliasedTable table = {database, srcTable->table, srcTable->alias};

// Table constraints
for (SqliteCreateTable::Constraint* tableConstr : createTable->constraints)
Expand All @@ -1354,7 +1357,7 @@ QHash<AliasedTable, SqlQueryModel::TableDetails> SqlQueryModel::readTableDetails
{
// Column details
TableDetails::ColumnDetails columnDetails;
columnName = stripObjName(columnStmt->name);
QString columnName = stripObjName(columnStmt->name);

// Column type
if (columnStmt->type)
Expand Down

0 comments on commit 4bca62a

Please sign in to comment.