From 81a21e6ce040e7740de86340c8ea4dba30e69bc3 Mon Sep 17 00:00:00 2001 From: Unit 193 Date: Thu, 16 Jan 2025 01:57:37 -0500 Subject: New upstream version 3.4.13+dfsg. --- SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp | 97 ++++++++++++++++++++--- 1 file changed, 84 insertions(+), 13 deletions(-) (limited to 'SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp') diff --git a/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp b/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp index 8a3efa8..0e4dad5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp @@ -110,7 +110,7 @@ QSet SelectResolver::resolveTables(SqliteSelect::Core::Jo QList columns = resolveAvailableColumns(joinSrc); for (const Column& col : columns) { - if (col.type != Column::Type::COLUMN) + if (col.type != Column::Type::COLUMN || (col.flags & SelectResolver::FROM_RES_COL_SUBSELECT)) continue; tables << col.getTable(); @@ -356,10 +356,13 @@ void SelectResolver::resolveStar(SqliteSelect::Core::ResultColumn *resCol) } // If source column name is aliased, use it - if (!column.alias.isNull()) - column.displayName = column.alias; - else - column.displayName = column.column; + if (column.displayName.isNull()) + { + if (!column.alias.isNull()) + column.displayName = column.alias; + else + column.displayName = column.column; + } currentCoreResults << column; foundAtLeastOne = true; @@ -379,8 +382,10 @@ void SelectResolver::resolveExpr(SqliteSelect::Core::ResultColumn *resCol) column.alias = resCol->alias; column.column = getResColTokensWithoutAlias(resCol).detokenize().trimmed(); column.displayName = !resCol->alias.isNull() ? column.alias : column.column; - column.type = Column::OTHER; + if (expr->mode == SqliteExpr::Mode::SUB_SELECT) + column.flags |= SelectResolver::FROM_RES_COL_SUBSELECT; + currentCoreResults << column; // In this case we end it here. @@ -444,6 +449,21 @@ void SelectResolver::resolveDbAndTable(SqliteSelect::Core::ResultColumn *resCol) SelectResolver::Column SelectResolver::resolveRowIdColumn(SqliteExpr *expr) { + // If the ROWID is used without table prefix, we rely on single source to be in the query. + // If there are more sources, there is no way to tell from which one the ROWID is taken. + if (expr->table.isNull()) + { + QSet tableSources; + for (Column& column : currentCoreSourceColumns) + tableSources += column.getTable(); + + if (tableSources.size() == 1) + { + // Single source. We can tell this is correct for our ROWID. + return currentCoreSourceColumns.first(); + } + } + // Looking for first source that can provide ROWID. for (Column& column : currentCoreSourceColumns) { @@ -650,6 +670,7 @@ QList SelectResolver::resolveTableFunctionColumns(Sqlite column.type = Column::OTHER; column.database = joinSrc->database; column.originalDatabase = resolveDatabase(joinSrc->database); + column.flags |= FROM_TABLE_VALUED_FN; if (!joinSrc->alias.isNull()) column.tableAlias = joinSrc->alias; @@ -663,16 +684,40 @@ QList SelectResolver::resolveTableFunctionColumns(Sqlite QList SelectResolver::resolveSingleSourceSubSelect(SqliteSelect::Core::SingleSource *joinSrc) { + static_qstring(newAliasTpl, "column%1"); + static_qstring(nextAliasTpl, "column%1:%2"); + QList columnSources = resolveSubSelect(joinSrc->select); applySubSelectAlias(columnSources, joinSrc->alias); + int colNum = 1; + QSet usedColumnNames; QMutableListIterator it(columnSources); while (it.hasNext()) { - if (it.next().alias.isEmpty()) - continue; + Column& col = it.next(); + usedColumnNames << (col.alias.isEmpty() ? col.column : col.alias).toLower(); - it.value().aliasDefinedInSubQuery = true; + // Columns named "true", "false" - require special treatment, + // as they will be renamed from subselects to columnN by SQLite query planner (#5065) + if (isReservedLiteral(col.alias) || (col.alias.isEmpty() && isReservedLiteral(col.column))) + { + QString newAlias = newAliasTpl.arg(colNum); + for (int i = 1; usedColumnNames.contains(newAlias); i++) + newAlias = nextAliasTpl.arg(colNum).arg(i); + + if (!col.alias.isNull()) + col.displayName = col.alias; + else + col.displayName = col.column; + + col.alias = newAlias; + } + + if (!col.alias.isEmpty()) + col.aliasDefinedInSubQuery = true; + + colNum++; } return columnSources; @@ -680,7 +725,19 @@ QList SelectResolver::resolveSingleSourceSubSelect(Sqlit QList SelectResolver::resolveOtherSource(SqliteSelect::Core::JoinSourceOther *otherSrc) { - return resolveSingleSource(otherSrc->singleSource); + QList joinedColumns = resolveSingleSource(otherSrc->singleSource); + if (!otherSrc->joinConstraint || otherSrc->joinConstraint->expr) + return joinedColumns; + + // Skip right-hand (aka "other") source column if it matches any of names listed in USING clause. + QSet usingColumns; + for (QString& colName : otherSrc->joinConstraint->columnNames) + usingColumns << colName.toLower(); + + return filter(joinedColumns, [usingColumns](const SelectResolver::Column& col) + { + return !usingColumns.contains((col.alias.isNull() ? col.column : col.alias).toLower()); + }); } QList SelectResolver::resolveSubSelect(SqliteSelect *select) @@ -716,9 +773,15 @@ QList SelectResolver::resolveSubSelect(SqliteSelect *sel } else { + static_qstring(colTpl, "%1.%2 AS %3"); + auto fn = [](const Column& c) {return colTpl.arg(c.table, c.column, c.alias);}; + QStringList resolverColumns = map(columnSourcesFromInternal, fn); + QStringList sqliteColumns = map(columnSources, fn); qCritical() << "Number of columns resolved by internal SchemaResolver is different than resolved by SQLite API:" << columnSourcesFromInternal.size() << "!=" << columnSources.size() - << ", therefore table alias may be identified incorrectly (from resolver, but not by SQLite API)"; + << ", therefore table alias may be identified incorrectly (from resolver, but not by SQLite API)" + << ". Columns were resolved from query:" << query << ". Colums resolved by SchemaResolver:" + << resolverColumns.join(", ") << ", while columns from SQLite:" << sqliteColumns.join(", "); } if (compound) @@ -737,8 +800,15 @@ QList SelectResolver::resolveView(SqliteSelect::Core::Si QList results = sqliteResolveColumns(columnSqlTpl.arg(joinSrc->detokenize())); applySubSelectAlias(results, (!joinSrc->alias.isNull() ? joinSrc->alias : joinSrc->table)); for (Column& column : results) + { column.flags |= FROM_VIEW; + if (column.alias.isEmpty()) + continue; + + column.aliasDefinedInSubQuery = true; + } + return results; } @@ -753,10 +823,11 @@ QList SelectResolver::sqliteResolveColumns(Db* db, const for (const AliasedColumn& queryColumn : queryColumns) { if (!queryColumn.getDatabase().isNull()) - column.database = dbNameToAttach.valueByRight(queryColumn.getDatabase(), queryColumn.getDatabase(), Qt::CaseInsensitive); + column.originalDatabase = dbNameToAttach.valueByRight(queryColumn.getDatabase(), queryColumn.getDatabase(), Qt::CaseInsensitive); else - column.database = QString(); + column.originalDatabase = QString(); + column.database = queryColumn.getDatabase(); column.displayName = queryColumn.getAlias(); if (queryColumn.getTable().isNull()) { -- cgit v1.2.3