diff options
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/db')
10 files changed, 87 insertions, 23 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h index 0620a7d..5b95f61 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h @@ -109,7 +109,6 @@ class AbstractDb2 : public AbstractDb int colCount = -1; QStringList colNames; QList<QVariant> nextRowValues; - int affected = 0; bool rowAvailable = false; }; @@ -725,6 +724,8 @@ SqlResultsRowPtr AbstractDb2<T>::Query::nextInternal() if (!rowAvailable || db.isNull()) return SqlResultsRowPtr(); + ReadWriteLocker locker(&(db->dbOperLock), query, Dialect::Sqlite2, flags.testFlag(Db::Flag::NO_LOCK)); + Row* row = new Row; row->init(colNames, nextRowValues); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h index fe37d5e..e7b0a4b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h @@ -107,7 +107,6 @@ class AbstractDb3 : public AbstractDb QString errorMessage; int colCount = 0; QStringList colNames; - int affected = 0; bool rowAvailable = false; }; @@ -1076,13 +1075,14 @@ int AbstractDb3<T>::Query::fetchFirst() for (int i = 0; i < colCount; i++) colNames << QString::fromUtf8(T::column_name(stmt, i)); + int changesBefore = T::total_changes(db->dbHandle); rowAvailable = true; int res = fetchNext(); affected = 0; if (res == T::OK) { - affected = T::changes(db->dbHandle); + affected = T::total_changes(db->dbHandle) - changesBefore; insertRowId["ROWID"] = T::last_insert_rowid(db->dbHandle); } diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp index 9fc49df..b790ffa 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp @@ -40,7 +40,8 @@ QueryExecutor::QueryExecutor(Db* db, const QString& query, QObject *parent) : setAutoDelete(false); connect(this, SIGNAL(executionFailed(int,QString)), this, SLOT(cleanupAfterExecFailed(int,QString))); - connect(DBLIST, SIGNAL(dbAboutToBeUnloaded(Db*, DbPlugin*)), this, SLOT(cleanupBeforeDbDestroy(Db*, DbPlugin*))); + connect(DBLIST, SIGNAL(dbAboutToBeUnloaded(Db*, DbPlugin*)), this, SLOT(cleanupBeforeDbDestroy(Db*))); + connect(DBLIST, SIGNAL(dbRemoved(Db*)), this, SLOT(cleanupBeforeDbDestroy(Db*))); } QueryExecutor::~QueryExecutor() @@ -146,9 +147,8 @@ void QueryExecutor::cleanupAfterExecFailed(int code, QString errorMessage) cleanup(); } -void QueryExecutor::cleanupBeforeDbDestroy(Db* dbToBeUnloaded, DbPlugin* plugin) +void QueryExecutor::cleanupBeforeDbDestroy(Db* dbToBeUnloaded) { - UNUSED(plugin); if (!dbToBeUnloaded || dbToBeUnloaded != db) return; @@ -404,7 +404,16 @@ void QueryExecutor::executeSimpleMethod() simpleExecution = true; context->editionForbiddenReasons << EditionForbiddenReason::SMART_EXECUTION_FAILED; simpleExecutionStartTime = QDateTime::currentMSecsSinceEpoch(); - asyncId = db->asyncExec(originalQuery, context->queryParameters, Db::Flag::PRELOAD); + + if (asyncMode) + { + asyncId = db->asyncExec(originalQuery, context->queryParameters, Db::Flag::PRELOAD); + } + else + { + SqlQueryPtr results = db->exec(originalQuery, context->queryParameters, Db::Flag::PRELOAD); + simpleExecutionFinished(results); + } } void QueryExecutor::simpleExecutionFinished(SqlQueryPtr results) @@ -435,6 +444,7 @@ void QueryExecutor::simpleExecutionFinished(SqlQueryPtr results) context->executionTime = QDateTime::currentMSecsSinceEpoch() - simpleExecutionStartTime; context->rowsAffected = results->rowsAffected(); context->totalRowsReturned = 0; + context->executionResults = results; requiredDbAttaches = context->dbNameToAttach.leftValues(); executionMutex.lock(); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h index c6d7701..83d0436 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h @@ -1407,7 +1407,7 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable * from deleted Db. Keeping results is dangerous, becuase the Db driver (plugin) is most likely to * be unloaded soon and we won't be able to call results destructor. */ - void cleanupBeforeDbDestroy(Db* dbToBeUnloaded, DbPlugin* plugin); + void cleanupBeforeDbDestroy(Db* dbToBeUnloaded); }; int qHash(QueryExecutor::EditionForbiddenReason reason); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp index 9307d13..ea42baf 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp @@ -59,6 +59,16 @@ QHash<SelectResolver::Table,QHash<QString,QString>> QueryExecutorAddRowIds::addR return rowIdColsMap; } + bool hasStar = false; + for (SqliteSelect::Core::ResultColumn* resCol : core->resultColumns) + { + if (resCol->star) + { + hasStar = true; + break; + } + } + // Getting all tables we need to get ROWID for SelectResolver resolver(db, select->tokens.detokenize(), context->dbNameToAttach); resolver.resolveMultiCore = false; // multicore subselects result in not editable columns, skip them @@ -69,7 +79,7 @@ QHash<SelectResolver::Table,QHash<QString,QString>> QueryExecutorAddRowIds::addR if (table.flags & (SelectResolver::FROM_COMPOUND_SELECT | SelectResolver::FROM_DISTINCT_SELECT | SelectResolver::FROM_GROUPED_SELECT)) continue; // we don't get ROWID from compound, distinct or aggregated subselects - if (!addResultColumns(core, table, rowIdColsMap, isTopSelect)) + if (!addResultColumns(core, table, rowIdColsMap, isTopSelect, hasStar)) { ok = false; return rowIdColsMap; @@ -146,12 +156,14 @@ QHash<QString,QString> QueryExecutorAddRowIds::getNextColNames(const SelectResol } bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const SelectResolver::Table& table, - QHash<SelectResolver::Table,QHash<QString,QString>>& rowIdColsMap, bool isTopSelect) + QHash<SelectResolver::Table,QHash<QString,QString>>& rowIdColsMap, bool isTopSelect, bool hasStar) { QHash<QString, QString> executorToRealColumns; + bool aliasOnlyAsSelectColumn = false; if (rowIdColsMap.contains(table)) { executorToRealColumns = rowIdColsMap[table]; // we already have resCol names from subselect + aliasOnlyAsSelectColumn = true; } else { @@ -169,7 +181,7 @@ bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const Se while (it.hasNext()) { it.next(); - if (!addResultColumns(core, table, it.key(), it.value())) + if (!addResultColumns(core, table, it.key(), it.value(), aliasOnlyAsSelectColumn)) return false; } @@ -189,7 +201,7 @@ bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const Se } bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const SelectResolver::Table& table, const QString& queryExecutorColumn, - const QString& realColumn) + const QString& realColumn, bool aliasOnlyAsSelectColumn) { SqliteSelect::Core::ResultColumn* resCol = new SqliteSelect::Core::ResultColumn(); resCol->setParent(core); @@ -197,17 +209,25 @@ bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const Se resCol->expr = new SqliteExpr(); resCol->expr->setParent(resCol); - resCol->expr->initId(realColumn); - if (!table.alias.isNull()) + if (aliasOnlyAsSelectColumn) { - resCol->expr->table = table.alias; + // We are re-querying this column from subselect, we already have it as an alias + resCol->expr->initId(queryExecutorColumn); } else { - if (!table.database.isNull()) - resCol->expr->database = table.database; + resCol->expr->initId(realColumn); + if (!table.alias.isNull()) + { + resCol->expr->table = table.alias; + } + else + { + if (!table.database.isNull()) + resCol->expr->database = table.database; - resCol->expr->table = table.table; + resCol->expr->table = table.table; + } } resCol->asKw = true; resCol->alias = queryExecutorColumn; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h index a5431fa..fa2167f 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h @@ -31,7 +31,7 @@ class QueryExecutorAddRowIds : public QueryExecutorStep * Finds columns representing ROWID for the \p table and adds them to result columns and to the context. */ bool addResultColumns(SqliteSelect::Core* core, const SelectResolver::Table& table, - QHash<SelectResolver::Table, QHash<QString, QString> >& rowIdColsMap, bool isTopSelect); + QHash<SelectResolver::Table, QHash<QString, QString> >& rowIdColsMap, bool isTopSelect, bool hasStar); /** * @brief Adds the column to result columns list. @@ -44,7 +44,7 @@ class QueryExecutorAddRowIds : public QueryExecutorStep * Adds given column to the result column list in the SELECT statement. */ bool addResultColumns(SqliteSelect::Core* core, const SelectResolver::Table& table, const QString& queryExecutorColumn, - const QString& realColumn); + const QString& realColumn, bool aliasOnlyAsSelectColumn); /** * @brief Adds all necessary ROWID columns to result columns. diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp index df2ed68..a954da7 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp @@ -7,6 +7,7 @@ #include "datatype.h" #include <QDateTime> #include <QDebug> +#include <QStack> #include <schemaresolver.h> #include <common/table.h> @@ -34,6 +35,7 @@ bool QueryExecutorExecute::executeQueries() QHash<QString, QVariant> bindParamsForQuery; SqlQueryPtr results; context->rowsAffected = 0; + QStack<int> rowsAffectedBeforeTransaction; Db::Flags flags; if (context->preloadResults) @@ -51,6 +53,9 @@ bool QueryExecutorExecute::executeQueries() if (queryCount == 0) // last query? setupSqlite2ColumnDataTypes(results); + if (isBeginTransaction(query->queryType)) + rowsAffectedBeforeTransaction.push(context->rowsAffected); + results->execute(); if (results->isError()) @@ -60,6 +65,14 @@ bool QueryExecutorExecute::executeQueries() } context->rowsAffected += results->rowsAffected(); + + if (rowsAffectedBeforeTransaction.size() > 0) + { + if (isCommitTransaction(query->queryType)) + rowsAffectedBeforeTransaction.pop(); + else if (isRollbackTransaction(query->queryType)) + context->rowsAffected = rowsAffectedBeforeTransaction.pop(); + } } handleSuccessfulResult(results); return true; @@ -152,3 +165,18 @@ void QueryExecutorExecute::setupSqlite2ColumnDataTypes(SqlQueryPtr results) sqlite2Helper->setBinaryType(idx); } } + +bool QueryExecutorExecute::isBeginTransaction(SqliteQueryType queryType) +{ + return (queryType == SqliteQueryType::BeginTrans || queryType == SqliteQueryType::Savepoint); +} + +bool QueryExecutorExecute::isCommitTransaction(SqliteQueryType queryType) +{ + return (queryType == SqliteQueryType::CommitTrans || queryType == SqliteQueryType::Release); +} + +bool QueryExecutorExecute::isRollbackTransaction(SqliteQueryType queryType) +{ + return queryType == SqliteQueryType::Rollback; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.h index a88bf56..ea6fed2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.h @@ -80,6 +80,9 @@ class QueryExecutorExecute : public QueryExecutorStep qint64 startTime; void setupSqlite2ColumnDataTypes(SqlQueryPtr results); + bool isBeginTransaction(SqliteQueryType queryType); + bool isCommitTransaction(SqliteQueryType queryType); + bool isRollbackTransaction(SqliteQueryType queryType); }; #endif // QUERYEXECUTOREXECUTE_H diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorreplaceviews.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorreplaceviews.cpp index 94300a0..1f2e736 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorreplaceviews.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorreplaceviews.cpp @@ -25,6 +25,7 @@ bool QueryExecutorReplaceViews::exec() return true; replaceViews(select.data()); + select->rebuildTokens(); updateQueries(); return true; @@ -72,7 +73,7 @@ void QueryExecutorReplaceViews::replaceViews(SqliteSelect* select) SqliteCreateViewPtr view; QList<SqliteSelect::Core::SingleSource*> sources = core->getAllTypedStatements<SqliteSelect::Core::SingleSource>(); - foreach (SqliteSelect::Core::SingleSource* src, sources) + for (SqliteSelect::Core::SingleSource* src : sources) { if (src->table.isNull()) continue; @@ -92,9 +93,9 @@ void QueryExecutorReplaceViews::replaceViews(SqliteSelect* select) src->select = view->select; src->database = QString::null; src->table = QString::null; - } - select->rebuildTokens(); + replaceViews(src->select); + } } uint qHash(const QueryExecutorReplaceViews::View& view) diff --git a/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h b/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h index 2f26aaf..6b0c422 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h @@ -64,6 +64,7 @@ static int column_type(stmt* arg1, int arg2) {return Prefix##sqlite3_column_type(arg1, arg2);} \ static int column_count(stmt* arg1) {return Prefix##sqlite3_column_count(arg1);} \ static int changes(handle* arg) {return Prefix##sqlite3_changes(arg);} \ + static int total_changes(handle* arg) {return Prefix##sqlite3_total_changes(arg);} \ static int last_insert_rowid(handle* arg) {return Prefix##sqlite3_last_insert_rowid(arg);} \ static int step(stmt* arg) {return Prefix##sqlite3_step(arg);} \ static int reset(stmt* arg) {return Prefix##sqlite3_reset(arg);} \ |
