diff options
| author | 2015-02-22 14:06:38 -0500 | |
|---|---|---|
| committer | 2015-02-22 14:06:38 -0500 | |
| commit | 6d42c08a54f15ddfdd8ee73643e3ddf8907bccc2 (patch) | |
| tree | 0a6554677b6a7fea5c81134c0804f0acdb00e632 /SQLiteStudio3/coreSQLiteStudio/db | |
| parent | a0cf2bb71de2b70a2b293c4ce907ecaaf24275bf (diff) | |
| parent | 306d6d3ca9c9ad774d19135681a7f9805f77035f (diff) | |
Merge tag 'upstream/3.0.3'
Upstream version 3.0.3
# gpg: Signature made Sun 22 Feb 2015 02:06:37 PM EST using RSA key ID EBE9BD91
# gpg: Good signature from "Unit 193 <unit193@gmail.com>"
# gpg: aka "Unit 193 <unit193@ninthfloor.org>"
# gpg: aka "Unit 193 <unit193@ubuntu.com>"
# gpg: aka "Unit 193 <unit193@ninthfloor.com>"
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/db')
7 files changed, 56 insertions, 31 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h index c521bfa..9b27dc3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h @@ -352,7 +352,7 @@ void AbstractDb2<T>::storeResult(sqlite_func* func, const QVariant& result, bool case QVariant::UInt: case QVariant::LongLong: { - sqlite_set_result_int(func, result.toInt()); + sqlite_set_result_int(func, result.toLongLong()); break; } case QVariant::Double: diff --git a/SQLiteStudio3/coreSQLiteStudio/db/db.h b/SQLiteStudio3/coreSQLiteStudio/db/db.h index 7d10a05..e11a844 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/db.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/db.h @@ -501,7 +501,8 @@ class API_EXPORT Db : public QObject, public Interruptable * @brief Attaches given database to this database. * @param otherDb Other registered database object. * @param silent If true, no errors or warnings will be reported to the NotifyManager (they will still appear in logs). - * @return Name of the attached database (it's not the symbolic name of the other database, it's a name you would use in <tt>ATTACH 'name'</tt> statement). + * @return Name of the attached database (it's not the symbolic name of the other database, it's a name you would use in <tt>ATTACH 'name'</tt> statement), + * or null string if error occurred. * * This is convinent method to attach other registered databases to this database. It generates attached database name, so it doesn't conflict * with other - already attached - database names, attaches the database with that name and returns that name to you, so you can refer to it in queries. @@ -583,7 +584,8 @@ class API_EXPORT Db : public QObject, public Interruptable * @return Database type label. * * The database type label is used on UI to tell user what database it is (SQLite 3, SQLite 2, Encrypted SQLite 3, etc). - * This is defined by DbPlugin. + * This is usually the same as DbPlugin::getTitle(), but getTitle() is used in list of plugins in configuration dialog, + * while getTypeLabel() is used on databases list. */ virtual QString getTypeLabel() = 0; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp index 97b3f1d..9fc49df 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp @@ -107,6 +107,8 @@ void QueryExecutor::executeChain() } } + requiredDbAttaches = context->dbNameToAttach.leftValues(); + // We're done. clearChain(); @@ -433,6 +435,7 @@ void QueryExecutor::simpleExecutionFinished(SqlQueryPtr results) context->executionTime = QDateTime::currentMSecsSinceEpoch() - simpleExecutionStartTime; context->rowsAffected = results->rowsAffected(); context->totalRowsReturned = 0; + requiredDbAttaches = context->dbNameToAttach.leftValues(); executionMutex.lock(); executionInProgress = false; @@ -538,6 +541,12 @@ bool QueryExecutor::handleRowCountingResults(quint32 asyncId, SqlQueryPtr result return true; } + +const QStringList& QueryExecutor::getRequiredDbAttaches() const +{ + return requiredDbAttaches; +} + bool QueryExecutor::getNoMetaColumns() const { return noMetaColumns; @@ -550,32 +559,24 @@ void QueryExecutor::setNoMetaColumns(bool value) void QueryExecutor::handleErrorsFromSmartAndSimpleMethods(SqlQueryPtr results) { - QString simpleText = results->getErrorText(); - - // Smart text may contain messages from steps before the actual execution, but they will have negative error code. - // Positive error code means that the error came directly from SQLite. - QString smartText = context->errorCodeFromSmartExecution > 0 ? context->errorMessageFromSmartExecution : QString(); - - if (simpleText.contains("no such") && smartText.contains("no such")) - { - // This happens if user refers to invalid column in attached database. - // Smart execution will tell "no such column: xxx", while simple method will tell: - // "no such table: attach.table". In that case we're more interested in smart method message. - // This also applies to views. - error(context->errorCodeFromSmartExecution, smartText); - return; - } - - if (simpleText.contains("no such") && smartText.contains("ambiguous")) + UNUSED(results); + // It turns out that currently smart execution error has more sense to be displayed to user than the simple execution error, + // so we're ignoring error from simple method, because it's usually misleading. + // The case when simple method error is more true than smart method error is very rare nowdays. + // Just rename attach names in the message. + QString msg = context->errorMessageFromSmartExecution; + QString match; + QString replaceName; + Dialect dialect = db->getDialect(); + for (const QString& attachName : context->dbNameToAttach.rightValues()) { - // This happens when smart execution raised "amigous column name" or something like that, - // but simple method failed to work because of transparent database attaching. We prefer smart method error. - error(context->errorCodeFromSmartExecution, smartText); - return; + match = attachName + "."; + replaceName = wrapObjIfNeeded(context->dbNameToAttach.valueByRight(attachName), dialect) + "."; + while (msg.contains(match)) + msg.replace(match, replaceName); } - // No special case, use simple method error - error(results->getErrorCode(), simpleText); + error(context->errorCodeFromSmartExecution, msg); } void QueryExecutor::releaseResultsAndCleanup() diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h index 72c7fed..c6d7701 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h @@ -344,10 +344,19 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable { /** * @brief Database name that the table with this row ID is in. + * + * It's the actual database name as SQLite sees it. That means it is a "main", or any attach name. */ QString database; /** + * @brief Symbolic database name as listed in databases list. + * + * It can be empty if database was not explicitly passed in the query. + */ + QString dbName; + + /** * @brief Table name that the row ID is for. */ QString table; @@ -1018,6 +1027,8 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable */ void releaseResultsAndCleanup(); + const QStringList& getRequiredDbAttaches() const; + private: /** * @brief Executes query. @@ -1280,6 +1291,16 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable bool noMetaColumns = false; /** + * @brief List of required databases to attach. + * + * List of database names (symbolic names, as they appear on the list) that needs to be + * attached to access all columns returned by the most recent successful execution. + * + * This is set after every successful execution. + */ + QStringList requiredDbAttaches; + + /** * @brief Chain of executor steps. * * Executor step list is set up by setupExecutionChain() and cleaned up after diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp index 55203e4..9307d13 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp @@ -60,7 +60,7 @@ QHash<SelectResolver::Table,QHash<QString,QString>> QueryExecutorAddRowIds::addR } // Getting all tables we need to get ROWID for - SelectResolver resolver(db, select->tokens.detokenize()); + SelectResolver resolver(db, select->tokens.detokenize(), context->dbNameToAttach); resolver.resolveMultiCore = false; // multicore subselects result in not editable columns, skip them QSet<SelectResolver::Table> tables = resolver.resolveTables(core); @@ -177,6 +177,7 @@ bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const Se { // Query executor result column description QueryExecutor::ResultRowIdColumnPtr queryExecutorResCol = QueryExecutor::ResultRowIdColumnPtr::create(); + queryExecutorResCol->dbName = table.originalDatabase; queryExecutorResCol->database = table.database; queryExecutorResCol->table = table.table; queryExecutorResCol->tableAlias = table.alias; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp index bce1304..6acfb6f 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp @@ -289,10 +289,10 @@ QString QueryExecutorColumns::getAliasedColumnNameForSqlite2(const QueryExecutor if (context->dbNameToAttach.containsLeft(resCol->database, Qt::CaseInsensitive)) colNameParts << context->dbNameToAttach.valueByLeft(resCol->database, Qt::CaseInsensitive); else - colNameParts << resCol->database; + colNameParts << wrapObjIfNeeded(resCol->database, dialect); } - colNameParts << resCol->table; + colNameParts << wrapObjIfNeeded(resCol->table, dialect); } - colNameParts << resCol->column; + colNameParts << wrapObjIfNeeded(resCol->column, dialect); return colNameParts.join("."); } diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp index 9a5c1c2..31cda9e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp @@ -14,7 +14,7 @@ bool QueryExecutorDataSources::exec() if (select->coreSelects.first()->valuesMode) return true; - SelectResolver resolver(db, select->tokens.detokenize()); + SelectResolver resolver(db, select->tokens.detokenize(), context->dbNameToAttach); resolver.resolveMultiCore = false; // multicore subselects result in not editable columns, skip them SqliteSelect::Core* core = select->coreSelects.first(); |
