Fix read-only queries stopping after the first row

Since #1046, QETSql::execReadOnly() runs a query with PRAGMA query_only
set and switches it off before returning. Switching it off aborts a
statement SQLite is still stepping through ("abort due to ROLLBACK"), and
QSQLITE has already stepped to the first row by then. A query that
produces its rows as it goes -- a UNION ALL without ORDER BY -- therefore
came back with its first row only and no error. A sorted query was not
affected, because SQLite has read every row before returning the first.

Every query from the SQL box of a table, a saved <graphics_table> query
and the scripting qet.query() goes through here.

The checked run is now finished before query_only is switched off, and a
query that passed is run again for the caller. SQLite refuses a write at
its first step, so passing that step is what proves a statement reads
only; the second run is of a statement already shown to be read-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
This commit is contained in:
ispyisail
2026-09-27 14:00:07 +13:00
parent 76eea09192
commit 29fe731728
2 changed files with 24 additions and 0 deletions
+7
View File
@@ -86,9 +86,16 @@ QSqlQuery execReadOnly(const QSqlDatabase &db, const QString &query, QString *er
QSqlQuery result(db);
const bool ok = result.exec(query);
//Switching query_only off aborts a statement SQLite is still
//stepping through -- an unsorted UNION ALL then ends after its
//first row. So the checked run is finished first, and a statement
//that passed is run again for the caller: SQLite refuses a write
//at its first step, so passing that step proves it read-only.
result.finish();
QSqlQuery(db).exec(QStringLiteral("PRAGMA query_only = OFF"));
if (ok) {
result.exec(query);
return result;
}