diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index b96ea2a5..9cdb806b 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1039,44 +1039,54 @@ void MainWindow::executeQuery() QString query; int execution_start_line = 0; int execution_start_index = 0; + int execution_start_position = 0; + SqlTextEdit *editor = sqlWidget->getEditor(); + const QString tabName = ui->tabSqlAreas->tabText(ui->tabSqlAreas->currentIndex()).remove('&'); + if(sender()->objectName() == "actionSqlExecuteLine") { int cursor_line, cursor_index; - SqlTextEdit *editor = sqlWidget->getEditor(); editor->getCursorPosition(&cursor_line, &cursor_index); execution_start_line = cursor_line; - int lineStartCursorPosition = editor->positionFromLineIndex(cursor_line, 0); + execution_start_position = editor->positionFromLineIndex(cursor_line, 0); QString entireSQL = editor->text(); - QString firstPartEntireSQL = entireSQL.left(lineStartCursorPosition); - QString secondPartEntireSQL = entireSQL.right(entireSQL.length() - lineStartCursorPosition); + QString firstPartEntireSQL = entireSQL.left(execution_start_position); + QString secondPartEntireSQL = entireSQL.right(entireSQL.length() - execution_start_position); QString firstPartSQL = firstPartEntireSQL.split(";").last(); QString lastPartSQL = secondPartEntireSQL.split(";").first(); query = firstPartSQL + lastPartSQL; + db.logSQL(tr("-- EXECUTING LINE IN '%1'\n--").arg(tabName), kLogMsg_User); + } else { // if a part of the query is selected, we will only execute this part query = sqlWidget->getSelectedSql(); int dummy; - if(query.isEmpty()) + if(query.isEmpty()) { query = sqlWidget->getSql(); - else - sqlWidget->getEditor()->getSelection(&execution_start_line, &execution_start_index, &dummy, &dummy); + db.logSQL(tr("-- EXECUTING ALL IN '%1'\n--").arg(tabName), kLogMsg_User); + } else { + editor->getSelection(&execution_start_line, &execution_start_index, &dummy, &dummy); + execution_start_position = editor->positionFromLineIndex(execution_start_line, execution_start_index); + db.logSQL(tr("-- EXECUTING SELECTION IN '%1'\n--").arg(tabName), kLogMsg_User); + } } - SqliteTableModel::removeCommentsFromQuery(query); - if (query.trimmed().isEmpty() || query.trimmed() == ";") return; - query = query.remove(QRegExp("^\\s*BEGIN TRANSACTION;|COMMIT;\\s*$")).trimmed(); + // All replacements in the query should be made by the same amount of characters, so the positions in the file + // for error indicators and line and column logs are not displaced. + // Whitespace and comments are discarded by SQLite, so it is better to just let it ignore them. + + query = query.replace(QRegExp("^(\\s*)BEGIN TRANSACTION;", Qt::CaseInsensitive), "\\1 "); + query = query.replace(QRegExp("COMMIT;(\\s*)$", Qt::CaseInsensitive), " \\1"); - //log the query - db.logSQL(query, kLogMsg_User); sqlite3_stmt *vm; QByteArray utf8Query = query.toUtf8(); const char *tail = utf8Query.data(); @@ -1090,7 +1100,9 @@ void MainWindow::executeQuery() bool savepoint_created = false; // Remove any error indicators - sqlWidget->getEditor()->clearErrorIndicators(); + editor->clearErrorIndicators(); + + QApplication::setOverrideCursor(Qt::BusyCursor); // Accept multi-line queries, by looping until the tail is empty QElapsedTimer timer; @@ -1150,7 +1162,7 @@ void MainWindow::executeQuery() sql3status = sqlite3_prepare_v2(pDb.get(), tail, tail_length, &vm, &tail); QString queryPart = QString::fromUtf8(qbegin, tail - qbegin); tail_length -= (tail - qbegin); - int execution_end_index = execution_start_index + tail_length_before - tail_length; + int execution_end_position = execution_start_position + tail_length_before - tail_length; if (sql3status == SQLITE_OK) { @@ -1183,9 +1195,7 @@ void MainWindow::executeQuery() model->waitUntilIdle(); qApp->processEvents(); // to make row count available - // The query takes the last placeholder as it may itself contain the sequence '%' + number - statusMessage = tr("%1 rows returned in %2ms from: %3").arg( - model->rowCount()).arg(timer.elapsed()).arg(queryPart.trimmed()); + statusMessage = tr("%1 rows returned in %2ms").arg(model->rowCount()).arg(timer.elapsed()); ok = true; ui->actionSqlResultsSave->setEnabled(true); ui->actionSqlResultsSaveAsView->setEnabled(!db.readOnly()); @@ -1209,28 +1219,45 @@ void MainWindow::executeQuery() if(query_part_type != StatementType::AttachStatement && query_part_type != StatementType::DetachStatement) modified = true; - statusMessage = tr("Query executed successfully: %1 (took %2ms%3)").arg(queryPart.trimmed()).arg(timer.elapsed()).arg(stmtHasChangedDatabase); + statusMessage = tr("query executed successfully. Took %1ms%2").arg(timer.elapsed()).arg(stmtHasChangedDatabase); ok = true; break; } case SQLITE_MISUSE: continue; default: - statusMessage = QString::fromUtf8(sqlite3_errmsg(pDb.get())) + ": " + queryPart; - ok = true; + ok = false; break; } timer.restart(); } else { - statusMessage = QString::fromUtf8(sqlite3_errmsg(pDb.get())) + ": " + queryPart; - sqlWidget->getEditor()->setErrorIndicator(execution_start_line, execution_start_index, execution_start_line, execution_end_index); ok = false; } + editor->lineIndexFromPosition(execution_start_position, &execution_start_line, &execution_start_index); + + // Special case: if the start position is at the end of a line, then move to the beggining of next line. + // Otherwise for the typical case, the line reference is one less than expected. + if (editor->lineLength(execution_start_line) == execution_start_index+1) { + execution_start_line++; + execution_start_index = 0; + } + + if (!ok) { + int execution_end_index, execution_end_line; + editor->lineIndexFromPosition(execution_end_position, &execution_end_line, &execution_end_index); + statusMessage = QString::fromUtf8(sqlite3_errmsg(pDb.get())); + editor->setErrorIndicator(execution_start_line, execution_start_index, execution_end_line, execution_end_index); + editor->setCursorPosition(execution_start_line, execution_start_index); + } + // Log the query and the result message. + // The query takes the last placeholder as it may itself contain the sequence '%' + number. + statusMessage = QString("-- At line %1:\n%4\n-- Result: %3").arg(execution_start_line+1).arg(statusMessage).arg(queryPart.trimmed()); + db.logSQL(statusMessage, kLogMsg_User); pDb = nullptr; // release db - execution_start_index = execution_end_index; + execution_start_position = execution_end_position; // Revert to save point now if it wasn't needed. We need to do this here because there are some rare cases where the next statement might // be affected by what is only a temporary and unnecessary savepoint. For example in this case: @@ -1256,6 +1283,8 @@ void MainWindow::executeQuery() // If the DB structure was changed by some command in this SQL script, update our schema representations if(structure_updated) db.updateSchema(); + + QApplication::restoreOverrideCursor(); } void MainWindow::mainTabSelected(int tabindex)