diff options
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio')
146 files changed, 12930 insertions, 6756 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/ChangeLog.txt b/SQLiteStudio3/coreSQLiteStudio/ChangeLog.txt index c0c42cd..8f1df64 100644 --- a/SQLiteStudio3/coreSQLiteStudio/ChangeLog.txt +++ b/SQLiteStudio3/coreSQLiteStudio/ChangeLog.txt @@ -1,3 +1,72 @@ +[3.2.1] + * [BUGFIX]: #3399 Fixed start under Linux using the pre-compiled binary distributions (it used to fail due to missing xcb dependency). + * [BUGFIX]: #3398 Fixed 'export data' checkbox in export dialog to not ignore it anymore. + * [BUGFIX]: Binary packages now include the MultiEditorImage plugin, which introduces the picture preview for BLOB values. It was introduced in 3.2.0, but missing in binary distributions. + +[3.2.0] + * [NEW]: #3188 New plugin to have images stored in database being visible as another tab in the Form View or cell's editor dialog window. + * [NEW]: #3207 #1444 #2547 Export, Import & Populate dialog settings are remembered, even after application restart. + * [NEW]: #3268 Query bind parameters are now supported by the query editor while execution - user will be asked for values for these parameters in a dedicated dialog. + * [NEW]: #3267 Added Extension Manager window, where all SQLite extensions can be registered for loading into databases. + * [NEW]: #3161 Added support for table-valued functions (https://sqlite.org/vtab.html#tabfunc2) + * [NEW]: #3349 Added support for UPSERT syntax from SQLite 3.24.0. + * [NEW]: #3292 Added possibility to execute huge SQL files directly from disk, without loading them to SQL Editor. + * [NEW]: #3265 Completely new installer for SQLiteStudio is introduced. It bases on Qt Installer Framework. This addresses numerous issues with automatic updates that SQLiteStudio had. It also allows for some new features, like automatic file association under Windows (#3178). Portable (download & run, without installation) distribution continues to be available. + * [NEW]: #2659 AutoIncrement option is now always available in PK configuration dialog. When AutoIncrement is enabled, a datatype will be enforced to INTEGER type. + * [NEW]: #2798 Added filter inputs per column as an option. + * [NEW]: #3224 Added context menu for SQL history tab to delete individual (or a range of selected) entries. Also a "delete" key can be used. + * [NEW]: #2651 Only a single instance of SQLiteStudio can be running at the time. If another instance is requested, the first one will be brought to the front of windows stack. If another instance was requested due to associated file being open, then the first instance will not only be raised, but also the requested file will be added to database list as temporary, volatile database (not added permanently to configuration). + * [NEW]: #3033 Ctrl+Shift+c copies data including headers. Also context menu entry added for the same. + * [NEW]: #2962 Pasting single value to multiple cells results in pasting the value into all selected cells, not just to first one. + * [NEW]: #2907 The "Open file's directory" menu item added to database list for database nodes. + * [NEW]: #3388 Added file association entries in the plist for MacOSX + * [NEW]: #3163 Added menubar accelerator keys. + * [CHANGE]: #3257 #3260 #3271 Bug/Feature reports are now completely managed by GitHub. Bug report dialog is no longer present in the application, but instead the menu entry opens web browser on project's GitHub page. + * [CHANGE]: #3285 SQLCipher and wxSQLite3 plugins can now be linked to system-provided libraries, which is especially useful under Linux. Instructions were added to the wiki page: https://github.com/pawelsalawa/sqlitestudio/wiki/Instructions_for_compilation_under_Linux#linking-with-system-provided-libraries + * [CHANGE]: #3284 SQLite3 upgraded to version 3.24.0 (excluding SQLCipher plugin, which is still on 3.20.1). + * [CHANGE]: API of QueryExecutor enhanced to provide custom steps at certain stages of execution. Steps can be injected by plugins. + * [CHANGE]: #3121 Column widths are kept between data reloads. + * [CHANGE]: #3024 Edit in editor action in cell's context menu stands now "show in viewer" if clicked on read-only cell. Also "set null" and "erase" are not displayed if none of selected cells is editable. + * [CHANGE]: #3142 Horizontal scroll position is now preserved between sort request on a data view. + * [CHANGE]: #2971 Column width is now mostly based on data width, not header width, but if there is little columns to be displayed, the header width is also considered. + * [CHANGE]: #3323 Disabled automatic line wrapping in SQL editor and all other code edition fields in the application. + * [BUGFIX]: #3259 #3215 #3327 Stop interpreting "+3" or "0010" as numeric types if entered to TEXT column (or any other column not declared as numeric-ish). + * [BUGFIX]: #3191 CSV import speed improved. It's 1400 times faster. It's not a joke. The bug used to cause the import to be terribly slow. Also other importing plugins gained around 400% of speed. + * [BUGFIX]: #3119 Fixed extra "empty" row of data when importing from CSV with a new, empty line at the end. + * [BUGFIX]: #3235 Crash when opening DB dialog, but file was moved. + * [BUGFIX]: #3185 Fixed creation of new tables/views if "Data" tab is configured as first. + * [BUGFIX]: #3279 Fixed reporting rows affected with DELETE statement for SQLite2. + * [BUGFIX]: #3023 Optimized SQL editor widget to work with huge contents. + * [BUGFIX]: Fixed random crashes at application close (when saving session). Most frequend on Windows platform. + * [BUGFIX]: #3252 Fixed first character input when starting to edit FK column data. + * [BUGFIX]: #3251 Fixed DEFAULT constraint dialog to work wit "literal values in double-quotes" + * [BUGFIX]: #3084 #3085 Fixed beeps under MacOSX when editing FK cell. + * [BUGFIX]: #3293 Fixed deault shortcut for code assistant under MacOSX from Cmd-Space to Ctrl-Space, so it does not conflict with Spotlight + * [BUGFIX]: #3190 Fixed handling WITHOUT ROWID and unusual column name. + * [BUGFIX]: #3177 Fixed tab indentations when selecting even part of a line. + * [BUGFIX]: #3171 Pasting object to same database is prevented. + * [BUGFIX]: #3176 Fixed exporting with Common Table Expression (the WITH statement). + * [BUGFIX]: #3162 Fixed order of column headers in Index Dialog + * [BUGFIX]: #3159 Fixed dictionary populating plugin to recognize different new-line characters. + * [BUGFIX]: #3156 Fixed recognition of double-quoted values. + * [BUGFIX]: #3093 Columns with AUTOINCREMENT statement are defaulted to null for new rows in Form View, so they get committed this way (unless manually changed) and they become an auto generated values. + * [BUGFIX]: #3086 #3187 Fixed internal task ordering when drag&dropping tasks on the taskbar, so switching between tasks with keyboard shortcut reflects order of tasks on the taskbar. + * [BUGFIX]: #3173 Added support for detecting and trimming whitespace in pasted text (thanks to nishanthkarthik for contributing this) + * [BUGFIX]: #2922 Fixed CTE execution by QueryExecutor, so it understands columns from CTE (not editable columns for now, maybe will become editable in future). + * [BUGFIX]: #2964 SQL history tab shows now local time of execution, not UTC. + * [BUGFIX]: #3290 Fixed querying data for FK dropdown from tables/columns with unusual characters in name. Also fixed name-wrapping for objects that have unescaped wrapper character inside of their name. + * [BUGFIX]: #3305 Introduced dynamic limit for number of rows per page - based on number of columns, so it's less likely to hit the memory limit. + * [BUGFIX]: #3311 Fixed floating point numbers handling. + * [BUGFIX]: #3383 Fixed JSON export plugin for quoted names. + * [BUGFIX]: #3347 #3351 Fixed QCheckBox in several places, so text() of it is not used as a valid data. This is to address issues with automatic accelerator keys. + * [BUGFIX]: Addressed some concurrency erorrs in SQLite 2 plugin + * [BUGFIX]: #3139 #3116 #3326 #3341 Various code compiling issues addressed. + * [BUGFIX]: #3145 #3165 #3179 Fixed various typos in messages/interface. + * [BUGFIX]: #3333 Fixed unit test to honor new features of TableModifier, but also fixed few bugs in TableModifier. + * [BUGFIX]: #3277 Open Source license issues addressed (specific exceptions for OpenSSL and icons) + * [BUGFIX]: #2966 Application icon added to package. + * [BUGFIX]: Few other bugfixes made on the fly, while working on other issues. + [3.1.1] * [ADDED]: WxSQLite3 plugin (with encryption support). * [ADDED]: System.Data.SQLite plugin (ADO.NET, includes encryption support). diff --git a/SQLiteStudio3/coreSQLiteStudio/Info.plist b/SQLiteStudio3/coreSQLiteStudio/Info.plist index 3ce6f15..794e404 100644 --- a/SQLiteStudio3/coreSQLiteStudio/Info.plist +++ b/SQLiteStudio3/coreSQLiteStudio/Info.plist @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> -<dict> + <dict> <key>NSPrincipalClass</key> <string>NSApplication</string> <key>CFBundleIconFile</key> @@ -18,5 +18,32 @@ <string>SQLiteStudio</string> <key>CFBundleIdentifier</key> <string>pl.com.salsoft.SQLiteStudio</string> -</dict> + <key>CFBundleDocumentTypes</key> + <array> + <dict> + <key>CFBundleTypeExtensions</key> + <array> + <string>db</string> + <string>sdb</string> + <string>sqlite</string> + <string>db3</string> + <string>s3db</string> + <string>sqlite3</string> + <string>sl3</string> + <string>db2</string> + <string>s2db</string> + <string>sqlite2</string> + <string>sl2</string> + </array> + <key>CFBundleTypeName</key> + <string>SQLite Database Document</string> + <key>CFBundleTypeOSTypes</key> + <array> + <string>****</string> + </array> + <key>CFBundleTypeRole</key> + <string>Editor</string> + </dict> + </array> + </dict> </plist> diff --git a/SQLiteStudio3/coreSQLiteStudio/TODO.txt b/SQLiteStudio3/coreSQLiteStudio/TODO.txt index 9e0a77d..e4121f0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/TODO.txt +++ b/SQLiteStudio3/coreSQLiteStudio/TODO.txt @@ -1,52 +1,8 @@ -cannot reproduce: -2922 / 2926 / 2925 -2940 -3009 - db w emailu od goretux@gmail.com -3052 -3062 - -* Outstanding features for 3.2: -- migrate updates engine to Qt Install Framework -- loadable extensions full support -- BLOB preview engine based on plugins -- ERD plugin -- DB compare plugin -- executing query with bind params -- comments support in formatter - * Next versions: -- object names (columns, tables, etc) in dialogs should be validated against suffix/prefix whitespaces and if they appear, user should be asked for confirmation -- small useful features: generating template queries from context menu for table/view, from data view. -- code templates -- committing DataView should be async -- syntax checkers as services - per language -- code assistants as services - per language - specialized validation of expressions for DEFAULT constraint. -- "recovery" after failed startup - detecting if previous start crashed and if yes, propose cleaning of configuration. -- tcl highlighter -- highlighting occurrences of the same object in the query when cursor is on it -- plugin to do performance testing -- plugins to generate artifacts -- qtscript syntax checker -- tcl syntax checker -- dbf import -- dbf export -- code assistant as a service with plugins, so it can be extended with other langs and injected in custom functions window, collations window, etc - in configuration dialog option to disable each individual native SQL function - move "integrity check" into dedicated window, add "PRAGMA foreign_key_check" as a second stage of checking and present all in one window -- tips&tricks dialog -- crash management -- SqlEditor::refreshValidObjects() doesn't add valid object names from other databases (not yet attached). It might be tricky to implement. -- need an idea for some smart "revert" or "backup", so users are protected from accidentaly deleting table, or data in table. -- expose query executor steps chain to plugins -- complete plugin for "Search in database(s)" -- complete plugin for compare tables/databases -- executing queries with bind parameters -- completer: when suggesting table in FROM clause, look at columns after SELECT to give related tables first. - constraints tab in table window should have toolbar for adding/editing/deleting constraints -- add menu mnemonics support (underlined shortcut letters) -- per column filtering field when clicked on column header(?) -- option to show current window's DB path in top window title CLI: - plugin management commands diff --git a/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp index 091121c..5f40521 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp @@ -1,4 +1,5 @@ #include "bistrhash.h" +#include <QStringList> BiStrHash::BiStrHash(std::initializer_list<std::pair<QString, QString> > list) { diff --git a/SQLiteStudio3/coreSQLiteStudio/common/global.h b/SQLiteStudio3/coreSQLiteStudio/common/global.h index b1f4b01..cfd8dc0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/global.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/global.h @@ -12,7 +12,7 @@ #define DEEP_COPY_COLLECTION(T, F) \ T* _new##T; \ - foreach (T* _element, other.F) \ + for (T* _element : other.F) \ { \ _new##T = new T(*_element); \ _new##T->setParent(this); \ diff --git a/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.cpp b/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.cpp new file mode 100644 index 0000000..2c39f34 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.cpp @@ -0,0 +1,37 @@ +#include "lazytrigger.h" +#include <QTimer> + +LazyTrigger::LazyTrigger(int delay, QObject* parent, const char* slot) : + QObject(parent) +{ + timer = new QTimer(this); + timer->setSingleShot(true); + timer->setInterval(delay); + connect(timer, &QTimer::timeout, this, &LazyTrigger::triggered); + if (slot) + connect(timer, SIGNAL(timeout()), parent, slot); +} + +LazyTrigger::LazyTrigger(int delay, LazyTrigger::Condition condition, QObject* parent, const char* slot) : + LazyTrigger(delay, parent, slot) +{ + this->condition = condition; +} + +void LazyTrigger::setDelay(int delay) +{ + timer->setInterval(delay); +} + +void LazyTrigger::schedule() +{ + timer->stop(); + + if (!condition || condition()) + timer->start(); +} + +void LazyTrigger::cancel() +{ + timer->stop(); +} diff --git a/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.h b/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.h new file mode 100644 index 0000000..9c34395 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.h @@ -0,0 +1,34 @@ +#ifndef LAZYTRIGGER_H +#define LAZYTRIGGER_H + +#include "coreSQLiteStudio_global.h" +#include <QObject> +#include <functional> + +class QTimer; + +class API_EXPORT LazyTrigger : public QObject +{ + Q_OBJECT + + public: + typedef std::function<bool()> Condition; + + LazyTrigger(int delay, QObject* parent = nullptr, const char* slot = nullptr); + LazyTrigger(int delay, Condition condition, QObject* parent = nullptr, const char* slot = nullptr); + + void setDelay(int delay); + + private: + QTimer* timer = nullptr; + Condition condition = nullptr; + + public slots: + void schedule(); + void cancel(); + + signals: + void triggered(); +}; + +#endif // LAZYTRIGGER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/common/objectpool.h b/SQLiteStudio3/coreSQLiteStudio/common/objectpool.h index b9f6b9f..7330efc 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/objectpool.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/objectpool.h @@ -24,7 +24,7 @@ class ObjectPool }; template <class T> -ObjectPool::ObjectPool(quint32 min, quint32 max) +ObjectPool<T>::ObjectPool(quint32 min, quint32 max) : min(min), max(max) { Q_ASSERT(min > 0); @@ -36,7 +36,8 @@ ObjectPool::ObjectPool(quint32 min, quint32 max) } } -T* ObjectPool::reserve() +template <class T> +T* ObjectPool<T>::reserve() { mutex.lock(); @@ -73,7 +74,7 @@ T* ObjectPool::reserve() } template <class T> -void ObjectPool::release(T* obj) +void ObjectPool<T>::release(T* obj) { mutex.lock(); pool[obj] = false; diff --git a/SQLiteStudio3/coreSQLiteStudio/common/sortedhash.h b/SQLiteStudio3/coreSQLiteStudio/common/sortedhash.h index 9ca6ade..c0d44b6 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/sortedhash.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/sortedhash.h @@ -74,7 +74,7 @@ class SortedHash : public QHash<Key, T> QList<Key> keys(const T& value) const
{
QList<Key> results;
- foreach (const Key& k, sortedKeys)
+ for (const Key& k : sortedKeys)
if (value(k) == value)
results << k;
@@ -98,7 +98,7 @@ class SortedHash : public QHash<Key, T> QList<T> values() const
{
QList<T> results;
- foreach (const Key& k, sortedKeys)
+ for (const Key& k : sortedKeys)
results << value(k);
return results;
diff --git a/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp b/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp index e3d2e47..fd40355 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp @@ -311,7 +311,7 @@ QStringList tokenizeArgs(const QString& str) QStringList prefixEach(const QString& prefix, const QStringList& list) { QStringList result; - foreach (const QString& item, list) + for (const QString& item : list) result << (prefix + item); return result; @@ -385,7 +385,7 @@ QString longest(const QStringList& strList) { int max = 0; QString result; - foreach (const QString str, strList) + for (const QString str : strList) { if (str.size() > max) { @@ -400,7 +400,7 @@ QString shortest(const QStringList& strList) { int max = INT_MAX; QString result; - foreach (const QString str, strList) + for (const QString str : strList) { if (str.size() < max) { @@ -421,7 +421,7 @@ QString longestCommonPart(const QStringList& strList) for (int i = 0; i < first.length(); i++) { common += first[i]; - foreach (const QString& str, strList) + for (const QString& str : strList) { if (!str.startsWith(common)) return common.left(i); @@ -434,7 +434,7 @@ QStringList applyMargin(const QString& str, int margin) { QStringList lines; QString line; - foreach (QString word, str.split(" ")) + for (QString word : str.split(" ")) { if (((line + word).length() + 1) > margin) { @@ -694,9 +694,11 @@ QString getOsString() case QSysInfo::WV_WINDOWS8_1: os += " 8.1"; break; +#if QT_VERSION >= 0x050500 case QSysInfo::WV_WINDOWS10: os += " 10"; break; +#endif case QSysInfo::WV_32s: case QSysInfo::WV_95: case QSysInfo::WV_98: @@ -710,7 +712,9 @@ QString getOsString() case QSysInfo::WV_CE_5: case QSysInfo::WV_CE_6: case QSysInfo::WV_CE_based: +#if QT_VERSION >= 0x050500 case QSysInfo::WV_None: +#endif break; } #elif defined(Q_OS_LINUX) @@ -752,6 +756,9 @@ QString getOsString() case QSysInfo::MV_10_11: os += " 10.11 El Capitan"; break; + case QSysInfo::MV_10_12: + os += " 10.12 Sierra"; + break; case QSysInfo::MV_9: case QSysInfo::MV_10_0: case QSysInfo::MV_10_1: @@ -816,6 +823,42 @@ bool isHex(const QString& str) return ok; } +bool isHex(const QChar& c) +{ + return isHex(c.toLatin1()); +} + +bool isHex(const char c) +{ + switch (c) + { + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + case 'd': + case 'D': + case 'e': + case 'E': + case 'f': + case 'F': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return true; + } + return false; +} + QString formatVersion(int version) { int majorVer = version / 10000; @@ -916,9 +959,18 @@ QStringList concat(const QList<QStringList>& list) return result; } + QString doubleToString(const QVariant& val) { - return val.toString(); + QString str = val.toString(); + if (str.contains("e")) + str = QString::number(val.toDouble(), 'f', 14).remove(QRegExp("0*$")); + else if (!str.contains('.')) + str += ".0"; + else if (str.mid(str.indexOf('.') + 1).length() > 14) + str = QString::number(val.toDouble(), 'f', 14).remove(QRegExp("0*$")); + + return str; } void sortWithReferenceList(QList<QString>& listToSort, const QList<QString>& referenceList, Qt::CaseSensitivity cs) @@ -941,3 +993,41 @@ void sortWithReferenceList(QList<QString>& listToSort, const QList<QString>& ref return (idx1 > idx2); }); } + +QByteArray serializeToBytes(const QVariant& value) +{ + QByteArray bytes; + QDataStream stream(&bytes, QIODevice::WriteOnly); + stream << value; + return bytes; +} + +QVariant deserializeFromBytes(const QByteArray& bytes) +{ + if (bytes.isNull()) + return QVariant(); + + QVariant deserializedValue; + QDataStream stream(bytes); + stream >> deserializedValue; + return deserializedValue; +} + +QString readFileContents(const QString& path, QString* err) +{ + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + if (err) + *err = QObject::tr("Could not open file '%1' for reading: %2").arg(path).arg(file.errorString()); + + return QString(); + } + + QTextStream stream(&file); + stream.setCodec("UTF-8"); + QString contents = stream.readAll(); + file.close(); + + return contents; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/common/utils.h b/SQLiteStudio3/coreSQLiteStudio/common/utils.h index c56a4db..24ea150 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils.h @@ -9,6 +9,8 @@ #include <QStringList> #include <QFileInfo> #include <functional> +#include <QVariant> +#include <QDataStream> class QTextCodec; @@ -236,6 +238,8 @@ API_EXPORT int sum(const QList<int>& integers); API_EXPORT QString getOsString(); API_EXPORT bool validateEmail(const QString& email); API_EXPORT bool isHex(const QString& str); +API_EXPORT bool isHex(const QChar& c); +API_EXPORT bool isHex(const char c); API_EXPORT QString formatVersion(int version); API_EXPORT bool copyRecursively(const QString& src, const QString& dst); API_EXPORT bool renameBetweenPartitions(const QString& src, const QString& dst); @@ -289,6 +293,12 @@ void removeDuplicates(QList<T>& list) } } +API_EXPORT QByteArray serializeToBytes(const QVariant& value); + +API_EXPORT QVariant deserializeFromBytes(const QByteArray& bytes); + +API_EXPORT QString readFileContents(const QString& path, QString* err); + Q_DECLARE_METATYPE(QList<int>) #endif // UTILS_H diff --git a/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp b/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp index ad37ff0..b5642ec 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp @@ -12,7 +12,8 @@ #include <QMetaType> QString invalidIdCharacters = "[]()\"'@*.,+-=/%&|:; \t\n<>"; -QHash<NameWrapper,QPair<QChar,QChar> > wrapperChars; +QHash<NameWrapper,QPair<QChar,QChar>> wrapperChars; +QHash<NameWrapper,QPair<QChar,bool>> wrapperEscapedEnding; QList<NameWrapper> sqlite3Wrappers; QList<NameWrapper> sqlite2Wrappers; @@ -23,6 +24,11 @@ void initUtilsSql() wrapperChars[NameWrapper::BACK_QUOTE] = QPair<QChar,QChar>('`', '`'); wrapperChars[NameWrapper::DOUBLE_QUOTE] = QPair<QChar,QChar>('"', '"'); + wrapperEscapedEnding[NameWrapper::BRACKET] = QPair<QChar,bool>(']', false); + wrapperEscapedEnding[NameWrapper::QUOTE] = QPair<QChar,bool>('\'', true); + wrapperEscapedEnding[NameWrapper::BACK_QUOTE] = QPair<QChar,bool>('`', true); + wrapperEscapedEnding[NameWrapper::DOUBLE_QUOTE] = QPair<QChar,bool>('"', true); + sqlite3Wrappers << NameWrapper::DOUBLE_QUOTE << NameWrapper::BRACKET << NameWrapper::QUOTE @@ -129,7 +135,7 @@ QPair<QChar,QChar> getQuoteCharacter(QString& obj, Dialect dialect, NameWrapper } QPair<QChar,QChar> wrapChars; - foreach (NameWrapper wrapper, wrappers) + for (NameWrapper wrapper : wrappers) { wrapChars = wrapperChars[wrapper]; if (obj.indexOf(wrapChars.first) > -1) @@ -277,6 +283,23 @@ bool isObjWrapped(const QString& str, Dialect dialect) return getObjWrapper(str, dialect) != NameWrapper::null; } +bool doesNotContainEndingWrapperChar(const QString& str, NameWrapper wrapper) +{ + QString innerPart = str.mid(1, str.length() - 2); + const QChar& endingChar = wrapperEscapedEnding[wrapper].first; + bool escapingAllowed = wrapperEscapedEnding[wrapper].second; + int idx = -1; + int lastIdx = innerPart.length() - 1; + while ((idx = innerPart.indexOf(endingChar, idx + 1)) > -1) + { + if (idx == lastIdx || !escapingAllowed || innerPart[idx + 1] != endingChar) + return false; + + idx++; // we had occurrence, but it was escaped, so we need to skip the second (escape) char + } + return true; +} + NameWrapper getObjWrapper(const QString& str, Dialect dialect) { if (str.isEmpty()) @@ -289,10 +312,10 @@ NameWrapper getObjWrapper(const QString& str, Dialect dialect) else wrappers = sqlite3Wrappers; - foreach (NameWrapper wrapper, wrappers) + for (NameWrapper wrapper : wrappers) { QPair<QChar,QChar> chars = wrapperChars[wrapper]; - if (str[0] == chars.first && str[str.length()-1] == chars.second) + if (str[0] == chars.first && str[str.length()-1] == chars.second && doesNotContainEndingWrapperChar(str, wrapper)) return wrapper; } return NameWrapper::null; @@ -306,7 +329,7 @@ bool isWrapperChar(const QChar& c, Dialect dialect) else wrappers = sqlite3Wrappers; - foreach (NameWrapper wrapper, wrappers) + for (NameWrapper wrapper : wrappers) { QPair<QChar,QChar> chars = wrapperChars[wrapper]; if (c == chars.first || c == chars.second) @@ -389,7 +412,7 @@ QList<TokenList> splitQueries(const TokenList& tokenizedQuery, bool* complete) int createTriggerMeter = 0; bool insideTrigger = false; bool completeQuery = false; - foreach (const TokenPtr& token, tokenizedQuery) + for (const TokenPtr& token : tokenizedQuery) { value = token->value.toUpper(); if (!token->isWhitespace()) @@ -556,7 +579,7 @@ QStringList splitQueries(const QString& sql, Dialect dialect, bool keepEmptyQuer QString query; QStringList queries; - foreach (const TokenList& queryTokens, tokenizedQueries) + for (const TokenList& queryTokens : tokenizedQueries) { query = queryTokens.detokenize(); if (keepEmptyQueries || (!query.trimmed().isEmpty() && query.trimmed() != ";")) @@ -627,10 +650,10 @@ QList<QueryWithParamNames> getQueriesWithParamNames(const QString& query, Dialec QString queryStr; QStringList paramNames; - foreach (const TokenList& tokens, queries) + for (const TokenList& tokens : queries) { paramNames.clear(); - foreach (const TokenPtr& token, tokens.filter(Token::BIND_PARAM)) + for (const TokenPtr& token : tokens.filter(Token::BIND_PARAM)) paramNames << token->value; queryStr = tokens.detokenize().trimmed(); @@ -648,7 +671,7 @@ QList<QueryWithParamCount> getQueriesWithParamCount(const QString& query, Dialec QList<TokenList> queries = splitQueries(allTokens); QString queryStr; - foreach (const TokenList& tokens, queries) + for (const TokenList& tokens : queries) { queryStr = tokens.detokenize().trimmed(); if (!queryStr.isEmpty()) @@ -663,7 +686,7 @@ QueryWithParamNames getQueryWithParamNames(const QString& query, Dialect dialect TokenList allTokens = Lexer::tokenize(query, dialect); QStringList paramNames; - foreach (const TokenPtr& token, allTokens.filter(Token::BIND_PARAM)) + for (const TokenPtr& token : allTokens.filter(Token::BIND_PARAM)) paramNames << token->value; return QueryWithParamNames(query, paramNames); diff --git a/SQLiteStudio3/coreSQLiteStudio/common/valuelocker.h b/SQLiteStudio3/coreSQLiteStudio/common/valuelocker.h new file mode 100644 index 0000000..a757506 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/valuelocker.h @@ -0,0 +1,44 @@ +#ifndef VALUELOCKER_H +#define VALUELOCKER_H + +/** + * ValueLocker is similar to QMutexLocker, but it's not intended for multithreaded locks. + * It's rather for event loop locking. + * It can be created as local scope variable with a pointer to member variable. + * It will set "unlockedValue" to that variable once the locker is destroyed (goes out of scope). + * Usually the variable used will be of boolean type, but it can be virtually any other type. + * You can also provide initial value for locked state. Otherwise you will need to set the locked + * by yourself before the lock is created. + */ +template <class T> +class ValueLocker { + public: + ValueLocker(T* valueToLock, const T& lockedValue, const T& unlockedValue); + ValueLocker(T* valueToLock, const T& unlockedValue); + ~ValueLocker(); + + private: + T* valueToLock; + T unlockedValue; +}; + +template<class T> +ValueLocker<T>::ValueLocker(T *valueToLock, const T &lockedValue, const T &unlockedValue) : + ValueLocker(valueToLock, unlockedValue) +{ + *valueToLock = lockedValue; +} + +template<class T> +ValueLocker<T>::ValueLocker(T *valueToLock, const T &unlockedValue) : + valueToLock(valueToLock), unlockedValue(unlockedValue) +{ +} + +template<class T> +ValueLocker<T>::~ValueLocker() +{ + *valueToLock = unlockedValue; +} + +#endif // VALUELOCKER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.cpp b/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.cpp new file mode 100644 index 0000000..7c86088 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.cpp @@ -0,0 +1,84 @@ +/*#include "xmldeserializer.h"
+#include "unused.h"
+#include <QDebug>
+
+XmlDeserializer::XmlDeserializer()
+{
+}
+
+QHash<QString, QVariant> XmlDeserializer::deserialize(QIODevice *input)
+{
+ QXmlStreamReader reader(input);
+ return deserialize(reader);
+}
+
+QHash<QString, QVariant> XmlDeserializer::deserialize(const QString &input)
+{
+ QXmlStreamReader reader(input);
+ return deserialize(reader);
+}
+
+QHash<QString, QVariant> XmlDeserializer::deserialize(QXmlStreamReader &reader)
+{
+ ctxStack.clear();
+ output.clear();
+ ctx = &output;
+
+ QXmlStreamReader::TokenType tokenType;
+ while ((tokenType = reader.readNext()) != QXmlStreamReader::EndDocument)
+ handleTokenType(reader, tokenType);
+
+ return output;
+}
+
+void XmlDeserializer::handleTokenType(QXmlStreamReader& reader, QXmlStreamReader::TokenType tokenType)
+{
+ switch (tokenType)
+ {
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::EndDocument:
+ case QXmlStreamReader::DTD:
+ case QXmlStreamReader::NoToken:
+ case QXmlStreamReader::ProcessingInstruction:
+ case QXmlStreamReader::StartDocument:
+ case QXmlStreamReader::EntityReference:
+ break;
+ case QXmlStreamReader::Invalid:
+ qDebug() << "Invalid token while parsing XML:" << reader.errorString();
+ break;
+ case QXmlStreamReader::StartElement:
+ handleStartElement(reader);
+ break;
+ case QXmlStreamReader::Characters:
+ handleText(reader);
+ break;
+ case QXmlStreamReader::EndElement:
+ handleEndElement(reader);
+ break;
+ }
+}
+
+void XmlDeserializer::handleStartElement(QXmlStreamReader &reader)
+{
+ QString key = reader.name().toString();
+ QHash<QString, QVariant> newCtx;
+ ctx->insertMulti(key, newCtx);
+
+ for (const QXmlStreamAttribute& attr : reader.attributes())
+ ctx->insertMulti(attr.name().toString(), attr.value().toString());
+
+ ctxStack.push(ctx);
+ ctx = &((*ctx)[key]);
+}
+
+void XmlDeserializer::handleText(QXmlStreamReader &reader)
+{
+ ctx->insertMulti(QString(), reader.text().toString());
+}
+
+void XmlDeserializer::handleEndElement(QXmlStreamReader &reader)
+{
+ UNUSED(reader);
+ ctx = ctxStack.pop();
+}
+*/
diff --git a/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.h b/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.h new file mode 100644 index 0000000..52761cf --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.h @@ -0,0 +1,31 @@ +/*#ifndef XMLDESERIALIZER_H
+#define XMLDESERIALIZER_H
+
+#include "coreSQLiteStudio_global.h"
+#include <QTextStream>
+#include <QXmlStreamReader>
+#include <QStack>
+#include <QHash>
+
+class API_EXPORT XmlDeserializer
+{
+ public:
+ XmlDeserializer();
+
+ QHash<QString,QVariant> deserialize(QIODevice* input);
+ QHash<QString,QVariant> deserialize(const QString& input);
+
+ private:
+ QHash<QString,QVariant> deserialize(QXmlStreamReader& reader);
+ void handleTokenType(QXmlStreamReader& reader, QXmlStreamReader::TokenType tokenType);
+ void handleStartElement(QXmlStreamReader& reader);
+ void handleText(QXmlStreamReader& reader);
+ void handleEndElement(QXmlStreamReader& reader);
+
+ QHash<QString, QVariant> output;
+ QHash<QString, QVariant>* ctx;
+ QStack<QHash<QString, QVariant>*> ctxStack;
+};
+
+#endif // XMLDESERIALIZER_H
+*/
diff --git a/SQLiteStudio3/coreSQLiteStudio/completioncomparer.cpp b/SQLiteStudio3/coreSQLiteStudio/completioncomparer.cpp index 978395f..ae64de8 100644 --- a/SQLiteStudio3/coreSQLiteStudio/completioncomparer.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/completioncomparer.cpp @@ -72,7 +72,7 @@ void CompletionComparer::init() contextDatabases = helper->originalParsedQuery->getContextDatabases(false); } - foreach (SelectResolver::Table table, helper->selectAvailableTables + helper->parentSelectAvailableTables) + for (SelectResolver::Table table : helper->selectAvailableTables + helper->parentSelectAvailableTables) availableTableNames += table.table; } } @@ -88,7 +88,7 @@ bool CompletionComparer::initSelect() contextTables = helper->originalCurrentSelectCore->getContextTables(false); contextDatabases = helper->originalCurrentSelectCore->getContextDatabases(false); - foreach (SqliteSelect::Core* core, helper->parentSelectCores) + for (SqliteSelect::Core* core : helper->parentSelectCores) { parentContextColumns += core->getContextColumns(false); parentContextTables += core->getContextTables(false); @@ -403,7 +403,7 @@ bool CompletionComparer::isTokenOnResultColumns(const ExpectedTokenPtr &token) bool CompletionComparer::isTokenOnColumnList(const ExpectedTokenPtr &token, const QList<SelectResolver::Column> &columnList) { - foreach (SelectResolver::Column column, columnList) + for (SelectResolver::Column column : columnList) { // If column name doesn't match, then it's not this column if (token->value.compare(column.column, Qt::CaseInsensitive) != 0) diff --git a/SQLiteStudio3/coreSQLiteStudio/completionhelper.cpp b/SQLiteStudio3/coreSQLiteStudio/completionhelper.cpp index aae4a60..f0d00a1 100644 --- a/SQLiteStudio3/coreSQLiteStudio/completionhelper.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/completionhelper.cpp @@ -149,7 +149,7 @@ CompletionHelper::Results CompletionHelper::getExpectedTokens() // Convert accepted tokens to expected tokens QList<ExpectedTokenPtr> results; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) results += getExpectedTokens(token); // Filter redundant tokens from results @@ -233,7 +233,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getExpectedTokens(TokenPtr token) break; case Token::CTX_FK_MATCH: { - foreach (QString kw, getFkMatchKeywords()) + for (QString kw : getFkMatchKeywords()) results += getExpectedToken(ExpectedToken::KEYWORD, kw); break; @@ -296,7 +296,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getExpectedTokens(TokenPtr token) } case Token::CTX_JOIN_OPTS: { - foreach (QString joinKw, getJoinKeywords()) + for (QString joinKw : getJoinKeywords()) results += getExpectedToken(ExpectedToken::KEYWORD, joinKw); break; } @@ -486,7 +486,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getDatabases() results += getExpectedToken(ExpectedToken::DATABASE, "temp", "temp", tr("Temporary objects database")); QSet<QString> databases = schemaResolver->getDatabases(); - foreach (QString dbName, databases) + for (QString dbName : databases) { if (dbAttacher->getDbNameToAttach().containsRight(dbName, Qt::CaseInsensitive)) continue; @@ -496,7 +496,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getDatabases() Dialect dialect = db->getDialect(); - foreach (Db* otherDb, DBLIST->getValidDbList()) + for (Db* otherDb : DBLIST->getValidDbList()) { if (otherDb->getDialect() != dialect) continue; @@ -546,7 +546,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getObjects(ExpectedToken::Type type, c } QList<ExpectedTokenPtr> results; - foreach (QString object, schemaResolver->getObjects(dbName, typeStr)) + for (QString object : schemaResolver->getObjects(dbName, typeStr)) results << getExpectedToken(type, object, originalDbName); return results; @@ -599,8 +599,8 @@ QList<ExpectedTokenPtr> CompletionHelper::getColumnsNoPrefix() // Getting all tables for main db. If any column repeats in many tables, // then tables are stored as a list for the same column. - foreach (QString table, schemaResolver->getTables(QString::null)) - foreach (QString column, schemaResolver->getTableColumns(table)) + for (QString table : schemaResolver->getTables(QString::null)) + for (QString column : schemaResolver->getTableColumns(table)) columnList[column] += table; // Now, for each column the expected token is created. @@ -621,7 +621,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getColumnsNoPrefix(const QString& colu QList<ExpectedTokenPtr> results; QStringList availableTableNames; - foreach (SelectResolver::Table resolverTable, selectAvailableTables + parentSelectAvailableTables) + for (SelectResolver::Table resolverTable : selectAvailableTables + parentSelectAvailableTables) { // This method is called only when collecting columns of tables in "main" database. // If here we have resolved table from other database, we don't compare it. @@ -632,11 +632,11 @@ QList<ExpectedTokenPtr> CompletionHelper::getColumnsNoPrefix(const QString& colu } int availableTableCount = 0; - foreach (QString availTable, availableTableNames) + for (QString availTable : availableTableNames) if (tables.contains(availTable)) availableTableCount++; - foreach (QString table, tables) + for (QString table : tables) { // Table prefix is used only if there is more than one table in FROM clause // that has this column, or table alias was used. @@ -649,10 +649,10 @@ QList<ExpectedTokenPtr> CompletionHelper::getColumnsNoPrefix(const QString& colu QString label = table; if (tableToAlias.contains(prefix)) { - foreach (prefix, tableToAlias[prefix]) + for (const QString& resolvedPrefix : tableToAlias[prefix]) { - label = prefix+" = "+table; - results << getExpectedToken(ExpectedToken::COLUMN, column, table, label, prefix); + label = resolvedPrefix+" = "+table; + results << getExpectedToken(ExpectedToken::COLUMN, column, table, label, resolvedPrefix); } } else @@ -700,7 +700,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getColumns(const QString &prefixTable) } // Get columns for given table in main db. - foreach (const QString& column, schemaResolver->getTableColumns(dbName, table)) + for (const QString& column : schemaResolver->getTableColumns(dbName, table)) results << getExpectedToken(ExpectedToken::COLUMN, column, table, label); return results; @@ -712,7 +712,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getColumns(const QString &prefixDb, co // Get columns for given table in given db. QString context = prefixDb+"."+prefixTable; - foreach (const QString& column, schemaResolver->getTableColumns(translateDatabase(prefixDb), prefixTable)) + for (const QString& column : schemaResolver->getTableColumns(translateDatabase(prefixDb), prefixTable)) results << getExpectedToken(ExpectedToken::COLUMN, column, context); return results; @@ -724,7 +724,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getFavoredColumns(const QList<Expected // Since results so far have more chance to provide context into, we will keep the original ones // from results so far and avoid adding then from favored list. QStringList columnsToAdd = favoredColumnNames; - foreach (const ExpectedTokenPtr& token, resultsSoFar) + for (const ExpectedTokenPtr& token : resultsSoFar) { if (token->prefix.isNull() && columnsToAdd.contains(token->value)) columnsToAdd.removeOne(token->value); @@ -735,7 +735,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getFavoredColumns(const QList<Expected ctxInfo = parsedQuery.dynamicCast<SqliteCreateTable>()->table; QList<ExpectedTokenPtr> results; - foreach (const QString& column, columnsToAdd) + for (const QString& column : columnsToAdd) results << getExpectedToken(ExpectedToken::COLUMN, column, ctxInfo); return results; @@ -760,7 +760,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getFunctions(Db* db) functions << fn->toString(); QList<ExpectedTokenPtr> expectedTokens; - foreach (QString function, functions) + for (QString function : functions) expectedTokens += getExpectedToken(ExpectedToken::FUNCTION, function); return expectedTokens; @@ -775,7 +775,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getPragmas(Dialect dialect) pragmas = sqlite3Pragmas; QList<ExpectedTokenPtr> expectedTokens; - foreach (QString pragma, pragmas) + for (QString pragma : pragmas) expectedTokens += getExpectedToken(ExpectedToken::PRAGMA, pragma); return expectedTokens; @@ -790,7 +790,7 @@ QList<ExpectedTokenPtr> CompletionHelper::getCollations() << results->getErrorText(); } QList<ExpectedTokenPtr> expectedTokens; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) expectedTokens += getExpectedToken(ExpectedToken::COLLATION, row->value("name").toString()); return expectedTokens; @@ -911,7 +911,7 @@ void CompletionHelper::filterContextKeywords(QList<ExpectedTokenPtr> &resultsSoF { bool wasJoinKw = false; bool wasFkMatchKw = false; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) { if (token->type == Token::CTX_JOIN_OPTS) wasJoinKw = true; @@ -941,7 +941,7 @@ void CompletionHelper::filterContextKeywords(QList<ExpectedTokenPtr> &resultsSoF void CompletionHelper::filterOtherId(QList<ExpectedTokenPtr> &resultsSoFar, const TokenList &tokens) { bool wasCtx = false; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) { switch (token->type) { @@ -1273,7 +1273,7 @@ bool CompletionHelper::testQueryToken(int tokenPosition, Token::Type type, const bool CompletionHelper::cursorAfterTokenMaps(SqliteStatement* stmt, const QStringList& mapNames) { TokenList tokens; - foreach (const QString& name, mapNames) + for (const QString& name : mapNames) { if (!stmt->tokensMap.contains(name) || stmt->tokensMap[name].size() == 0) continue; @@ -1292,7 +1292,7 @@ bool CompletionHelper::cursorAfterTokenMaps(SqliteStatement* stmt, const QString bool CompletionHelper::cursorBeforeTokenMaps(SqliteStatement* stmt, const QStringList& mapNames) { TokenList tokens; - foreach (const QString& name, mapNames) + for (const QString& name : mapNames) { if (!stmt->tokensMap.contains(name) || stmt->tokensMap[name].size() == 0) continue; @@ -1391,7 +1391,7 @@ void CompletionHelper::extractSelectAvailableColumnsAndTables() void CompletionHelper::extractTableAliasMap() { - foreach (SelectResolver::Column column, selectAvailableColumns) + for (SelectResolver::Column column : selectAvailableColumns) { if (column.type != SelectResolver::Column::COLUMN) continue; @@ -1407,7 +1407,7 @@ void CompletionHelper::extractTableAliasMap() // Given the above, we can extract table aliases in an order from deepest // to shallowest, skipping any duplicates, becase the deeper alias is mentioned, // the higher is its priority. - foreach (SelectResolver::Column column, parentSelectAvailableColumns) + for (SelectResolver::Column column : parentSelectAvailableColumns) { if (column.type != SelectResolver::Column::COLUMN) continue; @@ -1429,7 +1429,7 @@ void CompletionHelper::extractCreateTableColumns() return; SqliteCreateTablePtr createTable = parsedQuery.dynamicCast<SqliteCreateTable>(); - foreach (SqliteCreateTable::Column* col, createTable->columns) + for (SqliteCreateTable::Column* col : createTable->columns) favoredColumnNames << col->name; } diff --git a/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.cpp b/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.cpp index fb7d199..0c7295a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.cpp @@ -2,6 +2,7 @@ #include "config_builder/cfgcategory.h" #include "config_builder/cfgentry.h" #include "common/global.h" +#include <QDebug> CfgMain* lastCreatedCfgMain = nullptr; QList<CfgMain*>* CfgMain::instances = nullptr; @@ -153,6 +154,39 @@ QList<CfgEntry *> CfgMain::getEntries() const return entries; } +void CfgMain::setValuesFromQVariant(const QVariant& cfgMainHash) +{ + QHash<QString, QVariant> mainHash = cfgMainHash.toHash(); + if (mainHash.isEmpty()) + return; + + QHash<QString, QVariant>::const_iterator mainIt = mainHash.begin(); + if (mainIt.key() != name) + { + qWarning() << "Tried to set CfgMain values from QVariant which does not have such main in its registry."; + return; + } + + QHash<QString, QVariant> categoriesHash = mainIt.value().toHash(); + QHash<QString, QVariant> entriesHash; + QHash<QString, CfgEntry*> entries; + for (QHash<QString, CfgCategory*>::const_iterator categoryIt = childs.begin(); categoryIt != childs.end(); categoryIt++) + { + if (!categoriesHash.contains(categoryIt.key())) + continue; + + entriesHash = categoriesHash[categoryIt.key()].toHash(); + entries = categoryIt.value()->getEntries(); + for (QHash<QString, CfgEntry*>::const_iterator entryIt = entries.begin(); entryIt != entries.end(); entryIt++) + { + if (!entriesHash.contains(entryIt.key())) + continue; + + entryIt.value()->set(entriesHash[entryIt.key()]); + } + } +} + bool CfgMain::isPersistable() const { return persistable; @@ -173,6 +207,26 @@ QString CfgMain::getTitle() const return title; } +QVariant CfgMain::toQVariant() const +{ + QHash<QString, QVariant> categoriesVariant; + QHash<QString, QVariant> entriesVariant; + QHash<QString, CfgEntry*> entries; + for (QHash<QString, CfgCategory*>::const_iterator categoryIt = childs.begin(); categoryIt != childs.end(); categoryIt++) + { + entries = categoryIt.value()->getEntries(); + entriesVariant.clear(); + for (QHash<QString, CfgEntry*>::const_iterator entryIt = entries.begin(); entryIt != entries.end(); entryIt++) + entriesVariant[entryIt.key()] = entryIt.value()->get(); + + categoriesVariant[categoryIt.key()] = entriesVariant; + } + + QHash<QString, QVariant> mainVariant; + mainVariant[name] = categoriesVariant; + return mainVariant; +} + CfgMain::operator CfgMain*() { return this; diff --git a/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.h b/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.h index ea11c6d..4e84bef 100644 --- a/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.h +++ b/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.h @@ -37,12 +37,27 @@ class API_EXPORT CfgMain QStringList getPaths() const; QList<CfgEntry*> getEntries() const; + /** + * @brief Accepts QVariant produced by toQVariant(). + * + * This method assumes that the QVariant is actually a multi-level QHash + * produced by toQVariant() method. + * It sets all values recursivly using values from provided QVariant. + */ + void setValuesFromQVariant(const QVariant& cfgMainHash); + bool isPersistable() const; QString getName() const; const char* getMetaName() const; QString getTitle() const; operator CfgMain*(); + /** + * @brief Serializes this CfgMain to recursive QHash. + * @return Recursive QHash, where top level has one entry (name of CfgMain), then next level has keys as CfgCategory names, and last one has keys as CfgEntry names. + */ + QVariant toQVariant() const; + private: QString name; const char* metaName; diff --git a/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.pro b/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.pro index 8c3c21a..3eba953 100644 --- a/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.pro +++ b/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.pro @@ -18,8 +18,7 @@ TARGET = coreSQLiteStudio TEMPLATE = lib
win32 {
- LIBS += -lpsapi $$PWD/../../../lib/libquazip.a
- LIBS += -limagehlp
+ LIBS += -lpsapi -limagehlp
THE_FILE = $$PWD/qt.conf
THE_DEST = $${DESTDIR}
@@ -41,6 +40,7 @@ macx: { QMAKE_POST_LINK += ; $$QMAKE_MKDIR $$DESTDIR/SQLiteStudio.app
QMAKE_POST_LINK += ; $$QMAKE_MKDIR $$DESTDIR/SQLiteStudio.app/Contents
QMAKE_POST_LINK += ; $$QMAKE_COPY $$PWD/Info.plist $$DESTDIR/SQLiteStudio.app/Contents
+ LIBS += -L/usr/local/lib
}
LIBS += -lsqlite3
@@ -54,7 +54,8 @@ portable { CONFIG += c++11
QMAKE_CXXFLAGS += -pedantic
-TRANSLATIONS += translations/coreSQLiteStudio_de.ts \
+TRANSLATIONS += translations/coreSQLiteStudio_ro_RO.ts \
+ translations/coreSQLiteStudio_de.ts \
translations/coreSQLiteStudio_it.ts \
translations/coreSQLiteStudio_zh_CN.ts \
translations/coreSQLiteStudio_sk.ts \
@@ -206,7 +207,6 @@ SOURCES += sqlitestudio.cpp \ plugins/builtinplugin.cpp \
plugins/scriptingqtdbproxy.cpp \
plugins/sqlformatterplugin.cpp \
- services/bugreporter.cpp \
services/updatemanager.cpp \
config_builder/cfgmain.cpp \
config_builder/cfgcategory.cpp \
@@ -227,7 +227,11 @@ SOURCES += sqlitestudio.cpp \ common/private/blockingsocketprivate.cpp \
querygenerator.cpp \
common/bistrhash.cpp \
- plugins/dbpluginstdfilebase.cpp
+ plugins/dbpluginstdfilebase.cpp \
+ common/xmldeserializer.cpp \
+ services/impl/sqliteextensionmanagerimpl.cpp \
+ common/lazytrigger.cpp \
+ parser/ast/sqliteupsert.cpp
HEADERS += sqlitestudio.h\
coreSQLiteStudio_global.h \
@@ -397,7 +401,6 @@ HEADERS += sqlitestudio.h\ plugins/builtinplugin.h \
plugins/scriptingqtdbproxy.h \
plugins/codeformatterplugin.h \
- services/bugreporter.h \
services/updatemanager.h \
config_builder/cfgmain.h \
config_builder/cfgcategory.h \
@@ -424,7 +427,13 @@ HEADERS += sqlitestudio.h\ parser/ast/sqliteextendedindexedcolumn.h \
querygenerator.h \
common/sortedset.h \
- plugins/dbpluginstdfilebase.h
+ plugins/dbpluginstdfilebase.h \
+ common/xmldeserializer.h \
+ common/valuelocker.h \
+ services/sqliteextensionmanager.h \
+ services/impl/sqliteextensionmanagerimpl.h \
+ common/lazytrigger.h \
+ parser/ast/sqliteupsert.h
unix: {
target.path = $$LIBDIR
@@ -433,6 +442,7 @@ unix: { OTHER_FILES += \
parser/lempar.c \
+ parser/lemon.c \
parser/sqlite3_parse.y \
parser/sqlite2_parse.y \
parser/run_lemon.sh \
@@ -444,8 +454,9 @@ OTHER_FILES += \ licenses/diff_match.txt \
licenses/gpl.txt \
ChangeLog.txt \
- qt.conf
\ - Info.plist + qt.conf
+ \
+ Info.plist
FORMS += \
plugins/populatesequence.ui \
@@ -458,6 +469,10 @@ FORMS += \ RESOURCES += \
coreSQLiteStudio.qrc
+DISTFILES += \
+ licenses/mit.txt
+
+
diff --git a/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.qrc b/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.qrc index d58efc1..f0bc89f 100644 --- a/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.qrc +++ b/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.qrc @@ -17,8 +17,10 @@ <file>licenses/lgpl.txt</file> <file>licenses/diff_match.txt</file> <file>licenses/gpl.txt</file> + <file>licenses/mit.txt</file> </qresource> <qresource prefix="/msg"> + <file>translations/coreSQLiteStudio_ro_RO.qm</file> <file>translations/coreSQLiteStudio_pl.qm</file> <file>translations/coreSQLiteStudio_ru.qm</file> <file>translations/coreSQLiteStudio_fr.qm</file> @@ -27,6 +29,3 @@ <file>translations/coreSQLiteStudio_de.qm</file> </qresource> </RCC> - - - diff --git a/SQLiteStudio3/coreSQLiteStudio/csvformat.cpp b/SQLiteStudio3/coreSQLiteStudio/csvformat.cpp index 151fffd..c5019c3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/csvformat.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/csvformat.cpp @@ -10,6 +10,7 @@ CsvFormat::CsvFormat() CsvFormat::CsvFormat(const QString& columnSeparator, const QString& rowSeparator) : columnSeparator(columnSeparator), rowSeparator(rowSeparator) { + calculateSeparatorMaxLengths(); } CsvFormat::CsvFormat(const QStringList &columnSeparators, const QStringList &rowSeparators) @@ -31,9 +32,23 @@ CsvFormat::CsvFormat(const QStringList &columnSeparators, const QStringList &row } else if (columnSeparators.size() > 0) this->columnSeparator = columnSeparators.first(); + + calculateSeparatorMaxLengths(); } CsvFormat::CsvFormat(const QString& columnSeparator, const QString& rowSeparator, bool strictRowSeparator, bool strictColumnSeparator) : columnSeparator(columnSeparator), rowSeparator(rowSeparator), strictColumnSeparator(strictColumnSeparator), strictRowSeparator(strictRowSeparator) { + calculateSeparatorMaxLengths(); +} + +void CsvFormat::calculateSeparatorMaxLengths() +{ + maxColumnSeparatorLength = columnSeparator.length(); + for (const QString& sep : columnSeparators) + maxColumnSeparatorLength = qMax(sep.length(), maxColumnSeparatorLength); + + maxRowSeparatorLength = rowSeparator.length(); + for (const QString& sep : rowSeparators) + maxRowSeparatorLength = qMax(sep.length(), maxRowSeparatorLength); } diff --git a/SQLiteStudio3/coreSQLiteStudio/csvformat.h b/SQLiteStudio3/coreSQLiteStudio/csvformat.h index 3e8dda2..4b6df69 100644 --- a/SQLiteStudio3/coreSQLiteStudio/csvformat.h +++ b/SQLiteStudio3/coreSQLiteStudio/csvformat.h @@ -12,6 +12,8 @@ struct API_EXPORT CsvFormat CsvFormat(const QStringList& columnSeparators, const QStringList& rowSeparators); CsvFormat(const QString& columnSeparator, const QString& rowSeparator, bool strictRowSeparator, bool strictColumnSeparator); + void calculateSeparatorMaxLengths(); + QString columnSeparator; QString rowSeparator; QStringList columnSeparators; @@ -20,6 +22,8 @@ struct API_EXPORT CsvFormat bool strictRowSeparator = false; bool multipleRowSeparators = false; bool multipleColumnSeparators = false; + int maxColumnSeparatorLength = 0; + int maxRowSeparatorLength = 0; static const CsvFormat DEFAULT; }; diff --git a/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp b/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp index ce568e9..4c4ed0e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp @@ -1,167 +1,193 @@ #include "csvserializer.h" #include <QStringList> +#include <QList> +#include <QDebug> +#include <QTime> -// TODO write unit tests for CsvSerializer +template <class C> +bool isCsvSeparator(QList<C>& ahead, const C& theChar, const QStringList& separators) +{ + for (const QString& sep : separators) + if (isCsvSeparator(ahead, theChar, sep)) + return true; + + return false; +} template <class C> -bool isCsvColumnSeparator(QTextStream& data, const C& theChar, const CsvFormat& format) +bool isCsvSeparator(QList<C>& ahead, const C& theChar, const QString& singleSeparator) +{ + if (singleSeparator[0] != theChar) + return false; + + typename QList<C>::const_iterator aheadIter = ahead.begin(); + int singleSeparatorSize = singleSeparator.size(); + int i = 1; + while (aheadIter != ahead.end() && i < singleSeparatorSize) + { + if (singleSeparator[i++] != *aheadIter++) + return false; + } + + if (i < singleSeparatorSize) + return false; + + for (int i = 1, total = singleSeparator.size(); i < total; ++i) + ahead.removeFirst(); + + return true; +} + +template <class C> +bool isCsvColumnSeparator(QList<C>& ahead, const C& theChar, const CsvFormat& format) { if (!format.strictColumnSeparator) return format.columnSeparator.contains(theChar); // Strict checking (characters in defined order make a separator) - QStringList separators; if (format.multipleColumnSeparators) - separators = format.columnSeparators; - else - separators << format.columnSeparator; + return isCsvSeparator(ahead, theChar, format.columnSeparators); - qint64 origPos = data.pos(); - bool match = true; - for (const QString sep : separators) - { - match = true; - data.seek(origPos - 1); - C nextChar; - for (const QChar& c : sep) - { - data >> nextChar; - if (c != nextChar) - { - data.seek(origPos); - match = false; - break; - } - } - if (match) - break; - } - - return match; + return isCsvSeparator(ahead, theChar, format.columnSeparator); } template <class C> -bool isCsvRowSeparator(QTextStream& data, const C& theChar, const CsvFormat& format) +bool isCsvRowSeparator(QList<C>& ahead, const C& theChar, const CsvFormat& format) { if (!format.strictRowSeparator) return format.rowSeparator.contains(theChar); // Strict checking (characters in defined order make a separator) - QStringList separators; if (format.multipleRowSeparators) - separators = format.rowSeparators; - else - separators << format.rowSeparator; + return isCsvSeparator(ahead, theChar, format.rowSeparators); + + return isCsvSeparator(ahead, theChar, format.rowSeparator); +} - qint64 origPos = data.pos(); - bool match = true; - for (const QString sep : separators) +template <class C> +void readAhead(QTextStream& data, QList<C>& ahead, int desiredSize) +{ + C singleValue; + while (!data.atEnd() && ahead.size() < desiredSize) { - match = true; - data.seek(origPos - 1); - C nextChar; - for (const QChar& c : sep) - { - data >> nextChar; - if (data.atEnd() || c != nextChar) - { - data.seek(origPos); - match = false; - break; - } - } - if (match) - break; + data >> singleValue; + ahead << singleValue; } - - return match; } template <class T, class C> -QList<QList<T>> typedDeserialize(QTextStream& data, const CsvFormat& format, bool oneEntry) +void typedDeserializeInternal(QTextStream& data, const CsvFormat& format, QList<T>* cells, QList<QList<T>>* rows) { - QList<QList<T>> rows; - QList<T> cells; - bool quotes = false; bool sepAsLast = false; + int separatorMaxAhead = qMax(format.maxColumnSeparatorLength, format.maxRowSeparatorLength) - 1; T field = ""; - C c0; - C c1; + field.reserve(3); + C theChar; + QList<C> ahead; - while (!data.atEnd()) + while (!data.atEnd() || !ahead.isEmpty()) { - data >> c0; + if (!ahead.isEmpty()) + theChar = ahead.takeFirst(); + else + data >> theChar; + sepAsLast = false; - if (!quotes && c0 == '"' ) + if (!quotes && theChar == '"' ) { quotes = true; } - else if (quotes && c0 == '"' ) + else if (quotes && theChar == '"' ) { if (!data.atEnd()) { - data >> c1; - if (c1 == '"' ) + readAhead(data, ahead, 1); + if (ahead.isEmpty()) + { + field += theChar; + } + else if (ahead.first() == '"' ) { - field += c0; + field += theChar; + ahead.removeFirst(); } else { quotes = false; - data.seek(data.pos() - 1); } } else { if (field.length() == 0) - cells << field; + *cells << field; quotes = false; } } else if (!quotes) { - if (isCsvColumnSeparator(data, c0, format)) + readAhead(data, ahead, separatorMaxAhead); + if (isCsvColumnSeparator(ahead, theChar, format)) { - cells << field; - field = ""; + *cells << field; + field.truncate(0); sepAsLast = true; } - else if (isCsvRowSeparator(data, c0, format)) + else if (isCsvRowSeparator(ahead, theChar, format)) { - cells << field; - rows << cells; - cells.clear(); - field = ""; - if (oneEntry) + *cells << field; + field.truncate(0); + if (rows) + { + *rows << *cells; + cells->clear(); + } + else + { break; + } } else { - field += c0; + field += theChar; } } else { - field += c0; + field += theChar; } } if (field.size() > 0 || sepAsLast) - cells << field; + *cells << field; - if (cells.size() > 0) - rows << cells; + if (rows && cells->size() > 0) + *rows << *cells; +} +template <class T, class C> +QList<QList<T>> typedDeserialize(QTextStream& data, const CsvFormat& format) +{ + QList<QList<T>> rows; + QList<T> cells; + typedDeserializeInternal<T, C>(data, format, &cells, &rows); return rows; } +template <class T, class C> +QList<T> typedDeserializeOneEntry(QTextStream& data, const CsvFormat& format) +{ + QList<T> cells; + typedDeserializeInternal<T, C>(data, format, &cells, nullptr); + return cells; +} + QString CsvSerializer::serialize(const QList<QStringList>& data, const CsvFormat& format) { QStringList outputRows; - foreach (const QStringList& dataRow, data) + for (const QStringList& dataRow : data) outputRows << serialize(dataRow, format); return outputRows.join(format.rowSeparator); @@ -172,7 +198,7 @@ QString CsvSerializer::serialize(const QStringList& data, const CsvFormat& forma QString value; bool hasQuote; QStringList outputCells; - foreach (const QString& rowValue, data) + for (const QString& rowValue : data) { value = rowValue; @@ -191,27 +217,19 @@ QString CsvSerializer::serialize(const QStringList& data, const CsvFormat& forma QStringList CsvSerializer::deserializeOneEntry(QTextStream& data, const CsvFormat& format) { - QList<QStringList> deserialized = CsvSerializer::deserialize(data, format, true); - if (deserialized.size() > 0) - return deserialized.first(); - - return QStringList(); -} - -QList<QStringList> CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format) -{ - return CsvSerializer::deserialize(data, format, false); + QList<QString> deserialized = typedDeserializeOneEntry<QString, QChar>(data, format); + return QStringList(deserialized); } QList<QList<QByteArray>> CsvSerializer::deserialize(const QByteArray& data, const CsvFormat& format) { QTextStream stream(data, QIODevice::ReadWrite); - return typedDeserialize<QByteArray,char>(stream, format, false); + return typedDeserialize<QByteArray,char>(stream, format); } -QList<QStringList> CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format, bool oneEntry) +QList<QStringList> CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format) { - QList<QList<QString>> deserialized = typedDeserialize<QString, QChar>(data, format, oneEntry); + QList<QList<QString>> deserialized = typedDeserialize<QString, QChar>(data, format); QList<QStringList> finalList; for (const QList<QString>& resPart : deserialized) @@ -224,6 +242,6 @@ QList<QStringList> CsvSerializer::deserialize(const QString& data, const CsvForm { QString dataString = data; QTextStream stream(&dataString, QIODevice::ReadWrite); - return deserialize(stream, format, false); + return deserialize(stream, format); } diff --git a/SQLiteStudio3/coreSQLiteStudio/csvserializer.h b/SQLiteStudio3/coreSQLiteStudio/csvserializer.h index 0b7e095..f3ed91f 100644 --- a/SQLiteStudio3/coreSQLiteStudio/csvserializer.h +++ b/SQLiteStudio3/coreSQLiteStudio/csvserializer.h @@ -15,9 +15,6 @@ class API_EXPORT CsvSerializer static QList<QList<QByteArray>> deserialize(const QByteArray& data, const CsvFormat& format); static QList<QStringList> deserialize(QTextStream& data, const CsvFormat& format); static QStringList deserializeOneEntry(QTextStream& data, const CsvFormat& format); - - private: - static QList<QStringList> deserialize(QTextStream& data, const CsvFormat& format, bool oneEntry); }; #endif // CSVSERIALIZER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/datatype.cpp b/SQLiteStudio3/coreSQLiteStudio/datatype.cpp index d90a6b0..38d47d5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/datatype.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/datatype.cpp @@ -44,9 +44,7 @@ DataType::DataType() DataType::DataType(const QString& fullTypeString) { static const QRegularExpression - re(R"(" - "^(?<type>[^\)]*)\s*(\((?<scale>[\d\.]+)\s*(,\s*(?<precision>[\d\.])+\s*)?\))?$" - ")"); + re(R"(^(?<type>[^\)]*)\s*(\((?<scale>[\d\.]+)\s*(,\s*(?<precision>[\d\.])+\s*)?\))?$)"); QRegularExpressionMatch match = re.match(fullTypeString); if (!match.hasMatch()) diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.cpp b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.cpp index cd9b972..70037b0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.cpp @@ -8,6 +8,7 @@ #include "sqlerrorresults.h" #include "sqlerrorcodes.h" #include "services/notifymanager.h" +#include "services/sqliteextensionmanager.h" #include "log.h" #include "parser/lexer.h" #include <QDebug> @@ -120,7 +121,7 @@ void AbstractDb::registerAllFunctions() void AbstractDb::registerAllCollations() { - foreach (const QString& name, registeredCollations) + for (const QString& name : registeredCollations) { if (!deregisterCollation(name)) qWarning() << "Failed to deregister custom collation:" << name; @@ -128,13 +129,49 @@ void AbstractDb::registerAllCollations() registeredCollations.clear(); - foreach (const CollationManager::CollationPtr& collPtr, COLLATIONS->getCollationsForDatabase(getName())) + for (const CollationManager::CollationPtr& collPtr : COLLATIONS->getCollationsForDatabase(getName())) registerCollation(collPtr->name); disconnect(COLLATIONS, SIGNAL(collationListChanged()), this, SLOT(registerAllCollations())); connect(COLLATIONS, SIGNAL(collationListChanged()), this, SLOT(registerAllCollations())); } +void AbstractDb::loadExtensions() +{ + for (const SqliteExtensionManager::ExtensionPtr& extPtr : SQLITE_EXTENSIONS->getExtensionForDatabase(getName())) + loadedExtensionCount += loadExtension(extPtr->filePath, extPtr->initFunc) ? 1 : 0; + + connect(SQLITE_EXTENSIONS, SIGNAL(extensionListChanged()), this, SLOT(reloadExtensions())); +} + +void AbstractDb::reloadExtensions() +{ + if (!isOpen()) + return; + + bool doOpen = false; + if (loadedExtensionCount > 0) + { + if (!closeQuiet()) + { + qWarning() << "Failed to close database for extension reloading."; + return; + } + + doOpen = true; + loadedExtensionCount = 0; + disconnect(SQLITE_EXTENSIONS, SIGNAL(extensionListChanged()), this, SLOT(reloadExtensions())); + } + + if (doOpen && !openQuiet()) + { + qCritical() << "Failed to re-open database for extension reloading."; + return; + } + + loadExtensions(); +} + bool AbstractDb::isOpen() { // We use separate mutex for connection state to avoid situations, when some query is being executed, @@ -166,7 +203,7 @@ QString AbstractDb::generateUniqueDbNameNoLock() } QStringList existingDatabases; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) existingDatabases << row->value("name").toString(); return generateUniqueName("attached", existingDatabases); @@ -347,6 +384,9 @@ bool AbstractDb::openAndSetup() // Implementation specific initialization initAfterOpen(); + // Load extension + loadExtensions(); + // Custom SQL functions registerAllFunctions(); @@ -658,7 +698,7 @@ void AbstractDb::detachAll() if (!isOpenInternal()) return; - foreach (Db* db, attachedDbMap.rightValues()) + for (Db* db : attachedDbMap.rightValues()) detachInternal(db); } @@ -683,7 +723,7 @@ QString AbstractDb::getUniqueNewObjectName(const QString &attachedDbName) QSet<QString> existingNames; SqlQueryPtr results = exec(QString("SELECT name FROM %1.sqlite_master").arg(dbName)); - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) existingNames << row->value(0).toString(); return randStrNotIn(16, existingNames, false); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.h index 3f2b4c0..c69c9f2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.h @@ -86,6 +86,7 @@ class API_EXPORT AbstractDb : public Db void setTimeout(int secs); int getTimeout() const; bool isValid() const; + void loadExtensions(); protected: struct FunctionUserData @@ -445,6 +446,8 @@ class API_EXPORT AbstractDb : public Db */ QStringList registeredCollations; + int loadedExtensionCount = 0; + private slots: /** * @brief Handles asynchronous execution results. @@ -464,6 +467,7 @@ class API_EXPORT AbstractDb : public Db bool openForProbing(); void registerAllFunctions(); void registerAllCollations(); + void reloadExtensions(); }; /** diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h index 7419f8c..51465f9 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h @@ -12,6 +12,8 @@ #include <QThread> #include <QPointer> #include <QDebug> +#include <QMutexLocker> +#include <QMutex> /** * @brief Complete implementation of SQLite 2 driver for SQLiteStudio. @@ -42,9 +44,11 @@ class AbstractDb2 : public AbstractDb * All values from this constructor are just passed to AbstractDb constructor. */ AbstractDb2(const QString& name, const QString& path, const QHash<QString, QVariant>& connOptions); - ~AbstractDb2(); + bool loadExtension(const QString& filePath, const QString& initFunc = QString()); + bool isComplete(const QString& sql) const; + protected: bool isOpenInternal(); void interruptExecution(); @@ -131,6 +135,7 @@ class AbstractDb2 : public AbstractDb int dbErrorCode = SQLITE_OK; QList<FunctionUserData*> userDataList; QList<Query*> queries; + QMutex* dbOperMutex = nullptr; }; //------------------------------------------------------------------------------------ @@ -141,16 +146,32 @@ template <class T> AbstractDb2<T>::AbstractDb2(const QString& name, const QString& path, const QHash<QString, QVariant>& connOptions) : AbstractDb(name, path, connOptions) { + dbOperMutex = new QMutex(QMutex::Recursive); } template <class T> AbstractDb2<T>::~AbstractDb2() { + safe_delete(dbOperMutex); if (isOpenInternal()) closeInternal(); } template <class T> +bool AbstractDb2<T>::loadExtension(const QString& filePath, const QString& initFunc) +{ + UNUSED(filePath); + UNUSED(initFunc); + return false; +} + +template<class T> +bool AbstractDb2<T>::isComplete(const QString& sql) const +{ + return sqlite_complete(sql.toUtf8().constData()); +} + +template <class T> bool AbstractDb2<T>::isOpenInternal() { return dbHandle != nullptr; @@ -168,6 +189,7 @@ void AbstractDb2<T>::interruptExecution() if (!isOpenInternal()) return; + QMutexLocker mutexLocker(dbOperMutex); sqlite_interrupt(dbHandle); } @@ -189,6 +211,7 @@ bool AbstractDb2<T>::openInternal() resetError(); sqlite* handle = nullptr; char* errMsg = nullptr; + QMutexLocker mutexLocker(dbOperMutex); handle = sqlite_open(path.toUtf8().constData(), 0, &errMsg); if (!handle) { @@ -214,6 +237,7 @@ bool AbstractDb2<T>::closeInternal() cleanUp(); + QMutexLocker mutexLocker(dbOperMutex); sqlite_close(dbHandle); dbHandle = nullptr; return true; @@ -243,6 +267,7 @@ bool AbstractDb2<T>::deregisterFunction(const QString& name, int argCount) if (!dbHandle) return false; + QMutexLocker mutexLocker(dbOperMutex); sqlite_create_function(dbHandle, name.toLatin1().data(), argCount, nullptr, nullptr); sqlite_create_aggregate(dbHandle, name.toLatin1().data(), argCount, nullptr, nullptr, nullptr); @@ -273,6 +298,7 @@ bool AbstractDb2<T>::registerScalarFunction(const QString& name, int argCount) userData->argCount = argCount; userDataList << userData; + QMutexLocker mutexLocker(dbOperMutex); int res = sqlite_create_function(dbHandle, name.toUtf8().constData(), argCount, &AbstractDb2<T>::evaluateScalar, userData); @@ -291,6 +317,7 @@ bool AbstractDb2<T>::registerAggregateFunction(const QString& name, int argCount userData->argCount = argCount; userDataList << userData; + QMutexLocker mutexLocker(dbOperMutex); int res = sqlite_create_aggregate(dbHandle, name.toUtf8().constData(), argCount, &AbstractDb2<T>::evaluateAggregateStep, &AbstractDb2<T>::evaluateAggregateFinal, @@ -527,6 +554,7 @@ int AbstractDb2<T>::Query::prepareStmt(const QString& processedQuery) char* errMsg = nullptr; const char* tail; QByteArray queryBytes = processedQuery.toUtf8(); + QMutexLocker mutexLocker(db->dbOperMutex); int res = sqlite_compile(db->dbHandle, queryBytes.constData(), &tail, &stmt, &errMsg); if (res != SQLITE_OK) { @@ -556,6 +584,7 @@ int AbstractDb2<T>::Query::resetStmt() nextRowValues.clear(); char* errMsg = nullptr; + QMutexLocker mutexLocker(db->dbOperMutex); int res = sqlite_reset(stmt, &errMsg); if (res != SQLITE_OK) { @@ -576,23 +605,27 @@ bool AbstractDb2<T>::Query::execInternal(const QList<QVariant>& args) if (!checkDbState()) return false; - ReadWriteLocker locker(&(db->dbOperLock), query, Dialect::Sqlite2, flags.testFlag(Db::Flag::NO_LOCK)); + QMutexLocker mutexLocker(db->dbOperMutex); logSql(db.data(), query, args, flags); - QueryWithParamCount queryWithParams = getQueryWithParamCount(query, Dialect::Sqlite2); - QString singleStr = replaceNamedParams(queryWithParams.first); - int res; if (stmt) res = resetStmt(); else - res = prepareStmt(singleStr); + res = prepareStmt(query); if (res != SQLITE_OK) return false; - for (int paramIdx = 1; paramIdx <= queryWithParams.second; paramIdx++) + int maxParamIdx = args.size(); + if (!flags.testFlag(Db::Flag::SKIP_PARAM_COUNTING)) + { + QueryWithParamCount queryWithParams = getQueryWithParamCount(query, Dialect::Sqlite2); + maxParamIdx = qMin(maxParamIdx, queryWithParams.second); + } + + for (int paramIdx = 1; paramIdx <= maxParamIdx; paramIdx++) { res = bindParam(paramIdx, args[paramIdx-1]); if (res != SQLITE_OK) @@ -612,7 +645,7 @@ bool AbstractDb2<T>::Query::execInternal(const QHash<QString, QVariant>& args) if (!checkDbState()) return false; - ReadWriteLocker locker(&(db->dbOperLock), query, Dialect::Sqlite2, flags.testFlag(Db::Flag::NO_LOCK)); + QMutexLocker mutexLocker(db->dbOperMutex); logSql(db.data(), query, args, flags); @@ -629,7 +662,7 @@ bool AbstractDb2<T>::Query::execInternal(const QHash<QString, QVariant>& args) return false; int paramIdx = 1; - foreach (const QString& paramName, queryWithParams.second) + for (const QString& paramName : queryWithParams.second) { if (!args.contains(paramName)) { @@ -665,9 +698,7 @@ template <class T> int AbstractDb2<T>::Query::bindParam(int paramIdx, const QVariant& value) { if (value.isNull()) - { return sqlite_bind(stmt, paramIdx, nullptr, 0, 0); - } switch (value.type()) { @@ -686,6 +717,7 @@ int AbstractDb2<T>::Query::bindParam(int paramIdx, const QVariant& value) } } + qWarning() << "sqlite_bind() MISUSE"; return SQLITE_MISUSE; // not going to happen } template <class T> @@ -747,19 +779,14 @@ bool AbstractDb2<T>::Query::hasNextInternal() template <class T> int AbstractDb2<T>::Query::fetchFirst() { + QMutexLocker mutexLocker(db->dbOperMutex); rowAvailable = true; int res = fetchNext(); + affected = 0; if (res == SQLITE_OK) { - if (colCount == 0) - { - affected = 0; - } - else - { - affected = sqlite_changes(db->dbHandle); - insertRowId["ROWID"] = sqlite_last_insert_rowid(db->dbHandle); - } + affected = sqlite_changes(db->dbHandle); + insertRowId["ROWID"] = sqlite_last_insert_rowid(db->dbHandle); } return res; } @@ -783,6 +810,7 @@ QString AbstractDb2<T>::Query::finalize() if (stmt) { char* errMsg = nullptr; + QMutexLocker mutexLocker(db->dbOperMutex); sqlite_finalize(stmt, &errMsg); stmt = nullptr; if (errMsg) @@ -814,6 +842,7 @@ int AbstractDb2<T>::Query::fetchNext() int res; int secondsSpent = 0; + QMutexLocker mutexLocker(db->dbOperMutex); while ((res = sqlite_step(stmt, &columnsCount, &values, &columns)) == SQLITE_BUSY && secondsSpent < db->getTimeout()) { QThread::sleep(1); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h index db9bc02..f45e475 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h @@ -44,6 +44,9 @@ class AbstractDb3 : public AbstractDb AbstractDb3(const QString& name, const QString& path, const QHash<QString, QVariant>& connOptions); ~AbstractDb3(); + bool loadExtension(const QString& filePath, const QString& initFunc = QString()); + bool isComplete(const QString& sql) const; + protected: bool isOpenInternal(); void interruptExecution(); @@ -315,6 +318,31 @@ AbstractDb3<T>::~AbstractDb3() closeInternal(); } +template<class T> +bool AbstractDb3<T>::loadExtension(const QString& filePath, const QString& initFunc) +{ + char* errMsg = nullptr; + int res = T::load_extension(dbHandle, filePath.toUtf8().constData(), initFunc.isEmpty() ? nullptr : initFunc.toUtf8().constData(), &errMsg); + if (res != T::OK) + { + dbErrorMessage = QObject::tr("Could not load extension %1: %2").arg(filePath, extractLastError()); + dbErrorCode = res; + if (errMsg) + { + dbErrorMessage = QObject::tr("Could not load extension %1: %2").arg(filePath, QString::fromUtf8(errMsg)); + T::free(errMsg); + } + return false; + } + return true; +} + +template<class T> +bool AbstractDb3<T>::isComplete(const QString& sql) const +{ + return T::complete(sql.toUtf8().constData()); +} + template <class T> bool AbstractDb3<T>::isOpenInternal() { @@ -358,6 +386,7 @@ bool AbstractDb3<T>::openInternal() return false; } dbHandle = handle; + T::enable_load_extension(dbHandle, 1); return true; } @@ -392,7 +421,6 @@ bool AbstractDb3<T>::initAfterCreated() template <class T> void AbstractDb3<T>::initAfterOpen() { - T::enable_load_extension(dbHandle, true); registerDefaultCollationRequestHandler();; exec("PRAGMA foreign_keys = 1;", Flag::NO_LOCK); exec("PRAGMA recursive_triggers = 1;", Flag::NO_LOCK); @@ -864,8 +892,6 @@ bool AbstractDb3<T>::Query::execInternal(const QList<QVariant>& args) ReadWriteLocker locker(&(db->dbOperLock), query, Dialect::Sqlite3, flags.testFlag(Db::Flag::NO_LOCK)); logSql(db.data(), query, args, flags); - QueryWithParamCount queryWithParams = getQueryWithParamCount(query, Dialect::Sqlite3); - int res; if (stmt) res = resetStmt(); @@ -875,8 +901,14 @@ bool AbstractDb3<T>::Query::execInternal(const QList<QVariant>& args) if (res != T::OK) return false; + int maxParamIdx = args.size(); + if (!flags.testFlag(Db::Flag::SKIP_PARAM_COUNTING)) + { + QueryWithParamCount queryWithParams = getQueryWithParamCount(query, Dialect::Sqlite3); + maxParamIdx = qMin(maxParamIdx, queryWithParams.second); + } - for (int paramIdx = 1, argCount = args.size(); paramIdx <= queryWithParams.second && paramIdx <= argCount; paramIdx++) + for (int paramIdx = 1; paramIdx <= maxParamIdx; paramIdx++) { res = bindParam(paramIdx, args[paramIdx-1]); if (res != T::OK) diff --git a/SQLiteStudio3/coreSQLiteStudio/db/db.cpp b/SQLiteStudio3/coreSQLiteStudio/db/db.cpp index 977812a..ebe6731 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/db.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/db.cpp @@ -5,10 +5,12 @@ Db::Db() { +// qDebug() << "Db::Db()" << this; } Db::~Db() { +// qDebug() << "Db::~Db()" << this; } void Db::metaInit() diff --git a/SQLiteStudio3/coreSQLiteStudio/db/db.h b/SQLiteStudio3/coreSQLiteStudio/db/db.h index 4a9e80a..2ee79aa 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/db.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/db.h @@ -1,6 +1,7 @@ #ifndef DB_H #define DB_H +#include <QVariant> #include "returncode.h" #include "dialect.h" #include "services/functionmanager.h" @@ -10,13 +11,13 @@ #include "interruptable.h" #include "dbobjecttype.h" #include <QObject> -#include <QVariant> #include <QList> #include <QHash> #include <QReadWriteLock> #include <QRunnable> #include <QStringList> #include <QSet> +#include <QDataStream> /** @file */ @@ -147,8 +148,13 @@ class API_EXPORT Db : public QObject, public Interruptable * of code, where the lock on Db was already set. Never (!) use this to ommit lock from different * threads. Justified situation is when you implement Db::initialDbSetup() in the derived class, * or when you implement SqlFunctionPlugin. Don't use it for the usual cases. + * This flag is ignored by SQLite2 plugin, because SQLite2 is not prepared for multithreaded + * processing, therefore all operations must be synchronized. */ - SKIP_DROP_DETECTION = 0x4, /**< Query execution will not notify about any detected objects dropped by the query. */ + SKIP_DROP_DETECTION = 0x4, /**< Query execution will not notify about any detected objects dropped by the query. + * Benefit is that it speeds up execution. */ + SKIP_PARAM_COUNTING = 0x8, /**< During execution with arguments as list the number of bind parameters will not be verified. + * This speeds up execution at cost of possible error if bind params in query don't match number of args. */ }; Q_DECLARE_FLAGS(Flags, Flag) @@ -479,6 +485,12 @@ class API_EXPORT Db : public QObject, public Interruptable virtual bool isReadable() = 0; /** + * @brief Tells whether given SQL is a complete statement or not. + * @return true if given SQL is complete SQL (or more), or it misses some part. + */ + virtual bool isComplete(const QString& sql) const = 0; + + /** * @brief Checks if the database is writable at the moment. * @return true if the database is writable, or false otherwise. * @@ -623,7 +635,7 @@ class API_EXPORT Db : public QObject, public Interruptable * This method is used only to let the database know, that the given function exists in FunctionManager and we want it to be visible * in this database's context. When the function is called from SQL query, then the function execution is delegated to the FunctionManager. * - * For details about usage of custom SQL functions see http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_SQL_functions + * For details about usage of custom SQL functions see https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-sql-functions * * @see FunctionManager */ @@ -646,7 +658,7 @@ class API_EXPORT Db : public QObject, public Interruptable * This method is used only to let the database know, that the given function exists in FunctionManager and we want it to be visible * in this database's context. When the function is called from SQL query, then the function execution is delegated to the FunctionManager. * - * For details about usage of custom SQL functions see http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_SQL_functions + * For details about usage of custom SQL functions see https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-sql-functions * * @see FunctionManager */ @@ -663,7 +675,7 @@ class API_EXPORT Db : public QObject, public Interruptable * when comparing 2 values in the database in order to sort query results. The name passed to this method is a name of the collation * as it is used in SQL queries and also the same name must be used when defining collation in Collations editor window. * - * For details about usage of custom collations see http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_collations + * For details about usage of custom collations see https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-sql-functions * * @see CollationManager */ @@ -678,6 +690,19 @@ class API_EXPORT Db : public QObject, public Interruptable */ virtual bool deregisterCollation(const QString& name) = 0; + /** + * @brief Loads a SQLite extension. + * @param filePath Absolute path to the extension file (dll/so/dylib). + * @param initFunc Optional entry point function. If empty, SQLite's default will be used. + * @return true on success, or false on failure. + * + * This function works only on SQLite 3 drivers, as SQLite 2 does not support extensions. + * More details can be found at https://sqlite.org/c3ref/load_extension.html + * + * If function returns false, use getErrorText() to discover details. + */ + virtual bool loadExtension(const QString& filePath, const QString& initFunc = QString()) = 0; + signals: /** * @brief Emitted when the connection to the database was established. diff --git a/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.cpp b/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.cpp index a4a8b73..4778bb2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.cpp @@ -9,3 +9,8 @@ DbSqlite3::DbSqlite3(const QString& name, const QString& path) : DbSqlite3(name, path, QHash<QString,QVariant>()) { } + +bool DbSqlite3::complete(const QString& sql) +{ + return Sqlite3::complete(sql.toUtf8().constData()); +} diff --git a/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.h b/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.h index 29db5a8..1509dff 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.h @@ -28,6 +28,8 @@ class API_EXPORT DbSqlite3 : public AbstractDb3<Sqlite3> * @overload */ DbSqlite3(const QString& name, const QString& path); + + static bool complete(const QString& sql); }; #endif // DBSQLITE3_H diff --git a/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.cpp b/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.cpp index bdf3ef6..5e210f2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.cpp @@ -325,6 +325,18 @@ void InvalidDb::setError(const QString& value) error = value; } +bool InvalidDb::loadExtension(const QString& filePath, const QString& initFunc) +{ + UNUSED(filePath); + UNUSED(initFunc); + return false; +} + +bool InvalidDb::isComplete(const QString& sql) const +{ + UNUSED(sql); + return false; +} void InvalidDb::interrupt() { diff --git a/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.h b/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.h index a9d58e0..3bc91a4 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.h @@ -59,6 +59,8 @@ class API_EXPORT InvalidDb : public Db bool isValid() const; QString getError() const; void setError(const QString& value); + bool loadExtension(const QString& filePath, const QString& initFunc); + bool isComplete(const QString& sql) const; public slots: bool open(); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp index 4a1c2f6..4160e41 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp @@ -33,6 +33,10 @@ // TODO modify all executor steps to use rebuildTokensFromContents() method, instead of replacing tokens manually. +QHash<QueryExecutor::StepPosition, QList<QueryExecutorStep*>> QueryExecutor::additionalStatelessSteps; +QList<QueryExecutorStep*> QueryExecutor::allAdditionalStatelsssSteps; +QHash<QueryExecutor::StepPosition, QList<QueryExecutor::StepFactory*>> QueryExecutor::additionalStatefulStepFactories; + QueryExecutor::QueryExecutor(Db* db, const QString& query, QObject *parent) : QObject(parent) { @@ -46,8 +50,7 @@ QueryExecutor::QueryExecutor(Db* db, const QString& query, QObject *parent) : connect(this, SIGNAL(executionFailed(int,QString)), this, SLOT(cleanupAfterExecFailed(int,QString))); connect(DBLIST, SIGNAL(dbAboutToBeUnloaded(Db*, DbPlugin*)), this, SLOT(cleanupBeforeDbDestroy(Db*))); connect(DBLIST, SIGNAL(dbRemoved(Db*)), this, SLOT(cleanupBeforeDbDestroy(Db*))); - connect(simpleExecutor, SIGNAL(finished(SqlQueryPtr)), this, SLOT(simpleExecutionFinished(SqlQueryPtr))); - + connect(simpleExecutor, &ChainExecutor::finished, this, &QueryExecutor::simpleExecutionFinished, Qt::DirectConnection); } QueryExecutor::~QueryExecutor() @@ -58,38 +61,79 @@ QueryExecutor::~QueryExecutor() void QueryExecutor::setupExecutionChain() { + executionChain.append(additionalStatelessSteps[FIRST]); + executionChain.append(createSteps(FIRST)); + executionChain << new QueryExecutorParseQuery("initial") << new QueryExecutorDetectSchemaAlter() << new QueryExecutorExplainMode() << new QueryExecutorValuesMode() << new QueryExecutorAttaches() // needs to be at the begining, because columns needs to know real databases - << new QueryExecutorParseQuery("after Attaches") - << new QueryExecutorDataSources() + << new QueryExecutorParseQuery("after Attaches"); + + executionChain.append(additionalStatelessSteps[AFTER_ATTACHES]); + executionChain.append(createSteps(AFTER_ATTACHES)); + + executionChain << new QueryExecutorDataSources() << new QueryExecutorReplaceViews() - << new QueryExecutorParseQuery("after ReplaceViews") - << new QueryExecutorAddRowIds() - << new QueryExecutorParseQuery("after AddRowIds") - << new QueryExecutorColumns() - << new QueryExecutorParseQuery("after Columns") - //<< new QueryExecutorColumnAliases() - << new QueryExecutorOrder() - << new QueryExecutorWrapDistinctResults() - << new QueryExecutorParseQuery("after WrapDistinctResults") - << new QueryExecutorCellSize() + << new QueryExecutorParseQuery("after ReplaceViews"); + + executionChain.append(additionalStatelessSteps[AFTER_REPLACED_VIEWS]); + executionChain.append(createSteps(AFTER_REPLACED_VIEWS)); + + executionChain << new QueryExecutorAddRowIds() + << new QueryExecutorParseQuery("after AddRowIds"); + + executionChain.append(additionalStatelessSteps[AFTER_ROW_IDS]); + executionChain.append(createSteps(AFTER_ROW_IDS)); + + executionChain << new QueryExecutorColumns() + << new QueryExecutorParseQuery("after Columns"); + + executionChain.append(additionalStatelessSteps[AFTER_REPLACED_COLUMNS]); + executionChain.append(createSteps(AFTER_REPLACED_COLUMNS)); + + executionChain << new QueryExecutorOrder(); + + executionChain.append(additionalStatelessSteps[AFTER_ORDER]); + executionChain.append(createSteps(AFTER_ORDER)); + + executionChain << new QueryExecutorWrapDistinctResults() + << new QueryExecutorParseQuery("after WrapDistinctResults"); + + executionChain.append(additionalStatelessSteps[AFTER_DISTINCT_WRAP]); + executionChain.append(createSteps(AFTER_DISTINCT_WRAP)); + + executionChain << new QueryExecutorCellSize() << new QueryExecutorCountResults() - << new QueryExecutorParseQuery("after Order") - << new QueryExecutorLimit() - << new QueryExecutorParseQuery("after Limit") - << new QueryExecutorExecute(); + << new QueryExecutorParseQuery("after CellSize"); + + executionChain.append(additionalStatelessSteps[AFTER_CELL_SIZE_LIMIT]); + executionChain.append(createSteps(AFTER_CELL_SIZE_LIMIT)); - foreach (QueryExecutorStep* step, executionChain) + executionChain << new QueryExecutorLimit() + << new QueryExecutorParseQuery("after Limit"); + + executionChain.append(additionalStatelessSteps[AFTER_ROW_LIMIT_AND_OFFSET]); + executionChain.append(createSteps(AFTER_ROW_LIMIT_AND_OFFSET)); + executionChain.append(additionalStatelessSteps[JUST_BEFORE_EXECUTION]); + executionChain.append(createSteps(JUST_BEFORE_EXECUTION)); + executionChain.append(additionalStatelessSteps[LAST]); + executionChain.append(createSteps(LAST)); + + executionChain << new QueryExecutorExecute(); + + for (QueryExecutorStep* step : executionChain) step->init(this, context); } void QueryExecutor::clearChain() { - foreach (QueryExecutorStep* step, executionChain) - delete step; + for (QueryExecutorStep* step : executionChain) + { + if (!allAdditionalStatelsssSteps.contains(step)) + delete step; + } executionChain.clear(); } @@ -98,7 +142,7 @@ void QueryExecutor::executeChain() { // Go through all remaining steps bool result; - foreach (QueryExecutorStep* currentStep, executionChain) + for (QueryExecutorStep* currentStep : executionChain) { if (isInterrupted()) { @@ -249,6 +293,7 @@ void QueryExecutor::execInternal() context->noMetaColumns = noMetaColumns; context->resultsHandler = resultsHandler; context->preloadResults = preloadResults; + context->queryParameters = queryParameters; // Start the execution setupExecutionChain(); @@ -372,7 +417,12 @@ QSet<QueryExecutor::EditionForbiddenReason> QueryExecutor::getEditionForbiddenGl void QueryExecutor::setParam(const QString& name, const QVariant& value) { - context->queryParameters[name] = value; + queryParameters[name] = value; +} + +void QueryExecutor::setParams(const QHash<QString, QVariant>& params) +{ + queryParameters = params; } void QueryExecutor::arg(const QVariant& value) @@ -454,7 +504,7 @@ void QueryExecutor::simpleExecutionFinished(SqlQueryPtr results) ResultColumnPtr resCol; context->resultColumns.clear(); - foreach (const QString& colName, results->getColumnNames()) + for (const QString& colName : results->getColumnNames()) { resCol = ResultColumnPtr::create(); resCol->displayName = colName; @@ -487,19 +537,19 @@ bool QueryExecutor::simpleExecIsSelect() tokens.trim(); // First check if it's explicit "SELECT" or "VALUES" (the latter one added in SQLite 3.8.4). - TokenPtr token = tokens.first(); - QString upper = token->value.toUpper(); - if (token->type == Token::KEYWORD && (upper == "SELECT" || upper == "VALUES")) + TokenPtr firstToken = tokens.first(); + QString upper = firstToken->value.toUpper(); + if (firstToken->type == Token::KEYWORD && (upper == "SELECT" || upper == "VALUES")) return true; // Now it's only possible to be a SELECT if it starts with "WITH" statement. - if (token->type != Token::KEYWORD || upper != "WITH") + if (firstToken->type != Token::KEYWORD || upper != "WITH") return false; // Go through all tokens and find which one appears first (exclude contents indise parenthesis, // cause there will always be a SELECT for Common Table Expression). int depth = 0; - foreach (token, tokens) + for (const TokenPtr& token : tokens) { switch (token->type) { @@ -533,7 +583,7 @@ bool QueryExecutor::simpleExecIsSelect() void QueryExecutor::cleanup() { Db* attDb = nullptr; - foreach (const QString& attDbName, context->dbNameToAttach.leftValues()) + for (const QString& attDbName : context->dbNameToAttach.leftValues()) { attDb = DBLIST->getByName(attDbName, Qt::CaseInsensitive); if (attDbName.isNull()) @@ -575,8 +625,10 @@ bool QueryExecutor::handleRowCountingResults(quint32 asyncId, SqlQueryPtr result QStringList QueryExecutor::applyLimitForSimpleMethod(const QStringList &queries) { static_qstring(tpl, "SELECT * FROM (%1) LIMIT %2 OFFSET %3"); - QStringList result = queries; + if (page < 0) + return queries; // no paging requested + QStringList result = queries; QString lastQuery = queries.last(); bool isSelect = false; @@ -589,6 +641,15 @@ QStringList QueryExecutor::applyLimitForSimpleMethod(const QStringList &queries) return result; } +QList<QueryExecutorStep*> QueryExecutor::createSteps(QueryExecutor::StepPosition position) +{ + QList<QueryExecutorStep*> steps; + for (StepFactory* factory : additionalStatefulStepFactories[position]) + steps << factory->produceQueryExecutorStep(); + + return steps; +} + int QueryExecutor::getQueryCountLimitForSmartMode() const { return queryCountLimitForSmartMode; @@ -599,6 +660,28 @@ void QueryExecutor::setQueryCountLimitForSmartMode(int value) queryCountLimitForSmartMode = value; } +void QueryExecutor::registerStep(StepPosition position, QueryExecutorStep *step) +{ + additionalStatelessSteps[position] += step; + allAdditionalStatelsssSteps += step; +} + +void QueryExecutor::registerStep(QueryExecutor::StepPosition position, QueryExecutor::StepFactory* stepFactory) +{ + additionalStatefulStepFactories[position] += stepFactory; +} + +void QueryExecutor::deregisterStep(StepPosition position, QueryExecutorStep *step) +{ + additionalStatelessSteps[position].removeOne(step); + allAdditionalStatelsssSteps.removeOne(step); +} + +void QueryExecutor::deregisterStep(QueryExecutor::StepPosition position, QueryExecutor::StepFactory* stepFactory) +{ + additionalStatefulStepFactories[position].removeOne(stepFactory); +} + bool QueryExecutor::getForceSimpleMode() const { return forceSimpleMode; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h index 4830e36..85c39bf 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h @@ -647,6 +647,53 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable }; /** + * @brief Position for custom executor steps. + * + * These position define where in query executor chain of steps the new, registered step will be placed. + * It's used in arguments of registerStep() method. + * + * If multiple steps are registered at same position, they will be executed in order they were registered. + * + * Values of positions determin what actions have been already taken by the executor, so for example + * AFTER_ATTACHES means, that executor already attached referenced databases and replaced occurrences of objects + * from that databases. + * + * Enumerations are in order as the steps are executed. + * + * If you need more detailed description about certain steps performed by query executor, see documentation + * of their classes - all these classes name start with QueryExecutor prefix. + */ + enum StepPosition { + FIRST, /**< As first step */ + AFTER_ATTACHES, /**< After transparent attaching is applied (detected tables are defined to be attached first). */ + AFTER_REPLACED_VIEWS, /**< After referenced views have been replaced with subqueries */ + AFTER_ROW_IDS, /**< After ROWID columns have been added to result columns */ + AFTER_REPLACED_COLUMNS, /**< After all columns have been explicitly listed in result list, together with unique alias names */ + AFTER_ORDER, /**< After order clause was applied/modified */ + AFTER_DISTINCT_WRAP, /**< After wrapping SELECT was added in case of DISTINCT or GROUP BY clauses were used */ + AFTER_CELL_SIZE_LIMIT, /**< After cell result size was limited to save memory usage */ + AFTER_ROW_LIMIT_AND_OFFSET, /**< After LIMIT and ORDER clauses were added/modified. This is the last possible moment, directly ahead of final query execution */ + JUST_BEFORE_EXECUTION, /**< Same as AFTER_ROW_LIMIT_AND_OFFSET */ + LAST /**< Same as AFTER_ROW_LIMIT_AND_OFFSET */ + }; + + /** + * @brief Interface for producing query executor steps. + * + * It can be used for overloaded version of registerStep() method, + * in case a step is stateful and needs to be created/deleted for every query executor processing. + * + * If step is stateless, it can be registered directly as an instance, using the other version of registerStep() method. + * + * This is an abstract class and not pointer to function, because it has to be comparable (and std::function is not), + * so it's possible to deregister the factory later on. + */ + class StepFactory { + public: + virtual QueryExecutorStep* produceQueryExecutorStep() = 0; + }; + + /** * @brief Creates query executor, initializes internal context object. * @param db Optional database. If not provided, it has to be defined later with setDb(). * @param query Optional query to execute. If not provided, it has to be defined later with setQuery(). @@ -809,6 +856,15 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable void setParam(const QString& name, const QVariant& value); /** + * @brief Assigns all query parameters at once. + * @param params All bind parameters for the query. + * + * This is same as setParam(), except it overrides all current params with given ones. + * It allows for setting all params at once. + */ + void setParams(const QHash<QString, QVariant>& params); + + /** * @brief Replaces placeholder in the query. * @param value Value to replace placeholder with. * @@ -1038,6 +1094,49 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable int getQueryCountLimitForSmartMode() const; void setQueryCountLimitForSmartMode(int value); + /** + * @brief Adds new step to the chain of execution + * @param position Where in chain should the step be placed. + * @param step Step implementation instance. + * + * If multiple steps are registered for the same position, they will be executed in the order they were registered. + * + * If step is registered with a plugin, remember to deregister the step upon plugin unload. + * Best place for that is in Plugin::deinit(). + */ + static void registerStep(StepPosition position, QueryExecutorStep* step); + + /** + * @brief Adds new step to chain of execution + * @param position Where in chain should the step be placed. + * @param stepFactory Factory for creating instance of the step. + * + * This is overloaded method for cases when the step is stateful and needs to be recreated for every invokation of query executor. + */ + static void registerStep(StepPosition position, StepFactory* stepFactory); + + /** + * @brief Removes extra step from the execution chain. + * @param position Position from which the step should be removed. + * @param step Step implementation instance. + * + * Removes step from list of additional steps to be performed. If such step was not on the list, this method does nothing. + * + * There is a position parameter to this method, becuase a step could be added to multiple different positions + * and you decide from which you want to deregister it. + */ + static void deregisterStep(StepPosition position, QueryExecutorStep* step); + + /** + * @brief Removes extra step from the execution chain. + * @param position Position from which the step should be removed. + * @param stepFactory Factory to deregister. + * + * This is overloaded method to remove factory instead of instance of a step. To be used together with registerStep() + * that also takes factory in parameters. + */ + static void deregisterStep(StepPosition position, StepFactory* stepFactory); + private: /** * @brief Executes query. @@ -1126,6 +1225,13 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable QStringList applyLimitForSimpleMethod(const QStringList &queries); /** + * @brief Creates instances of steps for all registered factories for given position. + * @param position Position for which factories will be used. + * @return List of instances of steps from given factories. + */ + QList<QueryExecutorStep*> createSteps(StepPosition position); + + /** * @brief Query executor context object. * * Context object is shared across all execution steps. It's (re)initialized for every @@ -1317,6 +1423,37 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable QList<QueryExecutorStep*> executionChain; /** + * @brief List of registered additional steps to be performed + * + * It's a map, where keys describe where in chain should the steps be placed + * and values are list of steps to be inserted at that position. + * + * They are added/removed by methods: registerStep() and deregisterStep(). + */ + static QHash<StepPosition, QList<QueryExecutorStep*>> additionalStatelessSteps; + + /** + * @brief List of all registered additional steps + * + * This is a list of all registered additional steps (registered instances of steps), regardless of their position. + * This is used to identify registered stateless steps, so they are not deleted on query executor cleanup. + * + * Only steps created with a factory are deleted upon executor cleanup (and of course all internal steps created by the executor itself). + */ + static QList<QueryExecutorStep*> allAdditionalStatelsssSteps; + + /** + * @brief List of registered factories that create additional steps to be performed + * + * This is similar to additionalSteps, except it holds factories, instead of step instances. + * + * Steps created with a factory are appended after stateless steps registered as direct + * instances (held by additionalSteps) - that is for case when both instance and factory + * are registered for the same step position. + */ + static QHash<StepPosition, QList<StepFactory*>> additionalStatefulStepFactories; + + /** * @brief Execution results handler. * * This member keeps address of function that was defined for handling results. @@ -1327,6 +1464,13 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable */ Db::QueryResultsHandler resultsHandler = nullptr; + /** + * @brief Parameters for query execution. + * + * It's defined by setParam(). + */ + QHash<QString,QVariant> queryParameters; + bool forceSimpleMode = false; ChainExecutor* simpleExecutor = nullptr; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp index d417072..d59d73c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp @@ -54,7 +54,7 @@ QHash<SelectResolver::Table,QHash<QString,QString>> QueryExecutorAddRowIds::addR return rowIdColsMap; // Go trough subselects to add ROWID result columns there and collect rowId mapping to use here. - foreach (SqliteSelect* subSelect, getSubSelects(core)) + for (SqliteSelect* subSelect : getSubSelects(core)) { rowIdColsMap.unite(addRowIdForTables(subSelect, ok, false)); if (!ok) @@ -66,11 +66,14 @@ QHash<SelectResolver::Table,QHash<QString,QString>> QueryExecutorAddRowIds::addR resolver.resolveMultiCore = false; // multicore subselects result in not editable columns, skip them QSet<SelectResolver::Table> tables = resolver.resolveTables(core); - foreach (const SelectResolver::Table& table, tables) + for (const SelectResolver::Table& table : tables) { 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 (checkInWithClause(table, select->with)) + continue; // we don't get ROWID from WITH clause, as it's likely to be recurrent and difficult. TODO: support columns from WITH clause + if (!addResultColumns(core, table, rowIdColsMap, isTopSelect)) { ok = false; @@ -89,7 +92,7 @@ QList<SqliteSelect*> QueryExecutorAddRowIds::getSubSelects(SqliteSelect::Core* c if (core->from->singleSource && core->from->singleSource->select) selects << core->from->singleSource->select; - foreach (SqliteSelect::Core::JoinSourceOther* otherSource, core->from->otherSources) + for (SqliteSelect::Core::JoinSourceOther* otherSource : core->from->otherSources) { if (!otherSource->singleSource->select) continue; @@ -137,7 +140,7 @@ QHash<QString,QString> QueryExecutorAddRowIds::getNextColNames(const SelectResol SqliteCreateTable::Constraint* tableConstr = dynamic_cast<SqliteCreateTable::Constraint*>(primaryKey); if (tableConstr) { - foreach (SqliteIndexedColumn* idxCol, tableConstr->indexedColumns) + for (SqliteIndexedColumn* idxCol : tableConstr->indexedColumns) colNames[getNextColName()] = idxCol->name; return colNames; @@ -205,6 +208,27 @@ bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const Se return true; } +bool QueryExecutorAddRowIds::checkInWithClause(const SelectResolver::Table &table, SqliteWith *with) +{ + if (!table.database.isNull() || !with) + return false; + + SqliteWith::CommonTableExpression* cte = nullptr; + QString nameToCompareWith = table.tableAlias.isNull() ? table.table : table.tableAlias; + for (SqliteWith::CommonTableExpression* cteItem : with->cteList) + { + if (cteItem->table == nameToCompareWith) + { + cte = cteItem; + break; + } + } + if (!cte) + return false; + + return true; +} + bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const SelectResolver::Table& table, const QString& queryExecutorColumn, const QString& realColumn, bool aliasOnlyAsSelectColumn) { diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h index 61bc302..1669542 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h @@ -76,6 +76,8 @@ class QueryExecutorAddRowIds : public QueryExecutorStep * @return Map of query executor alias to real database column name. */ QHash<QString, QString> getNextColNames(const SelectResolver::Table& table); + + bool checkInWithClause(const SelectResolver::Table& table, SqliteWith *with); }; #endif // QUERYEXECUTORADDROWIDS_H diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcellsize.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcellsize.cpp index 54bd35a..352c74b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcellsize.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcellsize.cpp @@ -10,7 +10,7 @@ bool QueryExecutorCellSize::exec() if (!select || select->explain) return true; - foreach (SqliteSelect::Core* core, select->coreSelects) + for (SqliteSelect::Core* core : select->coreSelects) { if (!applyDataLimit(select.data(), core)) return false; @@ -31,7 +31,7 @@ bool QueryExecutorCellSize::applyDataLimit(SqliteSelect* select, SqliteSelect::C bool first = true; TokenList tokens; - foreach (const QueryExecutor::ResultColumnPtr& col, context->resultColumns) + for (const QueryExecutor::ResultColumnPtr& col : context->resultColumns) { if (!first) tokens += getSeparatorTokens(); @@ -40,7 +40,7 @@ bool QueryExecutorCellSize::applyDataLimit(SqliteSelect* select, SqliteSelect::C first = false; } - foreach (const QueryExecutor::ResultRowIdColumnPtr& col, context->rowIdColumns) + for (const QueryExecutor::ResultRowIdColumnPtr& col : context->rowIdColumns) { if (!first) tokens += getSeparatorTokens(); @@ -112,7 +112,7 @@ TokenList QueryExecutorCellSize::getNoLimitTokens(const QueryExecutor::ResultRow { TokenList newTokens; bool first = true; - foreach (const QString& col, resCol->queryExecutorAliasToColumn.keys()) + for (const QString& col : resCol->queryExecutorAliasToColumn.keys()) { if (!first) newTokens += getSeparatorTokens(); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp index 30a4f5d..0cb6b7a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp @@ -108,6 +108,9 @@ QueryExecutor::ResultColumnPtr QueryExecutorColumns::getResultColumn(const Selec if (resolvedColumn.flags & SelectResolver::FROM_DISTINCT_SELECT) resultColumn->editionForbiddenReasons << QueryExecutor::ColumnEditionForbiddenReason::DISTINCT_RESULTS; + if (resolvedColumn.flags & SelectResolver::FROM_CTE_SELECT) + resultColumn->editionForbiddenReasons << QueryExecutor::ColumnEditionForbiddenReason::COMM_TAB_EXPR; + resultColumn->database = resolvedColumn.originalDatabase; resultColumn->table = resolvedColumn.table; resultColumn->column = resolvedColumn.column; @@ -200,7 +203,7 @@ QString QueryExecutorColumns::resolveAttachedDatabases(const QString &dbName) bool QueryExecutorColumns::isRowIdColumnAlias(const QString& alias) { - foreach (QueryExecutor::ResultRowIdColumnPtr rowIdColumn, context->rowIdColumns) + for (QueryExecutor::ResultRowIdColumnPtr rowIdColumn : context->rowIdColumns) { if (rowIdColumn->queryExecutorAliasToColumn.keys().contains(alias)) return true; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp index 4a422d3..88c957b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp @@ -19,7 +19,7 @@ bool QueryExecutorDataSources::exec() SqliteSelect::Core* core = select->coreSelects.first(); QSet<SelectResolver::Table> tables = resolver.resolveTables(core); - foreach (SelectResolver::Table resolvedTable, tables) + for (SelectResolver::Table resolvedTable : tables) { QueryExecutor::SourceTablePtr table = QueryExecutor::SourceTablePtr::create(); table->database = resolvedTable.database; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp index aaa8014..0a97c1e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp @@ -23,7 +23,7 @@ bool QueryExecutorExecute::exec() void QueryExecutorExecute::provideResultColumns(SqlQueryPtr results) { QueryExecutor::ResultColumnPtr resCol; - foreach (const QString& colName, results->getColumnNames()) + for (const QString& colName : results->getColumnNames()) { resCol = QueryExecutor::ResultColumnPtr::create(); resCol->displayName = colName; @@ -124,8 +124,8 @@ void QueryExecutorExecute::handleFailResult(SqlQueryPtr results) QHash<QString, QVariant> QueryExecutorExecute::getBindParamsForQuery(SqliteQueryPtr query) { QHash<QString, QVariant> queryParams; - QStringList bindParams = query->tokens.filter(Token::BIND_PARAM).toStringList(); - foreach (const QString& bindParam, bindParams) + QStringList bindParams = query->tokens.filter(Token::BIND_PARAM).toValueList(); + for (const QString& bindParam : bindParams) { if (context->queryParameters.contains(bindParam)) queryParams.insert(bindParam, context->queryParameters[bindParam]); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.cpp index d64ea2e..8fbf026 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.cpp @@ -18,7 +18,7 @@ void QueryExecutorStep::init(QueryExecutor *queryExecutor, QueryExecutor::Contex void QueryExecutorStep::updateQueries() { QString newQuery; - foreach (SqliteQueryPtr query, context->parsedQueries) + for (SqliteQueryPtr query : context->parsedQueries) { newQuery += query->detokenize(); newQuery += "\n"; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.h index a15ad9c..9a89b26 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.h @@ -37,7 +37,7 @@ * * To access database object, that the query is executed on, use QueryExecutor::getDb(). */ -class QueryExecutorStep : public QObject +class API_EXPORT QueryExecutorStep : public QObject { Q_OBJECT diff --git a/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.cpp b/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.cpp index 4217711..94799d9 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.cpp @@ -1,5 +1,6 @@ #include "sqlquery.h" #include "db/sqlerrorcodes.h" +#include "common/utils_sql.h" SqlQuery::~SqlQuery() { @@ -115,7 +116,7 @@ void SqlQuery::setArgs(const QHash<QString, QVariant>& args) } -void RowIdConditionBuilder::setRowId(const RowId& rowId) +void RowIdConditionBuilder::setRowId(const RowId& rowId, Dialect dialect) { static const QString argTempalate = QStringLiteral(":rowIdArg%1"); @@ -127,7 +128,7 @@ void RowIdConditionBuilder::setRowId(const RowId& rowId) it.next(); arg = argTempalate.arg(i++); queryArgs[arg] = it.value(); - conditions << it.key() + " = " + arg; + conditions << wrapObjIfNeeded(it.key(), dialect) + " = " + arg; } } diff --git a/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.h b/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.h index 4e0d9cf..ed78d80 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.h @@ -304,7 +304,7 @@ class API_EXPORT SqlQuery class API_EXPORT RowIdConditionBuilder { public: - void setRowId(const RowId& rowId); + void setRowId(const RowId& rowId, Dialect dialect); const QHash<QString,QVariant>& getQueryArgs(); QString build(); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h b/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h index 6b0c422..94a0413 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h @@ -2,7 +2,7 @@ #define STDSQLITE3DRIVER_H #define STD_SQLITE3_DRIVER(Name, Label, Prefix, UppercasePrefix) \ - struct Name \ + struct API_EXPORT Name \ { \ static_char* label = Label; \ \ @@ -69,7 +69,9 @@ static int step(stmt* arg) {return Prefix##sqlite3_step(arg);} \ static int reset(stmt* arg) {return Prefix##sqlite3_reset(arg);} \ static int close(handle* arg) {return Prefix##sqlite3_close(arg);} \ + static void free(void* arg) {return Prefix##sqlite3_free(arg);} \ static int enable_load_extension(handle* arg1, int arg2) {return Prefix##sqlite3_enable_load_extension(arg1, arg2);} \ + static int load_extension(handle *arg1, const char *arg2, const char *arg3, char **arg4) {return Prefix##sqlite3_load_extension(arg1, arg2, arg3, arg4);} \ static void* user_data(context* arg) {return Prefix##sqlite3_user_data(arg);} \ static void* aggregate_context(context* arg1, int arg2) {return Prefix##sqlite3_aggregate_context(arg1, arg2);} \ static int collation_needed(handle* a1, void* a2, void(*a3)(void*,handle*,int eTextRep,const char*)) {return Prefix##sqlite3_collation_needed(a1, a2, a3);} \ @@ -80,6 +82,7 @@ {return Prefix##sqlite3_create_function_v2(a1, a2, a3, a4, a5, a6, a7, a8, a9);} \ static int create_collation_v2(handle* a1, const char *a2, int a3, void *a4, int(*a5)(void*,int,const void*,int,const void*), void(*a6)(void*)) \ {return Prefix##sqlite3_create_collation_v2(a1, a2, a3, a4, a5, a6);} \ + static int complete(const char* arg) {return Prefix##sqlite3_complete(arg);} \ }; #endif // STDSQLITE3DRIVER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.cpp b/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.cpp index 96f73d7..0ef924d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.cpp @@ -23,6 +23,7 @@ #include "parser/ast/sqlitesavepoint.h" #include "parser/ast/sqliteupdate.h" #include "parser/ast/sqlitevacuum.h" +#include "parser/ast/sqliteupsert.h" #include "services/pluginmanager.h" #include "plugins/dbplugin.h" #include "services/dbmanager.h" @@ -207,7 +208,8 @@ SqliteQueryPtr DbVersionConverter::convert3To2(SqliteQueryPtr query) if (!modifyDeleteForVersion2(newQuery.dynamicCast<SqliteDelete>().data())) { newQuery = SqliteEmptyQueryPtr::create(); - storeErrorDiff(query.data()); + if (diffsForNonDDL) + storeErrorDiff(query.data()); } break; case SqliteQueryType::Detach: @@ -230,7 +232,8 @@ SqliteQueryPtr DbVersionConverter::convert3To2(SqliteQueryPtr query) if (!modifyInsertForVersion2(newQuery.dynamicCast<SqliteInsert>().data())) { newQuery = SqliteEmptyQueryPtr::create(); - storeErrorDiff(query.data()); + if (diffsForNonDDL) + storeErrorDiff(query.data()); } break; case SqliteQueryType::Pragma: @@ -260,7 +263,8 @@ SqliteQueryPtr DbVersionConverter::convert3To2(SqliteQueryPtr query) if (!modifySelectForVersion2(newQuery.dynamicCast<SqliteSelect>().data())) { newQuery = SqliteEmptyQueryPtr::create(); - storeErrorDiff(query.data()); + if (diffsForNonDDL) + storeErrorDiff(query.data()); } break; } @@ -269,7 +273,8 @@ SqliteQueryPtr DbVersionConverter::convert3To2(SqliteQueryPtr query) if (!modifyUpdateForVersion2(newQuery.dynamicCast<SqliteUpdate>().data())) { newQuery = SqliteEmptyQueryPtr::create(); - storeErrorDiff(query.data()); + if (diffsForNonDDL) + storeErrorDiff(query.data()); } break; case SqliteQueryType::Vacuum: @@ -450,7 +455,9 @@ bool DbVersionConverter::modifySelectForVersion2(SqliteSelect* select) if (!modifyAllExprsForVersion2(select)) return false; - storeDiff(sql1, select); + if (diffsForNonDDL) + storeDiff(sql1, select); + return true; } @@ -471,7 +478,9 @@ bool DbVersionConverter::modifyDeleteForVersion2(SqliteDelete* del) if (!modifyAllExprsForVersion2(del)) return false; - storeDiff(sql1, del); + if (diffsForNonDDL) + storeDiff(sql1, del); + return true; } @@ -497,6 +506,9 @@ bool DbVersionConverter::modifyInsertForVersion2(SqliteInsert* insert) QString sql1 = getSqlForDiff(insert); + if (insert->upsert) + safe_delete(insert->upsert); + // Modifying SELECT deals with "VALUES" completely. if (!modifySelectForVersion2(insert->select)) return false; @@ -504,7 +516,9 @@ bool DbVersionConverter::modifyInsertForVersion2(SqliteInsert* insert) if (!modifyAllExprsForVersion2(insert)) return false; - storeDiff(sql1, insert); + if (diffsForNonDDL) + storeDiff(sql1, insert); + return true; } @@ -525,7 +539,9 @@ bool DbVersionConverter::modifyUpdateForVersion2(SqliteUpdate* update) update->indexedByKw = false; update->notIndexedKw = false; - storeDiff(sql1, update); + if (diffsForNonDDL) + storeDiff(sql1, update); + return true; } diff --git a/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.h b/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.h index 9486f1b..5fafc93 100644 --- a/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.h +++ b/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.h @@ -127,6 +127,21 @@ class API_EXPORT DbVersionConverter : public QObject bool interrupted = false; QMutex interruptMutex; + /** + * @brief Whether to include non-DDL statements in diff list. + * + * The non-DDL statements are INSERTs, SELECTs, etc. + * Normally, for DB conversion we only care about DDL modifications, + * that is for CREATE statements. Other statements may appear inside of + * triggers or views, but we don't need their diffs separately. + * + * This variable is not used currently, but may be in future, + * when for example individual INSERT statement would need to be converted. + * Right now there's no such need, but it would be pity to remove the code + * from that non-DDL statements. + */ + bool diffsForNonDDL = false; + private slots: void conversionError(Db* db, const QString& errMsg); void confirmConversion(); diff --git a/SQLiteStudio3/coreSQLiteStudio/diff/diff_match_patch.cpp b/SQLiteStudio3/coreSQLiteStudio/diff/diff_match_patch.cpp index 4f0022e..aa5765a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/diff/diff_match_patch.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/diff/diff_match_patch.cpp @@ -142,7 +142,7 @@ QString Patch::toString() { text = QString("@@ -") + coords1 + QString(" +") + coords2 + QString(" @@\n"); // Escape the body of the patch with %xx notation. - foreach (Diff aDiff, diffs) { + for (Diff aDiff : diffs) { switch (aDiff.operation) { case INSERT: text += QString('+'); @@ -1251,7 +1251,7 @@ int diff_match_patch::diff_xIndex(const QList<Diff> &diffs, int loc) { int last_chars1 = 0; int last_chars2 = 0; Diff lastDiff; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { if (aDiff.operation != INSERT) { // Equality or deletion. chars1 += aDiff.text.length(); @@ -1280,7 +1280,7 @@ int diff_match_patch::diff_xIndex(const QList<Diff> &diffs, int loc) { QString diff_match_patch::diff_prettyHtml(const QList<Diff> &diffs) { QString html; QString text; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { text = aDiff.text; text.replace("&", "&").replace("<", "<") .replace(">", ">").replace("\n", "¶<br>"); @@ -1304,7 +1304,7 @@ QString diff_match_patch::diff_prettyHtml(const QList<Diff> &diffs) { QString diff_match_patch::diff_text1(const QList<Diff> &diffs) { QString text; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { if (aDiff.operation != INSERT) { text += aDiff.text; } @@ -1315,7 +1315,7 @@ QString diff_match_patch::diff_text1(const QList<Diff> &diffs) { QString diff_match_patch::diff_text2(const QList<Diff> &diffs) { QString text; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { if (aDiff.operation != DELETE) { text += aDiff.text; } @@ -1328,7 +1328,7 @@ int diff_match_patch::diff_levenshtein(const QList<Diff> &diffs) { int levenshtein = 0; int insertions = 0; int deletions = 0; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { switch (aDiff.operation) { case INSERT: insertions += aDiff.text.length(); @@ -1351,7 +1351,7 @@ int diff_match_patch::diff_levenshtein(const QList<Diff> &diffs) { QString diff_match_patch::diff_toDelta(const QList<Diff> &diffs) { QString text; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { switch (aDiff.operation) { case INSERT: { QString encoded = QString(QUrl::toPercentEncoding(aDiff.text, @@ -1382,7 +1382,7 @@ QList<Diff> diff_match_patch::diff_fromDelta(const QString &text1, QList<Diff> diffs; int pointer = 0; // Cursor in text1 QStringList tokens = delta.split("\t"); - foreach(QString token, tokens) { + for (QString token : tokens) { if (token.isEmpty()) { // Blank tokens are ok (from a trailing \t). continue; @@ -1682,7 +1682,7 @@ QList<Patch> diff_match_patch::patch_make(const QString &text1, // context info. QString prepatch_text = text1; QString postpatch_text = text1; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { if (patch.diffs.isEmpty() && aDiff.operation != EQUAL) { // A new patch starts here. patch.start1 = char_count1; @@ -1748,9 +1748,9 @@ QList<Patch> diff_match_patch::patch_make(const QString &text1, QList<Patch> diff_match_patch::patch_deepCopy(QList<Patch> &patches) { QList<Patch> patchesCopy; - foreach(Patch aPatch, patches) { + for (Patch aPatch : patches) { Patch patchCopy = Patch(); - foreach(Diff aDiff, aPatch.diffs) { + for (Diff aDiff : aPatch.diffs) { Diff diffCopy = Diff(aDiff.operation, aDiff.text); patchCopy.diffs.append(diffCopy); } @@ -1785,7 +1785,7 @@ QPair<QString, QVector<bool> > diff_match_patch::patch_apply( // has an effective expected position of 22. int delta = 0; QVector<bool> results(patchesCopy.size()); - foreach(Patch aPatch, patchesCopy) { + for (Patch aPatch : patchesCopy) { int expected_loc = aPatch.start2 + delta; QString text1 = diff_text1(aPatch.diffs); int start_loc; @@ -1836,7 +1836,7 @@ QPair<QString, QVector<bool> > diff_match_patch::patch_apply( } else { diff_cleanupSemanticLossless(diffs); int index1 = 0; - foreach(Diff aDiff, aPatch.diffs) { + for (Diff aDiff : aPatch.diffs) { if (aDiff.operation != EQUAL) { int index2 = diff_xIndex(diffs, index1); if (aDiff.operation == INSERT) { @@ -2030,7 +2030,7 @@ void diff_match_patch::patch_splitMax(QList<Patch> &patches) { QString diff_match_patch::patch_toText(const QList<Patch> &patches) { QString text; - foreach(Patch aPatch, patches) { + for (Patch aPatch : patches) { text.append(aPatch.toString()); } return text; diff --git a/SQLiteStudio3/coreSQLiteStudio/impl/dbattacherimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/impl/dbattacherimpl.cpp index 7d9c1ba..59f4ac5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/impl/dbattacherimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/impl/dbattacherimpl.cpp @@ -61,7 +61,7 @@ bool DbAttacherImpl::attachDatabases() TokenList DbAttacherImpl::getDbTokens() { TokenList dbTokens; - foreach (SqliteQueryPtr query, queries) + for (SqliteQueryPtr query : queries) dbTokens += query->getContextDatabaseTokens(); return dbTokens; @@ -78,7 +78,7 @@ void DbAttacherImpl::detachAttached() void DbAttacherImpl::prepareNameToDbMap() { - foreach (Db* db, DBLIST->getValidDbList()) + for (Db* db : DBLIST->getValidDbList()) nameToDbMap[db->getName()] = db; } @@ -153,7 +153,7 @@ void DbAttacherImpl::replaceTokensInQueries(const QHash<TokenPtr, TokenPtr>& tok while (it.hasNext()) { it.next(); - foreach (SqliteQueryPtr query, queries) + for (SqliteQueryPtr query : queries) { idx = query->tokens.indexOf(it.key()); if (idx < 0) @@ -177,7 +177,7 @@ BiStrHash DbAttacherImpl::getDbNameToAttach() const QString DbAttacherImpl::getQuery() const { QStringList queryStrings; - foreach (SqliteQueryPtr query, queries) + for (SqliteQueryPtr query : queries) queryStrings << query->detokenize(); return queryStrings.join(";"); diff --git a/SQLiteStudio3/coreSQLiteStudio/importworker.cpp b/SQLiteStudio3/coreSQLiteStudio/importworker.cpp index ea6c40d..1496571 100644 --- a/SQLiteStudio3/coreSQLiteStudio/importworker.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/importworker.cpp @@ -149,6 +149,7 @@ bool ImportWorker::importData() QString theInsert = insertTemplate.arg(wrapObjIfNeeded(table, db->getDialect()), valList.join(", ")); SqlQueryPtr query = db->prepare(theInsert); + query->setFlags(Db::Flag::SKIP_DROP_DETECTION|Db::Flag::SKIP_PARAM_COUNTING|Db::Flag::NO_LOCK); int rowCnt = 0; QList<QVariant> row; @@ -161,10 +162,6 @@ bool ImportWorker::importData() // Assign argument values query->setArgs(row.mid(0, colCount)); - // No transactions = already in transaction, skip locking - if (config->skipTransaction) - query->setFlags(Db::Flag::NO_LOCK); - if (!query->execute()) { if (config->ignoreErrors) diff --git a/SQLiteStudio3/coreSQLiteStudio/licenses/fugue_icons.txt b/SQLiteStudio3/coreSQLiteStudio/licenses/fugue_icons.txt index 4fc7b75..22b0655 100644 --- a/SQLiteStudio3/coreSQLiteStudio/licenses/fugue_icons.txt +++ b/SQLiteStudio3/coreSQLiteStudio/licenses/fugue_icons.txt @@ -13,68 +13,3 @@ purchase a royalty-free license. I'm unavailable for custom icon design work. But your
suggestions are always welcome!
<mailto:p@yusukekamiyamane.com>
-
-------------------------------------------------------------
-
-All logos and trademarks in some icons are property of their
-respective owners.
-
-------------------------------------------------------------
-
-- geotag
-
- (C) Geotag Icon Project. All rights reserved.
- <http://www.geotagicons.com/>
-
- Geotag icon is licensed under a Creative Commons
- Attribution-Share Alike 3.0 License or LGPL.
- <http://creativecommons.org/licenses/by-sa/3.0/>
- <http://opensource.org/licenses/lgpl-license.php>
-
-- language
-
- (C) Language Icon Project. All rights reserved.
- <http://www.languageicon.org/>
-
- Language icon is licensed under a Creative Commons
- Attribution-Share Alike 3.0 License.
- <http://creativecommons.org/licenses/by-sa/3.0/>
-
-- open-share
-
- (C) Open Share Icon Project. All rights reserved.
- <http://www.openshareicons.com/>
-
- Open Share icon is licensed under a Creative Commons
- Attribution-Share Alike 3.0 License.
- <http://creativecommons.org/licenses/by-sa/3.0/>
-
-- opml
-
- (C) OPML Icon Project. All rights reserved.
- <http://opmlicons.com/>
-
- OPML icon is licensed under a Creative Commons
- Attribution-Share Alike 2.5 License.
- <http://creativecommons.org/licenses/by-sa/2.5/>
-
-- share
-
- (C) Share Icon Project. All rights reserved.
- <http://shareicons.com/>
-
- Share icon is licensed under a GPL or LGPL or BSD or
- Creative Commons Attribution 2.5 License.
- <http://opensource.org/licenses/gpl-license.php>
- <http://opensource.org/licenses/lgpl-license.php>
- <http://opensource.org/licenses/bsd-license.php>
- <http://creativecommons.org/licenses/by/2.5/>
-
-- xfn
-
- (C) Wolfgang Bartelme. All rights reserved.
- <http://www.bartelme.at/>
-
- XFN icon is licensed under a Creative Commons
- Attribution-Share Alike 2.5 License.
- <http://creativecommons.org/licenses/by-sa/2.5/>
\ No newline at end of file diff --git a/SQLiteStudio3/coreSQLiteStudio/licenses/gpl.txt b/SQLiteStudio3/coreSQLiteStudio/licenses/gpl.txt index 10926e8..5225330 100644 --- a/SQLiteStudio3/coreSQLiteStudio/licenses/gpl.txt +++ b/SQLiteStudio3/coreSQLiteStudio/licenses/gpl.txt @@ -1,3 +1,16 @@ +SQLiteStudio is licensed under the GNU General Public License version 3 with the +addition of the following special exception: + +In addition, as a special exception, the copyright holders give +permission to link the code of portions of this program with the OpenSSL +library. +You must obey the GNU General Public License in all respects for all of +the code used other than OpenSSL. If you modify file(s) with this +exception, you may extend this exception to your version of the file(s), +but you are not obligated to do so. If you do not wish to do so, delete +this exception statement from your version. If you delete this exception +statement from all source files in the program, then also delete it here. + GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 @@ -672,4 +685,3 @@ may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>. - diff --git a/SQLiteStudio3/coreSQLiteStudio/licenses/mit.txt b/SQLiteStudio3/coreSQLiteStudio/licenses/mit.txt new file mode 100644 index 0000000..85b2a14 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/licenses/mit.txt @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Copyright (c) Itay Grudev 2015 - 2016 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Note: Some of the examples include code not distributed under the terms of the +MIT License. diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp index fdbadf8..5c11ff5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp @@ -57,7 +57,7 @@ SqliteCreateIndex::SqliteCreateIndex(bool unique, bool ifNotExists, const QStrin table = name3; this->indexedColumns = columns; - foreach (SqliteOrderBy* idxCol, columns) + for (SqliteOrderBy* idxCol : columns) idxCol->setParent(this); this->where = where; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp index 2ac6c04..eb4ae85 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp @@ -22,11 +22,10 @@ SqliteCreateTable::SqliteCreateTable(bool ifNotExistsKw, int temp, const QString { init(ifNotExistsKw, temp, name1, name2); this->columns = columns; - foreach (Column* column, columns) + for (Column* column : columns) column->setParent(this); - SqliteCreateTable::Constraint* constr = nullptr; - foreach (constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) { if (this->constraints.size() > 0 && this->constraints.last()->type == SqliteCreateTable::Constraint::NAME_ONLY) @@ -66,7 +65,7 @@ SqliteStatement*SqliteCreateTable::clone() QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getConstraints(SqliteCreateTable::Constraint::Type type) const { QList<SqliteCreateTable::Constraint*> results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (constr->type == type) results << constr; @@ -75,11 +74,11 @@ QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getConstraints(SqliteCr SqliteStatement* SqliteCreateTable::getPrimaryKey() const { - foreach (Constraint* constr, getConstraints(Constraint::PRIMARY_KEY)) + for (Constraint* constr : getConstraints(Constraint::PRIMARY_KEY)) return constr; Column::Constraint* colConstr = nullptr; - foreach (Column* col, columns) + for (Column* col : columns) { colConstr = col->getConstraint(Column::Constraint::PRIMARY_KEY); if (colConstr) @@ -106,7 +105,7 @@ QStringList SqliteCreateTable::getPrimaryKeyColumns() const SqliteCreateTable::Constraint* tableConstr = dynamic_cast<SqliteCreateTable::Constraint*>(primaryKey); if (tableConstr) { - foreach (SqliteIndexedColumn* idxCol, tableConstr->indexedColumns) + for (SqliteIndexedColumn* idxCol : tableConstr->indexedColumns) colNames << idxCol->name; } return colNames; @@ -114,7 +113,7 @@ QStringList SqliteCreateTable::getPrimaryKeyColumns() const SqliteCreateTable::Column* SqliteCreateTable::getColumn(const QString& colName) { - foreach (Column* col, columns) + for (Column* col : columns) { if (col->name.compare(colName, Qt::CaseInsensitive) == 0) return col; @@ -125,7 +124,7 @@ SqliteCreateTable::Column* SqliteCreateTable::getColumn(const QString& colName) QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getForeignKeysByTable(const QString& foreignTable) const { QList<Constraint*> results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (constr->type == Constraint::FOREIGN_KEY && constr->foreignKey->foreignTable.compare(foreignTable, Qt::CaseInsensitive) == 0) results << constr; @@ -135,7 +134,7 @@ QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getForeignKeysByTable(c QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::getColumnForeignKeysByTable(const QString& foreignTable) const { QList<Column::Constraint*> results; - foreach (Column* col, columns) + for (Column* col : columns) results += col->getForeignKeysByTable(foreignTable); return results; @@ -144,7 +143,7 @@ QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::getColumnForeig QStringList SqliteCreateTable::getColumnNames() const { QStringList names; - foreach (Column* col, columns) + for (Column* col : columns) names << col->name; return names; @@ -154,7 +153,7 @@ QHash<QString, QString> SqliteCreateTable::getModifiedColumnsMap(bool lowercaseK { QHash<QString, QString> colMap; QString key; - foreach (Column* col, columns) + for (Column* col : columns) { key = lowercaseKeys ? col->originalName.toLower() : col->originalName; if (col->name.compare(col->originalName, cs) != 0) @@ -385,10 +384,10 @@ void SqliteCreateTable::Column::Constraint::initFk(const QString& table, const Q foreignKey = fk; fk->setParent(this); - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(fk); - foreach (SqliteForeignKey::Condition* cond, conditions) + for (SqliteForeignKey::Condition* cond : conditions) cond->setParent(fk); } @@ -466,7 +465,7 @@ void SqliteCreateTable::Constraint::initPk(const QList<SqliteIndexedColumn *> &i autoincrKw = autoincr; onConflict = algo; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(this); } @@ -476,7 +475,7 @@ void SqliteCreateTable::Constraint::initUnique(const QList<SqliteIndexedColumn * this->indexedColumns = indexedColumns; onConflict = algo; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(this); } @@ -499,7 +498,7 @@ void SqliteCreateTable::Constraint::initFk(const QList<SqliteIndexedColumn *> &i this->type = SqliteCreateTable::Constraint::FOREIGN_KEY; this->indexedColumns = indexedColumns; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(this); SqliteForeignKey* fk = new SqliteForeignKey(); @@ -511,10 +510,10 @@ void SqliteCreateTable::Constraint::initFk(const QList<SqliteIndexedColumn *> &i fk->setParent(this); - foreach (SqliteIndexedColumn* idxCol, fkColumns) + for (SqliteIndexedColumn* idxCol : fkColumns) idxCol->setParent(fk); - foreach (SqliteForeignKey::Condition* cond, conditions) + for (SqliteForeignKey::Condition* cond : conditions) cond->setParent(fk); this->foreignKey = fk; @@ -528,7 +527,7 @@ bool SqliteCreateTable::Constraint::doesAffectColumn(const QString& columnName) int SqliteCreateTable::Constraint::getAffectedColumnIdx(const QString& columnName) { int i = 0; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) { if (idxCol->name.compare(columnName, Qt::CaseInsensitive) == 0) return i; @@ -619,8 +618,7 @@ SqliteCreateTable::Column::Column(const QString &name, SqliteColumnType *type, c if (type) type->setParent(this); - SqliteCreateTable::Column::Constraint* constr = nullptr; - foreach (constr, constraints) + for (SqliteCreateTable::Column::Constraint* constr : constraints) { // If last constraint on list is NAME_ONLY we apply the name // to current constraint and remove NAME_ONLY. @@ -689,7 +687,7 @@ QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::Column::getCons QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::Column::getForeignKeysByTable(const QString& foreignTable) const { QList<Constraint*> results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (constr->type == Constraint::FOREIGN_KEY && constr->foreignKey->foreignTable.compare(foreignTable, Qt::CaseInsensitive) == 0) results << constr; @@ -748,7 +746,7 @@ TokenList SqliteCreateTable::Column::Constraint::rebuildTokensFromContents() { builder.withKeyword("DEFAULT").withSpace(); if (!id.isNull()) - builder.withOther(id); + builder.withOther(id, dialect); else if (!ctime.isNull()) builder.withKeyword(ctime.toUpper()); else if (expr) diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp index e15ddd6..001dd2d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp @@ -22,7 +22,7 @@ SqliteCreateTrigger::SqliteCreateTrigger(const SqliteCreateTrigger& other) : // Special case of deep collection copy SqliteQuery* newQuery = nullptr; - foreach (SqliteQuery* query, other.queries) + for (SqliteQuery* query : other.queries) { switch (query->queryType) { @@ -95,7 +95,7 @@ SqliteCreateTrigger::SqliteCreateTrigger(int temp, bool ifNotExists, const QStri if (when) when->setParent(this); - foreach (SqliteQuery* q, queries) + for (SqliteQuery* q : queries) q->setParent(this); } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp index 5dc830b..d17205a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp @@ -269,7 +269,7 @@ void SqliteExpr::initIn(SqliteExpr *expr, bool notKw, const QList<SqliteExpr*>& expr1 = expr; this->notKw = notKw; this->exprList = exprList; - foreach (SqliteExpr* expr, exprList) + for (SqliteExpr* expr : exprList) expr->setParent(this); } @@ -331,7 +331,7 @@ void SqliteExpr::initCase(SqliteExpr *expr1, const QList<SqliteExpr*>& exprList, if (expr2) expr2->setParent(this); - foreach (SqliteExpr* expr, exprList) + for (SqliteExpr* expr : exprList) expr->setParent(this); } @@ -341,6 +341,28 @@ void SqliteExpr::initRaise(const QString& type, const QString& text) raiseFunction = new SqliteRaise(type, text); } +void SqliteExpr::detectDoubleQuotes(bool recursively) +{ + if (doubleQuotesChecked) + return; + + doubleQuotesChecked = true; + + if (tokens.size() > 0) + { + QString val = tokens.first()->value; + if (val[0] == '"' && val[0] == val[val.length() - 1]) + possibleDoubleQuotedString = true; + } + + for (SqliteStatement* stmt : childStatements()) + { + SqliteExpr* subExpr = dynamic_cast<SqliteExpr*>(stmt); + if (subExpr) + subExpr->detectDoubleQuotes(recursively); + } +} + QStringList SqliteExpr::getColumnsInStatement() { return getStrListFromValue(column); @@ -533,12 +555,7 @@ TokenList SqliteExpr::rebuildTokensFromContents() void SqliteExpr::evaluatePostParsing() { - if (tokens.size() > 0) - { - QString val = tokens.first()->value; - if (val[0] == '"' && val[0] == val[val.length() - 1]) - possibleDoubleQuotedString = true; - } + detectDoubleQuotes(false); // not recursively, as SqliteStatement will take care of recursiveness } TokenList SqliteExpr::rebuildId() @@ -550,7 +567,7 @@ TokenList SqliteExpr::rebuildId() if (!table.isNull()) builder.withOther(table, dialect).withOperator("."); - if (possibleDoubleQuotedString) + if (table.isNull() && possibleDoubleQuotedString) builder.withStringPossiblyOther(column, dialect); else builder.withOther(column, dialect); @@ -652,7 +669,7 @@ TokenList SqliteExpr::rebuildCase() builder.withSpace(); bool then = false; - foreach (SqliteExpr* expr, exprList) + for (SqliteExpr* expr : exprList) { if (then) builder.withKeyword("THEN"); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h index 4d5bb03..c65a8e2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h @@ -92,6 +92,7 @@ class API_EXPORT SqliteExpr : public SqliteStatement void initSubSelect(SqliteSelect* select); void initCase(SqliteExpr* expr1, const QList<SqliteExpr*>& exprList, SqliteExpr* expr2); void initRaise(const QString& type, const QString& text = QString::null); + void detectDoubleQuotes(bool recursively = true); Mode mode = Mode::null; QVariant literalValue = QVariant(); @@ -132,6 +133,7 @@ class API_EXPORT SqliteExpr : public SqliteStatement void evaluatePostParsing(); private: + bool doubleQuotesChecked = false; TokenList rebuildId(); TokenList rebuildLike(); TokenList rebuildNotNull(); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp index cb85377..e48cffb 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp @@ -5,6 +5,7 @@ #include "parser/statementtokenbuilder.h" #include "common/global.h" #include "sqlitewith.h" +#include "sqliteupsert.h" SqliteInsert::SqliteInsert() { @@ -18,6 +19,7 @@ SqliteInsert::SqliteInsert(const SqliteInsert& other) : DEEP_COPY_COLLECTION(SqliteExpr, values); DEEP_COPY_FIELD(SqliteSelect, select); DEEP_COPY_FIELD(SqliteWith, with); + DEEP_COPY_FIELD(SqliteUpsert, upsert); } SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, const QList<QString> &columns, @@ -33,12 +35,12 @@ SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QS if (with) with->setParent(this); - foreach (SqliteExpr* expr, row) + for (SqliteExpr* expr : row) expr->setParent(this); } SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, const QList<QString> &columns, - SqliteSelect *select, SqliteWith* with) : + SqliteSelect *select, SqliteWith* with, SqliteUpsert* upsert) : SqliteInsert() { initName(name1, name2); @@ -48,6 +50,10 @@ SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QS if (with) with->setParent(this); + this->upsert = upsert; + if (upsert) + upsert->setParent(this); + columnNames = columns; this->select = select; if (select) @@ -98,7 +104,7 @@ QStringList SqliteInsert::getDatabasesInStatement() TokenList SqliteInsert::getColumnTokensInStatement() { TokenList list; - foreach (TokenPtr token, getTokenListFromNamedKey("inscollist_opt", -1)) + for (TokenPtr token : getTokenListFromNamedKey("idlist_opt", -1)) { if (token->type != Token::OTHER && token->type != Token::KEYWORD) continue; @@ -201,6 +207,8 @@ TokenList SqliteInsert::rebuildTokensFromContents() if (select) { builder.withStatement(select); + if (upsert) + builder.withSpace().withStatement(upsert); } else if (dialect == Dialect::Sqlite2) // Sqlite2 uses classic single row values { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h index 4287680..2ee4965 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h @@ -9,6 +9,7 @@ class SqliteSelect; class SqliteExpr; class SqliteWith; +class SqliteUpsert; class API_EXPORT SqliteInsert : public SqliteQuery { @@ -19,7 +20,7 @@ class API_EXPORT SqliteInsert : public SqliteQuery const QString& name2, const QList<QString>& columns, const QList<SqliteExpr*>& row, SqliteWith* with); SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString& name1, - const QString& name2, const QList<QString>& columns, SqliteSelect* select, SqliteWith* with); + const QString& name2, const QList<QString>& columns, SqliteSelect* select, SqliteWith* with, SqliteUpsert* upsert = nullptr); SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString& name1, const QString& name2, const QList<QString>& columns, SqliteWith* with); ~SqliteInsert(); @@ -50,6 +51,7 @@ class API_EXPORT SqliteInsert : public SqliteQuery QList<SqliteExpr*> values; SqliteSelect* select = nullptr; SqliteWith* with = nullptr; + SqliteUpsert* upsert = nullptr; }; typedef QSharedPointer<SqliteInsert> SqliteInsertPtr; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp index f1b1929..8038cb6 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp @@ -50,7 +50,7 @@ SqliteSelect* SqliteSelect::append(SqliteSelect* select, SqliteSelect::CompoundO Core::ResultColumn* resCol = nullptr; QList<Core::ResultColumn*> resColList; - foreach (const QList<SqliteExpr*>& singleValues, values) + for (const QList<SqliteExpr*>& singleValues : values) { Core* core = new Core(); core->setParent(select); @@ -64,9 +64,10 @@ SqliteSelect* SqliteSelect::append(SqliteSelect* select, SqliteSelect::CompoundO select->coreSelects << core; resColList.clear(); - foreach (SqliteExpr* value, singleValues) + for (SqliteExpr* value : singleValues) { resCol = new Core::ResultColumn(value, false, QString::null); + value->detectDoubleQuotes(); // invoke explicitly before rebuilding tokens not to lose this information resCol->rebuildTokens(); resCol->setParent(core); core->resultColumns << resCol; @@ -116,7 +117,7 @@ SqliteSelect::CompoundOperator SqliteSelect::compoundOperator(const QString& op) void SqliteSelect::reset() { - foreach (Core* core, coreSelects) + for (Core* core : coreSelects) delete core; coreSelects.clear(); @@ -172,13 +173,13 @@ SqliteSelect::Core::Core(int distinct, const QList<ResultColumn *> &resCols, Sql if (limit) limit->setParent(this); - foreach (SqliteOrderBy* order, orderBy) + for (SqliteOrderBy* order : orderBy) order->setParent(this); - foreach (SqliteExpr* expr, groupBy) + for (SqliteExpr* expr : groupBy) expr->setParent(this); - foreach (SqliteSelect::Core::ResultColumn* resCol, resCols) + for (SqliteSelect::Core::ResultColumn* resCol : resCols) resCol->setParent(this); } @@ -293,6 +294,24 @@ SqliteSelect::Core::SingleSource::SingleSource(const QString& name1, const QStri this->notIndexedKw = notIndexedKw; } +SqliteSelect::Core::SingleSource::SingleSource(const QString &name1, const QString &name2, bool asKw, const QString &alias, const QList<SqliteExpr*> &exprList) +{ + if (!name2.isNull()) + { + database = name1; + funcName = name2; + } + else + funcName = name1; + + funcParams.append(exprList); + for (SqliteExpr* expr : exprList) + expr->setParent(this); + + this->asKw = asKw; + this->alias = alias; +} + SqliteSelect::Core::SingleSource::SingleSource(SqliteSelect *select, bool asKw, const QString &alias) { this->select = select; @@ -409,7 +428,7 @@ QStringList SqliteSelect::Core::JoinConstraint::getColumnsInStatement() TokenList SqliteSelect::Core::JoinConstraint::getColumnTokensInStatement() { TokenList list; - foreach (TokenPtr token, getTokenListFromNamedKey("inscollist", -1)) + for (TokenPtr token : getTokenListFromNamedKey("idlist", -1)) { if (token->type == Token::OPERATOR) // a COMMA continue; @@ -539,7 +558,7 @@ SqliteSelect::Core::JoinSource::JoinSource(SqliteSelect::Core::SingleSource *sin if (singleSource) singleSource->setParent(this); - foreach (JoinSourceOther* other, otherSources) + for (JoinSourceOther* other : otherSources) other->setParent(this); } @@ -590,12 +609,27 @@ TokenList SqliteSelect::Core::SingleSource::rebuildTokensFromContents() builder.withSpace().withKeyword("AS"); builder.withSpace().withOther(alias, dialect); + } + } + else if (!funcName.isNull()) + { + if (!database.isNull()) + builder.withOther(database, dialect).withOperator("."); - if (indexedByKw) - builder.withSpace().withKeyword("INDEXED").withSpace().withKeyword("BY").withSpace().withOther(indexedBy, dialect); - else if (notIndexedKw) - builder.withSpace().withKeyword("NOT").withSpace().withKeyword("INDEXED"); + builder.withOther(funcName, dialect).withParLeft().withStatementList(funcParams).withParRight(); + + if (!alias.isNull()) + { + if (asKw) + builder.withSpace().withKeyword("AS"); + + builder.withSpace().withOther(alias, dialect); } + + if (indexedByKw) + builder.withSpace().withKeyword("INDEXED").withSpace().withKeyword("BY").withSpace().withOther(indexedBy, dialect); + else if (notIndexedKw) + builder.withSpace().withKeyword("NOT").withSpace().withKeyword("INDEXED"); } else if (select) { @@ -723,7 +757,11 @@ TokenList SqliteSelect::Core::rebuildTokensFromContents() StatementTokenBuilder builder; if (valuesMode) { - builder.withKeyword("VALUES").withSpace().withParLeft().withStatementList(resultColumns).withParRight(); + SqliteSelect* select = dynamic_cast<SqliteSelect*>(parentStatement()); + if (select->coreSelects.indexOf(this) == 0) // this is first core in series of cores of values mode of the SELECT + builder.withKeyword("VALUES").withSpace(); + + builder.withParLeft().withStatementList(resultColumns).withParRight(); return builder.build(); } @@ -763,7 +801,7 @@ TokenList SqliteSelect::rebuildTokensFromContents() if (with) builder.withStatement(with); - foreach (SqliteSelect::Core* core, coreSelects) + for (SqliteSelect::Core* core : coreSelects) { if (core->compoundOp == CompoundOperator::UNION_ALL) { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h index 22d1921..b6f537d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h @@ -63,6 +63,8 @@ class API_EXPORT SqliteSelect : public SqliteQuery SingleSource(const SingleSource& other); SingleSource(const QString& name1, const QString& name2, bool asKw, const QString& alias, bool notIndexedKw, const QString& indexedBy); + SingleSource(const QString& name1, const QString& name2, + bool asKw, const QString& alias, const QList<SqliteExpr*>& exprList); SingleSource(SqliteSelect* select, bool asKw, const QString& alias); SingleSource(JoinSource* src, bool asKw, const QString& alias); @@ -71,6 +73,8 @@ class API_EXPORT SqliteSelect : public SqliteQuery QString database = QString::null; QString table = QString::null; QString alias = QString::null; + QString funcName = QString::null; + QList<SqliteExpr*> funcParams; bool asKw = false; bool indexedByKw = false; bool notIndexedKw = false; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp index f14273d..119461a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp @@ -90,7 +90,7 @@ QList<SqliteStatement::FullObject> SqliteStatement::getContextFullObjects(bool c void SqliteStatement::setSqliteDialect(Dialect dialect) { this->dialect = dialect; - foreach (SqliteStatement* stmt, childStatements()) + for (SqliteStatement* stmt : childStatements()) stmt->setSqliteDialect(dialect); } @@ -106,14 +106,14 @@ SqliteStatementPtr SqliteStatement::detach() void SqliteStatement::processPostParsing() { evaluatePostParsing(); - foreach (SqliteStatement* stmt, childStatements()) + for (SqliteStatement* stmt : childStatements()) stmt->processPostParsing(); } QStringList SqliteStatement::getContextColumns(SqliteStatement *caller, bool checkParent, bool checkChilds) { QStringList results = getColumnsInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextColumns(this, checkParent, checkChilds); return results; @@ -122,7 +122,7 @@ QStringList SqliteStatement::getContextColumns(SqliteStatement *caller, bool che QStringList SqliteStatement::getContextTables(SqliteStatement *caller, bool checkParent, bool checkChilds) { QStringList results = getTablesInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextTables(this, checkParent, checkChilds); return results; @@ -131,7 +131,7 @@ QStringList SqliteStatement::getContextTables(SqliteStatement *caller, bool chec QStringList SqliteStatement::getContextDatabases(SqliteStatement *caller, bool checkParent, bool checkChilds) { QStringList results = getDatabasesInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextDatabases(this, checkParent, checkChilds); return results; @@ -140,7 +140,7 @@ QStringList SqliteStatement::getContextDatabases(SqliteStatement *caller, bool c TokenList SqliteStatement::getContextColumnTokens(SqliteStatement *caller, bool checkParent, bool checkChilds) { TokenList results = getColumnTokensInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextColumnTokens(this, checkParent, checkChilds); return results; @@ -149,7 +149,7 @@ TokenList SqliteStatement::getContextColumnTokens(SqliteStatement *caller, bool TokenList SqliteStatement::getContextTableTokens(SqliteStatement *caller, bool checkParent, bool checkChilds) { TokenList results = getTableTokensInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextTableTokens(this, checkParent, checkChilds); return results; @@ -158,7 +158,7 @@ TokenList SqliteStatement::getContextTableTokens(SqliteStatement *caller, bool c TokenList SqliteStatement::getContextDatabaseTokens(SqliteStatement *caller, bool checkParent, bool checkChilds) { TokenList results = getDatabaseTokensInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextDatabaseTokens(this, checkParent, checkChilds); return results; @@ -167,7 +167,7 @@ TokenList SqliteStatement::getContextDatabaseTokens(SqliteStatement *caller, boo QList<SqliteStatement::FullObject> SqliteStatement::getContextFullObjects(SqliteStatement* caller, bool checkParent, bool checkChilds) { QList<SqliteStatement::FullObject> results = getFullObjectsInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) { stmt->setContextDbForFullObject(dbTokenForFullObjects); results += stmt->getContextFullObjects(this, checkParent, checkChilds); @@ -231,12 +231,12 @@ QList<SqliteStatement *> SqliteStatement::getContextStatements(SqliteStatement * if (checkChilds) { - foreach (stmt, childStatements()) + for (SqliteStatement* childStmt : childStatements()) { - if (stmt == caller) + if (childStmt == caller) continue; - results += stmt; + results += childStmt; } } @@ -246,7 +246,7 @@ QList<SqliteStatement *> SqliteStatement::getContextStatements(SqliteStatement * TokenList SqliteStatement::extractPrintableTokens(const TokenList &tokens, bool skipMeaningless) { TokenList list; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) { switch (token->type) { @@ -488,7 +488,7 @@ Range SqliteStatement::getRange() SqliteStatement *SqliteStatement::findStatementWithToken(TokenPtr token) { SqliteStatement* stmtWithToken = nullptr; - foreach (SqliteStatement* stmt, childStatements()) + for (SqliteStatement* stmt : childStatements()) { stmtWithToken = stmt->findStatementWithToken(token); if (stmtWithToken) @@ -521,7 +521,7 @@ SqliteStatement *SqliteStatement::parentStatement() QList<SqliteStatement *> SqliteStatement::childStatements() { QList<SqliteStatement*> results; - foreach (QObject* obj, children()) + for (QObject* obj : children()) results += dynamic_cast<SqliteStatement*>(obj); return results; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h index bacb2d7..779bea3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h @@ -249,7 +249,7 @@ class API_EXPORT SqliteStatement : public QObject if (casted) results << casted; - foreach (SqliteStatement* stmt, getContextStatements(this, false, true)) + for (SqliteStatement* stmt : getContextStatements(this, false, true)) results += stmt->getAllTypedStatements<T>(); return results; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp index df892fb..2063e0e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp @@ -17,7 +17,7 @@ SqliteUpdate::SqliteUpdate(const SqliteUpdate& other) : { // Special case of deep collection copy SqliteExpr* newExpr = nullptr; - foreach (const ColumnAndValue& keyValue, other.keyValueMap) + for (const ColumnAndValue& keyValue : other.keyValueMap) { newExpr = new SqliteExpr(*keyValue.second); newExpr->setParent(this); @@ -33,7 +33,7 @@ SqliteUpdate::~SqliteUpdate() } SqliteUpdate::SqliteUpdate(SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, bool notIndexedKw, const QString &indexedBy, - const QList<QPair<QString,SqliteExpr*> > values, SqliteExpr *where, SqliteWith* with) + const QList<ColumnAndValue>& values, SqliteExpr *where, SqliteWith* with) : SqliteUpdate() { this->onConflict = onConflict; @@ -59,7 +59,7 @@ SqliteUpdate::SqliteUpdate(SqliteConflictAlgo onConflict, const QString &name1, if (with) with->setParent(this); - foreach (const ColumnAndValue& keyValue, keyValueMap) + for (const ColumnAndValue& keyValue : keyValueMap) keyValue.second->setParent(this); } @@ -70,7 +70,7 @@ SqliteStatement*SqliteUpdate::clone() SqliteExpr* SqliteUpdate::getValueForColumnSet(const QString& column) { - foreach (const ColumnAndValue& keyValue, keyValueMap) + for (const ColumnAndValue& keyValue : keyValueMap) { if (keyValue.first == column) return keyValue.second; @@ -81,8 +81,13 @@ SqliteExpr* SqliteUpdate::getValueForColumnSet(const QString& column) QStringList SqliteUpdate::getColumnsInStatement() { QStringList columns; - foreach (const ColumnAndValue& keyValue, keyValueMap) - columns += keyValue.first; + for (const ColumnAndValue& keyValue : keyValueMap) + { + if (keyValue.first.type() == QVariant::StringList) + columns += keyValue.first.toStringList(); + else + columns += keyValue.first.toString(); + } return columns; } @@ -105,20 +110,26 @@ TokenList SqliteUpdate::getColumnTokensInStatement() // for each 'expr' we get its first token, then locate it // in entire "setlist", get back 2 tokens to get what's before "=". TokenList list; - TokenList setListTokens = getTokenListFromNamedKey("setlist"); + TokenList setListTokens = getTokenListFromNamedKey("setlist", -1); int setListTokensSize = setListTokens.size(); - int colNameTokenIdx; + int end; + int start = 0; SqliteExpr* expr = nullptr; - foreach (const ColumnAndValue& keyValue, keyValueMap) + for (const ColumnAndValue& keyValue : keyValueMap) { expr = keyValue.second; - colNameTokenIdx = setListTokens.indexOf(expr->tokens[0]) - 2; - if (colNameTokenIdx < 0 || colNameTokenIdx > setListTokensSize) + end = setListTokens.indexOf(expr->tokens[0]); + if (end < 0 || end >= setListTokensSize) { qCritical() << "Went out of bounds while looking for column tokens in SqliteUpdate::getColumnTokensInStatement()."; continue; } - list << setListTokens[colNameTokenIdx]; + + // Before expression tokens there will be only column(s) token(s) + // and commans, and equal operator. Let's take only ID tokens, which are columns. + list += setListTokens.mid(start, end - start - 1).filter(Token::OTHER); + + start = end + expr->tokens.size(); } return list; } @@ -189,12 +200,17 @@ TokenList SqliteUpdate::rebuildTokensFromContents() builder.withKeyword("SET").withSpace(); bool first = true; - foreach (const ColumnAndValue& keyVal, keyValueMap) + for (const ColumnAndValue& keyVal : keyValueMap) { if (!first) builder.withOperator(",").withSpace(); - builder.withOther(keyVal.first, dialect).withSpace().withOperator("=").withStatement(keyVal.second); + if (keyVal.first.type() == QVariant::StringList) + builder.withParLeft().withOtherList(keyVal.first.toStringList(), dialect).withParRight(); + else + builder.withOther(keyVal.first.toString(), dialect); + + builder.withSpace().withOperator("=").withStatement(keyVal.second); first = false; } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h index 7d6e0c1..642473c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h @@ -13,13 +13,13 @@ class SqliteWith; class API_EXPORT SqliteUpdate : public SqliteQuery { public: - typedef QPair<QString,SqliteExpr*> ColumnAndValue; + typedef QPair<QVariant,SqliteExpr*> ColumnAndValue; SqliteUpdate(); SqliteUpdate(const SqliteUpdate& other); ~SqliteUpdate(); SqliteUpdate(SqliteConflictAlgo onConflict, const QString& name1, const QString& name2, - bool notIndexedKw, const QString& indexedBy, const QList<QPair<QString,SqliteExpr*> > values, + bool notIndexedKw, const QString& indexedBy, const QList<ColumnAndValue>& values, SqliteExpr* where, SqliteWith* with); SqliteStatement* clone(); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp new file mode 100644 index 0000000..ced9c2d --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp @@ -0,0 +1,152 @@ +#include "sqliteupsert.h" +#include "common/global.h" +#include "parser/ast/sqliteorderby.h" +#include "parser/ast/sqliteexpr.h" +#include "parser/statementtokenbuilder.h" +#include <QDebug> + +SqliteUpsert::SqliteUpsert() +{ + doNothing = true; +} + +SqliteUpsert::SqliteUpsert(const QList<SqliteOrderBy*>& conflictColumns, SqliteExpr* conflictWhere) +{ + this->conflictColumns = conflictColumns; + this->conflictWhere = conflictWhere; + + if (this->conflictWhere) + this->conflictWhere->setParent(this); + + for (SqliteOrderBy* idxCol : conflictColumns) + idxCol->setParent(this); + + doNothing = true; +} + +SqliteUpsert::SqliteUpsert(const QList<SqliteOrderBy*>& conflictColumns, SqliteExpr* conflictWhere, const QList<ColumnAndValue>& values, SqliteExpr* setWhere) +{ + this->conflictColumns = conflictColumns; + this->conflictWhere = conflictWhere; + this->keyValueMap = values; + this->setWhere = setWhere; + + if (this->conflictWhere) + this->conflictWhere->setParent(this); + + if (this->setWhere) + this->setWhere->setParent(this); + + for (SqliteOrderBy* idxCol : conflictColumns) + idxCol->setParent(this); + + doNothing = false; +} + +SqliteUpsert::SqliteUpsert(const SqliteUpsert& other) + : SqliteStatement(other), doNothing(other.doNothing) +{ + DEEP_COPY_COLLECTION(SqliteOrderBy, conflictColumns); + + // Special case of deep collection copy + SqliteExpr* newExpr = nullptr; + for (const ColumnAndValue& keyValue : other.keyValueMap) + { + newExpr = new SqliteExpr(*keyValue.second); + newExpr->setParent(this); + keyValueMap << ColumnAndValue(keyValue.first, newExpr); + } + + DEEP_COPY_FIELD(SqliteExpr, conflictWhere); + DEEP_COPY_FIELD(SqliteExpr, setWhere); +} + +SqliteStatement* SqliteUpsert::clone() +{ + return new SqliteUpsert(*this); +} + +TokenList SqliteUpsert::rebuildTokensFromContents() +{ + StatementTokenBuilder builder; + + builder.withKeyword("ON").withSpace().withKeyword("CONFLICT"); + if (!conflictColumns.isEmpty()) + { + builder.withSpace().withParLeft().withStatementList(conflictColumns).withParRight(); + if (conflictWhere) + builder.withSpace().withKeyword("WHERE").withStatement(conflictWhere); + } + + builder.withSpace().withKeyword("DO").withSpace(); + + if (doNothing) + { + builder.withKeyword("NOTHING"); + } + else + { + builder.withKeyword("UPDATE").withSpace().withKeyword("SET").withSpace(); + bool first = true; + for (const ColumnAndValue& keyVal : keyValueMap) + { + if (!first) + builder.withOperator(",").withSpace(); + + if (keyVal.first.type() == QVariant::StringList) + builder.withParLeft().withOtherList(keyVal.first.toStringList(), dialect).withParRight(); + else + builder.withOther(keyVal.first.toString(), dialect); + + builder.withSpace().withOperator("=").withStatement(keyVal.second); + first = false; + } + + if (setWhere) + builder.withSpace().withKeyword("WHERE").withStatement(setWhere); + } + + return builder.build(); +} + +QStringList SqliteUpsert::getColumnsInStatement() +{ + QStringList columns; + for (const ColumnAndValue& keyValue : keyValueMap) + { + if (keyValue.first.type() == QVariant::StringList) + columns += keyValue.first.toStringList(); + else + columns += keyValue.first.toString(); + } + + return columns; +} + +TokenList SqliteUpsert::getColumnTokensInStatement() +{ + // Alrorithm same as in UPDATE. See comments there for details. + TokenList list; + TokenList setListTokens = getTokenListFromNamedKey("setlist", -1); + int setListTokensSize = setListTokens.size(); + int end; + int start = 0; + SqliteExpr* expr = nullptr; + for (const ColumnAndValue& keyValue : keyValueMap) + { + expr = keyValue.second; + end = setListTokens.indexOf(expr->tokens[0]); + if (end < 0 || end >= setListTokensSize) + { + qCritical() << "Went out of bounds while looking for column tokens in SqliteUpdate::getColumnTokensInStatement()."; + continue; + } + + // Before expression tokens there will be only column(s) token(s) + // and commans, and equal operator. Let's take only ID tokens, which are columns. + list += setListTokens.mid(start, end - start - 1).filter(Token::OTHER); + + start = end + expr->tokens.size(); + } + return list; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h new file mode 100644 index 0000000..4a245cd --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h @@ -0,0 +1,35 @@ +#ifndef SQLITEUPSERT_H +#define SQLITEUPSERT_H + + +#include "sqlitestatement.h" +#include "sqliteindexedcolumn.h" + +class SqliteExpr; +class SqliteOrderBy; + +class SqliteUpsert : public SqliteStatement +{ + public: + typedef QPair<QVariant,SqliteExpr*> ColumnAndValue; + + SqliteUpsert(); + SqliteUpsert(const QList<SqliteOrderBy*>& conflictColumns, SqliteExpr* conflictWhere); + SqliteUpsert(const QList<SqliteOrderBy*>& conflictColumns, SqliteExpr* conflictWhere, const QList<ColumnAndValue>& values, SqliteExpr* setWhere); + SqliteUpsert(const SqliteUpsert& other); + + SqliteStatement* clone(); + + QList<SqliteOrderBy*> conflictColumns; + SqliteExpr* conflictWhere = nullptr; + QList<ColumnAndValue> keyValueMap; + SqliteExpr* setWhere = nullptr; + bool doNothing = false; + + protected: + TokenList rebuildTokensFromContents(); + QStringList getColumnsInStatement(); + TokenList getColumnTokensInStatement(); +}; + +#endif // SQLITEUPSERT_H diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp index 2088ff2..bc8112e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp @@ -106,6 +106,8 @@ void initKeywords() keywords3["NOTNULL"] = TK3_NOTNULL; keywords3["NOT"] = TK3_NOT; keywords3["NO"] = TK3_NO; + keywords3["DO"] = TK3_DO; + keywords3["NOTHING"] = TK3_NOTHING; keywords3["NULL"] = TK3_NULL; keywords3["LIKE"] = TK3_LIKE_KW; keywords3["CASCADE"] = TK3_CASCADE; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lemon.c b/SQLiteStudio3/coreSQLiteStudio/parser/lemon.c new file mode 100644 index 0000000..4a2d68d --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/lemon.c @@ -0,0 +1,5044 @@ +/* + * This is a version of lemon that works with grammar files used by SQLiteStudio. + * It's taken from one of older SQLite versions. Code from new SQLite codebase is incompatible, unfortunately. + * +** This file contains all sources (including headers) to the LEMON +** LALR(1) parser generator. The sources have been combined into a +** single file to make it easy to include LEMON in the source tree +** and Makefile of another program. +** +** The author of this program disclaims copyright. +*/ +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <assert.h> + +#ifndef __WIN32__ +# if defined(_WIN32) || defined(WIN32) +# define __WIN32__ +# endif +#endif + +#ifdef __WIN32__ +#ifdef __cplusplus +extern "C" { +#endif +extern int access(const char *path, int mode); +#ifdef __cplusplus +} +#endif +#else +#include <unistd.h> +#endif + +/* #define PRIVATE static */ +#define PRIVATE + +#ifdef TEST +#define MAXRHS 5 /* Set low to exercise exception code */ +#else +#define MAXRHS 1000 +#endif + +static int showPrecedenceConflict = 0; +static char *msort(char*,char**,int(*)(const char*,const char*)); + +/* +** Compilers are getting increasingly pedantic about type conversions +** as C evolves ever closer to Ada.... To work around the latest problems +** we have to define the following variant of strlen(). +*/ +#define lemonStrlen(X) ((int)strlen(X)) + +/* +** Compilers are starting to complain about the use of sprintf() and strcpy(), +** saying they are unsafe. So we define our own versions of those routines too. +** +** There are three routines here: lemon_sprintf(), lemon_vsprintf(), and +** lemon_addtext(). The first two are replacements for sprintf() and vsprintf(). +** The third is a helper routine for vsnprintf() that adds texts to the end of a +** buffer, making sure the buffer is always zero-terminated. +** +** The string formatter is a minimal subset of stdlib sprintf() supporting only +** a few simply conversions: +** +** %d +** %s +** %.*s +** +*/ +static void lemon_addtext( + char *zBuf, /* The buffer to which text is added */ + int *pnUsed, /* Slots of the buffer used so far */ + const char *zIn, /* Text to add */ + int nIn, /* Bytes of text to add. -1 to use strlen() */ + int iWidth /* Field width. Negative to left justify */ +){ + if( nIn<0 ) for(nIn=0; zIn[nIn]; nIn++){} + while( iWidth>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth--; } + if( nIn==0 ) return; + memcpy(&zBuf[*pnUsed], zIn, nIn); + *pnUsed += nIn; + while( (-iWidth)>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth++; } + zBuf[*pnUsed] = 0; +} +static int lemon_vsprintf(char *str, const char *zFormat, va_list ap){ + int i, j, k, c; + int nUsed = 0; + const char *z; + char zTemp[50]; + str[0] = 0; + for(i=j=0; (c = zFormat[i])!=0; i++){ + if( c=='%' ){ + int iWidth = 0; + lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0); + c = zFormat[++i]; + if( isdigit(c) || (c=='-' && isdigit(zFormat[i+1])) ){ + if( c=='-' ) i++; + while( isdigit(zFormat[i]) ) iWidth = iWidth*10 + zFormat[i++] - '0'; + if( c=='-' ) iWidth = -iWidth; + c = zFormat[i]; + } + if( c=='d' ){ + int v = va_arg(ap, int); + if( v<0 ){ + lemon_addtext(str, &nUsed, "-", 1, iWidth); + v = -v; + }else if( v==0 ){ + lemon_addtext(str, &nUsed, "0", 1, iWidth); + } + k = 0; + while( v>0 ){ + k++; + zTemp[sizeof(zTemp)-k] = (v%10) + '0'; + v /= 10; + } + lemon_addtext(str, &nUsed, &zTemp[sizeof(zTemp)-k], k, iWidth); + }else if( c=='s' ){ + z = va_arg(ap, const char*); + lemon_addtext(str, &nUsed, z, -1, iWidth); + }else if( c=='.' && memcmp(&zFormat[i], ".*s", 3)==0 ){ + i += 2; + k = va_arg(ap, int); + z = va_arg(ap, const char*); + lemon_addtext(str, &nUsed, z, k, iWidth); + }else if( c=='%' ){ + lemon_addtext(str, &nUsed, "%", 1, 0); + }else{ + fprintf(stderr, "illegal format\n"); + exit(1); + } + j = i+1; + } + } + lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0); + return nUsed; +} +static int lemon_sprintf(char *str, const char *format, ...){ + va_list ap; + int rc; + va_start(ap, format); + rc = lemon_vsprintf(str, format, ap); + va_end(ap); + return rc; +} +static void lemon_strcpy(char *dest, const char *src){ + while( (*(dest++) = *(src++))!=0 ){} +} +static void lemon_strcat(char *dest, const char *src){ + while( *dest ) dest++; + lemon_strcpy(dest, src); +} + + +/* a few forward declarations... */ +struct rule; +struct lemon; +struct action; + +static struct action *Action_new(void); +static struct action *Action_sort(struct action *); + +/********** From the file "build.h" ************************************/ +void FindRulePrecedences(); +void FindFirstSets(); +void FindStates(); +void FindLinks(); +void FindFollowSets(); +void FindActions(); + +/********* From the file "configlist.h" *********************************/ +void Configlist_init(void); +struct config *Configlist_add(struct rule *, int); +struct config *Configlist_addbasis(struct rule *, int); +void Configlist_closure(struct lemon *); +void Configlist_sort(void); +void Configlist_sortbasis(void); +struct config *Configlist_return(void); +struct config *Configlist_basis(void); +void Configlist_eat(struct config *); +void Configlist_reset(void); + +/********* From the file "error.h" ***************************************/ +void ErrorMsg(const char *, int,const char *, ...); + +/****** From the file "option.h" ******************************************/ +enum option_type { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR, + OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR}; +struct s_options { + enum option_type type; + const char *label; + char *arg; + const char *message; +}; +int OptInit(char**,struct s_options*,FILE*); +int OptNArgs(void); +char *OptArg(int); +void OptErr(int); +void OptPrint(void); + +/******** From the file "parse.h" *****************************************/ +void Parse(struct lemon *lemp); + +/********* From the file "plink.h" ***************************************/ +struct plink *Plink_new(void); +void Plink_add(struct plink **, struct config *); +void Plink_copy(struct plink **, struct plink *); +void Plink_delete(struct plink *); + +/********** From the file "report.h" *************************************/ +void Reprint(struct lemon *); +void ReportOutput(struct lemon *); +void ReportTable(struct lemon *, int); +void ReportHeader(struct lemon *); +void CompressTables(struct lemon *); +void ResortStates(struct lemon *); + +/********** From the file "set.h" ****************************************/ +void SetSize(int); /* All sets will be of size N */ +char *SetNew(void); /* A new set for element 0..N */ +void SetFree(char*); /* Deallocate a set */ +int SetAdd(char*,int); /* Add element to a set */ +int SetUnion(char *,char *); /* A <- A U B, thru element N */ +#define SetFind(X,Y) (X[Y]) /* True if Y is in set X */ + +/********** From the file "struct.h" *************************************/ +/* +** Principal data structures for the LEMON parser generator. +*/ + +typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean; + +/* Symbols (terminals and nonterminals) of the grammar are stored +** in the following: */ +enum symbol_type { + TERMINAL, + NONTERMINAL, + MULTITERMINAL +}; +enum e_assoc { + LEFT, + RIGHT, + NONE, + UNK +}; +struct symbol { + const char *name; /* Name of the symbol */ + int index; /* Index number for this symbol */ + enum symbol_type type; /* Symbols are all either TERMINALS or NTs */ + struct rule *rule; /* Linked list of rules of this (if an NT) */ + struct symbol *fallback; /* fallback token in case this token doesn't parse */ + int prec; /* Precedence if defined (-1 otherwise) */ + enum e_assoc assoc; /* Associativity if precedence is defined */ + char *firstset; /* First-set for all rules of this symbol */ + Boolean lambda; /* True if NT and can generate an empty string */ + int useCnt; /* Number of times used */ + char *destructor; /* Code which executes whenever this symbol is + ** popped from the stack during error processing */ + int destLineno; /* Line number for start of destructor */ + char *datatype; /* The data type of information held by this + ** object. Only used if type==NONTERMINAL */ + int dtnum; /* The data type number. In the parser, the value + ** stack is a union. The .yy%d element of this + ** union is the correct data type for this object */ + /* The following fields are used by MULTITERMINALs only */ + int nsubsym; /* Number of constituent symbols in the MULTI */ + struct symbol **subsym; /* Array of constituent symbols */ +}; + +/* Each production rule in the grammar is stored in the following +** structure. */ +struct rule { + struct symbol *lhs; /* Left-hand side of the rule */ + const char *lhsalias; /* Alias for the LHS (NULL if none) */ + int lhsStart; /* True if left-hand side is the start symbol */ + int ruleline; /* Line number for the rule */ + int nrhs; /* Number of RHS symbols */ + struct symbol **rhs; /* The RHS symbols */ + const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ + int line; /* Line number at which code begins */ + const char *code; /* The code executed when this rule is reduced */ + struct symbol *precsym; /* Precedence symbol for this rule */ + int index; /* An index number for this rule */ + Boolean canReduce; /* True if this rule is ever reduced */ + struct rule *nextlhs; /* Next rule with the same LHS */ + struct rule *next; /* Next rule in the global list */ +}; + +/* A configuration is a production rule of the grammar together with +** a mark (dot) showing how much of that rule has been processed so far. +** Configurations also contain a follow-set which is a list of terminal +** symbols which are allowed to immediately follow the end of the rule. +** Every configuration is recorded as an instance of the following: */ +enum cfgstatus { + COMPLETE, + INCOMPLETE +}; +struct config { + struct rule *rp; /* The rule upon which the configuration is based */ + int dot; /* The parse point */ + char *fws; /* Follow-set for this configuration only */ + struct plink *fplp; /* Follow-set forward propagation links */ + struct plink *bplp; /* Follow-set backwards propagation links */ + struct state *stp; /* Pointer to state which contains this */ + enum cfgstatus status; /* used during followset and shift computations */ + struct config *next; /* Next configuration in the state */ + struct config *bp; /* The next basis configuration */ +}; + +enum e_action { + SHIFT, + ACCEPT, + REDUCE, + ERROR, + SSCONFLICT, /* A shift/shift conflict */ + SRCONFLICT, /* Was a reduce, but part of a conflict */ + RRCONFLICT, /* Was a reduce, but part of a conflict */ + SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ + RD_RESOLVED, /* Was reduce. Precedence resolved conflict */ + NOT_USED /* Deleted by compression */ +}; + +/* Every shift or reduce operation is stored as one of the following */ +struct action { + struct symbol *sp; /* The look-ahead symbol */ + enum e_action type; + union { + struct state *stp; /* The new state, if a shift */ + struct rule *rp; /* The rule, if a reduce */ + } x; + struct action *next; /* Next action for this state */ + struct action *collide; /* Next action with the same hash */ +}; + +/* Each state of the generated parser's finite state machine +** is encoded as an instance of the following structure. */ +struct state { + struct config *bp; /* The basis configurations for this state */ + struct config *cfp; /* All configurations in this set */ + int statenum; /* Sequential number for this state */ + struct action *ap; /* Array of actions for this state */ + int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ + int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ + int iDflt; /* Default action */ +}; +#define NO_OFFSET (-2147483647) + +/* A followset propagation link indicates that the contents of one +** configuration followset should be propagated to another whenever +** the first changes. */ +struct plink { + struct config *cfp; /* The configuration to which linked */ + struct plink *next; /* The next propagate link */ +}; + +/* The state vector for the entire parser generator is recorded as +** follows. (LEMON uses no global variables and makes little use of +** static variables. Fields in the following structure can be thought +** of as begin global variables in the program.) */ +struct lemon { + struct state **sorted; /* Table of states sorted by state number */ + struct rule *rule; /* List of all rules */ + int nstate; /* Number of states */ + int nrule; /* Number of rules */ + int nsymbol; /* Number of terminal and nonterminal symbols */ + int nterminal; /* Number of terminal symbols */ + struct symbol **symbols; /* Sorted array of pointers to symbols */ + int errorcnt; /* Number of errors */ + struct symbol *errsym; /* The error symbol */ + struct symbol *wildcard; /* Token that matches anything */ + char *name; /* Name of the generated parser */ + char *arg; /* Declaration of the 3th argument to parser */ + char *tokentype; /* Type of terminal symbols in the parser stack */ + char *vartype; /* The default type of non-terminal symbols */ + char *start; /* Name of the start symbol for the grammar */ + char *stacksize; /* Size of the parser stack */ + char *include; /* Code to put at the start of the C file */ + char *error; /* Code to execute when an error is seen */ + char *overflow; /* Code to execute on a stack overflow */ + char *failure; /* Code to execute on parser failure */ + char *accept; /* Code to execute when the parser excepts */ + char *extracode; /* Code appended to the generated file */ + char *tokendest; /* Code to execute to destroy token data */ + char *vardest; /* Code for the default non-terminal destructor */ + char *filename; /* Name of the input file */ + char *outname; /* Name of the current output file */ + char *tokenprefix; /* A prefix added to token names in the .h file */ + int nconflict; /* Number of parsing conflicts */ + int tablesize; /* Size of the parse tables */ + int basisflag; /* Print only basis configurations */ + int has_fallback; /* True if any %fallback is seen in the grammar */ + int nolinenosflag; /* True if #line statements should not be printed */ + char *argv0; /* Name of the program */ +}; + +#define MemoryCheck(X) if((X)==0){ \ + extern void memory_error(); \ + memory_error(); \ +} + +/**************** From the file "table.h" *********************************/ +/* +** All code in this file has been automatically generated +** from a specification in the file +** "table.q" +** by the associative array code building program "aagen". +** Do not edit this file! Instead, edit the specification +** file, then rerun aagen. +*/ +/* +** Code for processing tables in the LEMON parser generator. +*/ +/* Routines for handling a strings */ + +const char *Strsafe(const char *); + +void Strsafe_init(void); +int Strsafe_insert(const char *); +const char *Strsafe_find(const char *); + +/* Routines for handling symbols of the grammar */ + +struct symbol *Symbol_new(const char *); +int Symbolcmpp(const void *, const void *); +void Symbol_init(void); +int Symbol_insert(struct symbol *, const char *); +struct symbol *Symbol_find(const char *); +struct symbol *Symbol_Nth(int); +int Symbol_count(void); +struct symbol **Symbol_arrayof(void); + +/* Routines to manage the state table */ + +int Configcmp(const char *, const char *); +struct state *State_new(void); +void State_init(void); +int State_insert(struct state *, struct config *); +struct state *State_find(struct config *); +struct state **State_arrayof(/* */); + +/* Routines used for efficiency in Configlist_add */ + +void Configtable_init(void); +int Configtable_insert(struct config *); +struct config *Configtable_find(struct config *); +void Configtable_clear(int(*)(struct config *)); + +/****************** From the file "action.c" *******************************/ +/* +** Routines processing parser actions in the LEMON parser generator. +*/ + +/* Allocate a new parser action */ +static struct action *Action_new(void){ + static struct action *freelist = 0; + struct action *newaction; + + if( freelist==0 ){ + int i; + int amt = 100; + freelist = (struct action *)calloc(amt, sizeof(struct action)); + if( freelist==0 ){ + fprintf(stderr,"Unable to allocate memory for a new parser action."); + exit(1); + } + for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; + freelist[amt-1].next = 0; + } + newaction = freelist; + freelist = freelist->next; + return newaction; +} + +/* Compare two actions for sorting purposes. Return negative, zero, or +** positive if the first action is less than, equal to, or greater than +** the first +*/ +static int actioncmp( + struct action *ap1, + struct action *ap2 +){ + int rc; + rc = ap1->sp->index - ap2->sp->index; + if( rc==0 ){ + rc = (int)ap1->type - (int)ap2->type; + } + if( rc==0 && ap1->type==REDUCE ){ + rc = ap1->x.rp->index - ap2->x.rp->index; + } + if( rc==0 ){ + rc = (int) (ap2 - ap1); + } + return rc; +} + +/* Sort parser actions */ +static struct action *Action_sort( + struct action *ap +){ + ap = (struct action *)msort((char *)ap,(char **)&ap->next, + (int(*)(const char*,const char*))actioncmp); + return ap; +} + +void Action_add( + struct action **app, + enum e_action type, + struct symbol *sp, + char *arg +){ + struct action *newaction; + newaction = Action_new(); + newaction->next = *app; + *app = newaction; + newaction->type = type; + newaction->sp = sp; + if( type==SHIFT ){ + newaction->x.stp = (struct state *)arg; + }else{ + newaction->x.rp = (struct rule *)arg; + } +} +/********************** New code to implement the "acttab" module ***********/ +/* +** This module implements routines use to construct the yy_action[] table. +*/ + +/* +** The state of the yy_action table under construction is an instance of +** the following structure. +** +** The yy_action table maps the pair (state_number, lookahead) into an +** action_number. The table is an array of integers pairs. The state_number +** determines an initial offset into the yy_action array. The lookahead +** value is then added to this initial offset to get an index X into the +** yy_action array. If the aAction[X].lookahead equals the value of the +** of the lookahead input, then the value of the action_number output is +** aAction[X].action. If the lookaheads do not match then the +** default action for the state_number is returned. +** +** All actions associated with a single state_number are first entered +** into aLookahead[] using multiple calls to acttab_action(). Then the +** actions for that single state_number are placed into the aAction[] +** array with a single call to acttab_insert(). The acttab_insert() call +** also resets the aLookahead[] array in preparation for the next +** state number. +*/ +struct lookahead_action { + int lookahead; /* Value of the lookahead token */ + int action; /* Action to take on the given lookahead */ +}; +typedef struct acttab acttab; +struct acttab { + int nAction; /* Number of used slots in aAction[] */ + int nActionAlloc; /* Slots allocated for aAction[] */ + struct lookahead_action + *aAction, /* The yy_action[] table under construction */ + *aLookahead; /* A single new transaction set */ + int mnLookahead; /* Minimum aLookahead[].lookahead */ + int mnAction; /* Action associated with mnLookahead */ + int mxLookahead; /* Maximum aLookahead[].lookahead */ + int nLookahead; /* Used slots in aLookahead[] */ + int nLookaheadAlloc; /* Slots allocated in aLookahead[] */ +}; + +/* Return the number of entries in the yy_action table */ +#define acttab_size(X) ((X)->nAction) + +/* The value for the N-th entry in yy_action */ +#define acttab_yyaction(X,N) ((X)->aAction[N].action) + +/* The value for the N-th entry in yy_lookahead */ +#define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead) + +/* Free all memory associated with the given acttab */ +void acttab_free(acttab *p){ + free( p->aAction ); + free( p->aLookahead ); + free( p ); +} + +/* Allocate a new acttab structure */ +acttab *acttab_alloc(void){ + acttab *p = (acttab *) calloc( 1, sizeof(*p) ); + if( p==0 ){ + fprintf(stderr,"Unable to allocate memory for a new acttab."); + exit(1); + } + memset(p, 0, sizeof(*p)); + return p; +} + +/* Add a new action to the current transaction set. +** +** This routine is called once for each lookahead for a particular +** state. +*/ +void acttab_action(acttab *p, int lookahead, int action){ + if( p->nLookahead>=p->nLookaheadAlloc ){ + p->nLookaheadAlloc += 25; + p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead, + sizeof(p->aLookahead[0])*p->nLookaheadAlloc ); + if( p->aLookahead==0 ){ + fprintf(stderr,"malloc failed\n"); + exit(1); + } + } + if( p->nLookahead==0 ){ + p->mxLookahead = lookahead; + p->mnLookahead = lookahead; + p->mnAction = action; + }else{ + if( p->mxLookahead<lookahead ) p->mxLookahead = lookahead; + if( p->mnLookahead>lookahead ){ + p->mnLookahead = lookahead; + p->mnAction = action; + } + } + p->aLookahead[p->nLookahead].lookahead = lookahead; + p->aLookahead[p->nLookahead].action = action; + p->nLookahead++; +} + +/* +** Add the transaction set built up with prior calls to acttab_action() +** into the current action table. Then reset the transaction set back +** to an empty set in preparation for a new round of acttab_action() calls. +** +** Return the offset into the action table of the new transaction. +*/ +int acttab_insert(acttab *p){ + int i, j, k, n; + assert( p->nLookahead>0 ); + + /* Make sure we have enough space to hold the expanded action table + ** in the worst case. The worst case occurs if the transaction set + ** must be appended to the current action table + */ + n = p->mxLookahead + 1; + if( p->nAction + n >= p->nActionAlloc ){ + int oldAlloc = p->nActionAlloc; + p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20; + p->aAction = (struct lookahead_action *) realloc( p->aAction, + sizeof(p->aAction[0])*p->nActionAlloc); + if( p->aAction==0 ){ + fprintf(stderr,"malloc failed\n"); + exit(1); + } + for(i=oldAlloc; i<p->nActionAlloc; i++){ + p->aAction[i].lookahead = -1; + p->aAction[i].action = -1; + } + } + + /* Scan the existing action table looking for an offset that is a + ** duplicate of the current transaction set. Fall out of the loop + ** if and when the duplicate is found. + ** + ** i is the index in p->aAction[] where p->mnLookahead is inserted. + */ + for(i=p->nAction-1; i>=0; i--){ + if( p->aAction[i].lookahead==p->mnLookahead ){ + /* All lookaheads and actions in the aLookahead[] transaction + ** must match against the candidate aAction[i] entry. */ + if( p->aAction[i].action!=p->mnAction ) continue; + for(j=0; j<p->nLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + if( k<0 || k>=p->nAction ) break; + if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break; + if( p->aLookahead[j].action!=p->aAction[k].action ) break; + } + if( j<p->nLookahead ) continue; + + /* No possible lookahead value that is not in the aLookahead[] + ** transaction is allowed to match aAction[i] */ + n = 0; + for(j=0; j<p->nAction; j++){ + if( p->aAction[j].lookahead<0 ) continue; + if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++; + } + if( n==p->nLookahead ){ + break; /* An exact match is found at offset i */ + } + } + } + + /* If no existing offsets exactly match the current transaction, find an + ** an empty offset in the aAction[] table in which we can add the + ** aLookahead[] transaction. + */ + if( i<0 ){ + /* Look for holes in the aAction[] table that fit the current + ** aLookahead[] transaction. Leave i set to the offset of the hole. + ** If no holes are found, i is left at p->nAction, which means the + ** transaction will be appended. */ + for(i=0; i<p->nActionAlloc - p->mxLookahead; i++){ + if( p->aAction[i].lookahead<0 ){ + for(j=0; j<p->nLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + if( k<0 ) break; + if( p->aAction[k].lookahead>=0 ) break; + } + if( j<p->nLookahead ) continue; + for(j=0; j<p->nAction; j++){ + if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break; + } + if( j==p->nAction ){ + break; /* Fits in empty slots */ + } + } + } + } + /* Insert transaction set at index i. */ + for(j=0; j<p->nLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + p->aAction[k] = p->aLookahead[j]; + if( k>=p->nAction ) p->nAction = k+1; + } + p->nLookahead = 0; + + /* Return the offset that is added to the lookahead in order to get the + ** index into yy_action of the action */ + return i - p->mnLookahead; +} + +/********************** From the file "build.c" *****************************/ +/* +** Routines to construction the finite state machine for the LEMON +** parser generator. +*/ + +/* Find a precedence symbol of every rule in the grammar. +** +** Those rules which have a precedence symbol coded in the input +** grammar using the "[symbol]" construct will already have the +** rp->precsym field filled. Other rules take as their precedence +** symbol the first RHS symbol with a defined precedence. If there +** are not RHS symbols with a defined precedence, the precedence +** symbol field is left blank. +*/ +void FindRulePrecedences(struct lemon *xp) +{ + struct rule *rp; + for(rp=xp->rule; rp; rp=rp->next){ + if( rp->precsym==0 ){ + int i, j; + for(i=0; i<rp->nrhs && rp->precsym==0; i++){ + struct symbol *sp = rp->rhs[i]; + if( sp->type==MULTITERMINAL ){ + for(j=0; j<sp->nsubsym; j++){ + if( sp->subsym[j]->prec>=0 ){ + rp->precsym = sp->subsym[j]; + break; + } + } + }else if( sp->prec>=0 ){ + rp->precsym = rp->rhs[i]; + } + } + } + } + return; +} + +/* Find all nonterminals which will generate the empty string. +** Then go back and compute the first sets of every nonterminal. +** The first set is the set of all terminal symbols which can begin +** a string generated by that nonterminal. +*/ +void FindFirstSets(struct lemon *lemp) +{ + int i, j; + struct rule *rp; + int progress; + + for(i=0; i<lemp->nsymbol; i++){ + lemp->symbols[i]->lambda = LEMON_FALSE; + } + for(i=lemp->nterminal; i<lemp->nsymbol; i++){ + lemp->symbols[i]->firstset = SetNew(); + } + + /* First compute all lambdas */ + do{ + progress = 0; + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->lhs->lambda ) continue; + for(i=0; i<rp->nrhs; i++){ + struct symbol *sp = rp->rhs[i]; + assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE ); + if( sp->lambda==LEMON_FALSE ) break; + } + if( i==rp->nrhs ){ + rp->lhs->lambda = LEMON_TRUE; + progress = 1; + } + } + }while( progress ); + + /* Now compute all first sets */ + do{ + struct symbol *s1, *s2; + progress = 0; + for(rp=lemp->rule; rp; rp=rp->next){ + s1 = rp->lhs; + for(i=0; i<rp->nrhs; i++){ + s2 = rp->rhs[i]; + if( s2->type==TERMINAL ){ + progress += SetAdd(s1->firstset,s2->index); + break; + }else if( s2->type==MULTITERMINAL ){ + for(j=0; j<s2->nsubsym; j++){ + progress += SetAdd(s1->firstset,s2->subsym[j]->index); + } + break; + }else if( s1==s2 ){ + if( s1->lambda==LEMON_FALSE ) break; + }else{ + progress += SetUnion(s1->firstset,s2->firstset); + if( s2->lambda==LEMON_FALSE ) break; + } + } + } + }while( progress ); + return; +} + +/* Compute all LR(0) states for the grammar. Links +** are added to between some states so that the LR(1) follow sets +** can be computed later. +*/ +PRIVATE struct state *getstate(struct lemon *); /* forward reference */ +void FindStates(struct lemon *lemp) +{ + struct symbol *sp; + struct rule *rp; + + Configlist_init(); + + /* Find the start symbol */ + if( lemp->start ){ + sp = Symbol_find(lemp->start); + if( sp==0 ){ + ErrorMsg(lemp->filename,0, +"The specified start symbol \"%s\" is not \ +in a nonterminal of the grammar. \"%s\" will be used as the start \ +symbol instead.",lemp->start,lemp->rule->lhs->name); + lemp->errorcnt++; + sp = lemp->rule->lhs; + } + }else{ + sp = lemp->rule->lhs; + } + + /* Make sure the start symbol doesn't occur on the right-hand side of + ** any rule. Report an error if it does. (YACC would generate a new + ** start symbol in this case.) */ + for(rp=lemp->rule; rp; rp=rp->next){ + int i; + for(i=0; i<rp->nrhs; i++){ + if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */ + ErrorMsg(lemp->filename,0, +"The start symbol \"%s\" occurs on the \ +right-hand side of a rule. This will result in a parser which \ +does not work properly.",sp->name); + lemp->errorcnt++; + } + } + } + + /* The basis configuration set for the first state + ** is all rules which have the start symbol as their + ** left-hand side */ + for(rp=sp->rule; rp; rp=rp->nextlhs){ + struct config *newcfp; + rp->lhsStart = 1; + newcfp = Configlist_addbasis(rp,0); + SetAdd(newcfp->fws,0); + } + + /* Compute the first state. All other states will be + ** computed automatically during the computation of the first one. + ** The returned pointer to the first state is not used. */ + (void)getstate(lemp); + return; +} + +/* Return a pointer to a state which is described by the configuration +** list which has been built from calls to Configlist_add. +*/ +PRIVATE void buildshifts(struct lemon *, struct state *); /* Forwd ref */ +PRIVATE struct state *getstate(struct lemon *lemp) +{ + struct config *cfp, *bp; + struct state *stp; + + /* Extract the sorted basis of the new state. The basis was constructed + ** by prior calls to "Configlist_addbasis()". */ + Configlist_sortbasis(); + bp = Configlist_basis(); + + /* Get a state with the same basis */ + stp = State_find(bp); + if( stp ){ + /* A state with the same basis already exists! Copy all the follow-set + ** propagation links from the state under construction into the + ** preexisting state, then return a pointer to the preexisting state */ + struct config *x, *y; + for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){ + Plink_copy(&y->bplp,x->bplp); + Plink_delete(x->fplp); + x->fplp = x->bplp = 0; + } + cfp = Configlist_return(); + Configlist_eat(cfp); + }else{ + /* This really is a new state. Construct all the details */ + Configlist_closure(lemp); /* Compute the configuration closure */ + Configlist_sort(); /* Sort the configuration closure */ + cfp = Configlist_return(); /* Get a pointer to the config list */ + stp = State_new(); /* A new state structure */ + MemoryCheck(stp); + stp->bp = bp; /* Remember the configuration basis */ + stp->cfp = cfp; /* Remember the configuration closure */ + stp->statenum = lemp->nstate++; /* Every state gets a sequence number */ + stp->ap = 0; /* No actions, yet. */ + State_insert(stp,stp->bp); /* Add to the state table */ + buildshifts(lemp,stp); /* Recursively compute successor states */ + } + return stp; +} + +/* +** Return true if two symbols are the same. +*/ +int same_symbol(struct symbol *a, struct symbol *b) +{ + int i; + if( a==b ) return 1; + if( a->type!=MULTITERMINAL ) return 0; + if( b->type!=MULTITERMINAL ) return 0; + if( a->nsubsym!=b->nsubsym ) return 0; + for(i=0; i<a->nsubsym; i++){ + if( a->subsym[i]!=b->subsym[i] ) return 0; + } + return 1; +} + +/* Construct all successor states to the given state. A "successor" +** state is any state which can be reached by a shift action. +*/ +PRIVATE void buildshifts(struct lemon *lemp, struct state *stp) +{ + struct config *cfp; /* For looping thru the config closure of "stp" */ + struct config *bcfp; /* For the inner loop on config closure of "stp" */ + struct config *newcfg; /* */ + struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ + struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ + struct state *newstp; /* A pointer to a successor state */ + + /* Each configuration becomes complete after it contibutes to a successor + ** state. Initially, all configurations are incomplete */ + for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE; + + /* Loop through all configurations of the state "stp" */ + for(cfp=stp->cfp; cfp; cfp=cfp->next){ + if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */ + if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */ + Configlist_reset(); /* Reset the new config set */ + sp = cfp->rp->rhs[cfp->dot]; /* Symbol after the dot */ + + /* For every configuration in the state "stp" which has the symbol "sp" + ** following its dot, add the same configuration to the basis set under + ** construction but with the dot shifted one symbol to the right. */ + for(bcfp=cfp; bcfp; bcfp=bcfp->next){ + if( bcfp->status==COMPLETE ) continue; /* Already used */ + if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */ + bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */ + if( !same_symbol(bsp,sp) ) continue; /* Must be same as for "cfp" */ + bcfp->status = COMPLETE; /* Mark this config as used */ + newcfg = Configlist_addbasis(bcfp->rp,bcfp->dot+1); + Plink_add(&newcfg->bplp,bcfp); + } + + /* Get a pointer to the state described by the basis configuration set + ** constructed in the preceding loop */ + newstp = getstate(lemp); + + /* The state "newstp" is reached from the state "stp" by a shift action + ** on the symbol "sp" */ + if( sp->type==MULTITERMINAL ){ + int i; + for(i=0; i<sp->nsubsym; i++){ + Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp); + } + }else{ + Action_add(&stp->ap,SHIFT,sp,(char *)newstp); + } + } +} + +/* +** Construct the propagation links +*/ +void FindLinks(struct lemon *lemp) +{ + int i; + struct config *cfp, *other; + struct state *stp; + struct plink *plp; + + /* Housekeeping detail: + ** Add to every propagate link a pointer back to the state to + ** which the link is attached. */ + for(i=0; i<lemp->nstate; i++){ + stp = lemp->sorted[i]; + for(cfp=stp->cfp; cfp; cfp=cfp->next){ + cfp->stp = stp; + } + } + + /* Convert all backlinks into forward links. Only the forward + ** links are used in the follow-set computation. */ + for(i=0; i<lemp->nstate; i++){ + stp = lemp->sorted[i]; + for(cfp=stp->cfp; cfp; cfp=cfp->next){ + for(plp=cfp->bplp; plp; plp=plp->next){ + other = plp->cfp; + Plink_add(&other->fplp,cfp); + } + } + } +} + +/* Compute all followsets. +** +** A followset is the set of all symbols which can come immediately +** after a configuration. +*/ +void FindFollowSets(struct lemon *lemp) +{ + int i; + struct config *cfp; + struct plink *plp; + int progress; + int change; + + for(i=0; i<lemp->nstate; i++){ + for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ + cfp->status = INCOMPLETE; + } + } + + do{ + progress = 0; + for(i=0; i<lemp->nstate; i++){ + for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ + if( cfp->status==COMPLETE ) continue; + for(plp=cfp->fplp; plp; plp=plp->next){ + change = SetUnion(plp->cfp->fws,cfp->fws); + if( change ){ + plp->cfp->status = INCOMPLETE; + progress = 1; + } + } + cfp->status = COMPLETE; + } + } + }while( progress ); +} + +static int resolve_conflict(struct action *,struct action *); + +/* Compute the reduce actions, and resolve conflicts. +*/ +void FindActions(struct lemon *lemp) +{ + int i,j; + struct config *cfp; + struct state *stp; + struct symbol *sp; + struct rule *rp; + + /* Add all of the reduce actions + ** A reduce action is added for each element of the followset of + ** a configuration which has its dot at the extreme right. + */ + for(i=0; i<lemp->nstate; i++){ /* Loop over all states */ + stp = lemp->sorted[i]; + for(cfp=stp->cfp; cfp; cfp=cfp->next){ /* Loop over all configurations */ + if( cfp->rp->nrhs==cfp->dot ){ /* Is dot at extreme right? */ + for(j=0; j<lemp->nterminal; j++){ + if( SetFind(cfp->fws,j) ){ + /* Add a reduce action to the state "stp" which will reduce by the + ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */ + Action_add(&stp->ap,REDUCE,lemp->symbols[j],(char *)cfp->rp); + } + } + } + } + } + + /* Add the accepting token */ + if( lemp->start ){ + sp = Symbol_find(lemp->start); + if( sp==0 ) sp = lemp->rule->lhs; + }else{ + sp = lemp->rule->lhs; + } + /* Add to the first state (which is always the starting state of the + ** finite state machine) an action to ACCEPT if the lookahead is the + ** start nonterminal. */ + Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0); + + /* Resolve conflicts */ + for(i=0; i<lemp->nstate; i++){ + struct action *ap, *nap; + struct state *stp; + stp = lemp->sorted[i]; + /* assert( stp->ap ); */ + stp->ap = Action_sort(stp->ap); + for(ap=stp->ap; ap && ap->next; ap=ap->next){ + for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){ + /* The two actions "ap" and "nap" have the same lookahead. + ** Figure out which one should be used */ + lemp->nconflict += resolve_conflict(ap,nap); + } + } + } + + /* Report an error for each rule that can never be reduced. */ + for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE; + for(i=0; i<lemp->nstate; i++){ + struct action *ap; + for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ + if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE; + } + } + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->canReduce ) continue; + ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n"); + lemp->errorcnt++; + } +} + +/* Resolve a conflict between the two given actions. If the +** conflict can't be resolved, return non-zero. +** +** NO LONGER TRUE: +** To resolve a conflict, first look to see if either action +** is on an error rule. In that case, take the action which +** is not associated with the error rule. If neither or both +** actions are associated with an error rule, then try to +** use precedence to resolve the conflict. +** +** If either action is a SHIFT, then it must be apx. This +** function won't work if apx->type==REDUCE and apy->type==SHIFT. +*/ +static int resolve_conflict( + struct action *apx, + struct action *apy +){ + struct symbol *spx, *spy; + int errcnt = 0; + assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */ + if( apx->type==SHIFT && apy->type==SHIFT ){ + apy->type = SSCONFLICT; + errcnt++; + } + if( apx->type==SHIFT && apy->type==REDUCE ){ + spx = apx->sp; + spy = apy->x.rp->precsym; + if( spy==0 || spx->prec<0 || spy->prec<0 ){ + /* Not enough precedence information. */ + apy->type = SRCONFLICT; + errcnt++; + }else if( spx->prec>spy->prec ){ /* higher precedence wins */ + apy->type = RD_RESOLVED; + }else if( spx->prec<spy->prec ){ + apx->type = SH_RESOLVED; + }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */ + apy->type = RD_RESOLVED; /* associativity */ + }else if( spx->prec==spy->prec && spx->assoc==LEFT ){ /* to break tie */ + apx->type = SH_RESOLVED; + }else{ + assert( spx->prec==spy->prec && spx->assoc==NONE ); + apy->type = SRCONFLICT; + errcnt++; + } + }else if( apx->type==REDUCE && apy->type==REDUCE ){ + spx = apx->x.rp->precsym; + spy = apy->x.rp->precsym; + if( spx==0 || spy==0 || spx->prec<0 || + spy->prec<0 || spx->prec==spy->prec ){ + apy->type = RRCONFLICT; + errcnt++; + }else if( spx->prec>spy->prec ){ + apy->type = RD_RESOLVED; + }else if( spx->prec<spy->prec ){ + apx->type = RD_RESOLVED; + } + }else{ + assert( + apx->type==SH_RESOLVED || + apx->type==RD_RESOLVED || + apx->type==SSCONFLICT || + apx->type==SRCONFLICT || + apx->type==RRCONFLICT || + apy->type==SH_RESOLVED || + apy->type==RD_RESOLVED || + apy->type==SSCONFLICT || + apy->type==SRCONFLICT || + apy->type==RRCONFLICT + ); + /* The REDUCE/SHIFT case cannot happen because SHIFTs come before + ** REDUCEs on the list. If we reach this point it must be because + ** the parser conflict had already been resolved. */ + } + return errcnt; +} +/********************* From the file "configlist.c" *************************/ +/* +** Routines to processing a configuration list and building a state +** in the LEMON parser generator. +*/ + +static struct config *freelist = 0; /* List of free configurations */ +static struct config *current = 0; /* Top of list of configurations */ +static struct config **currentend = 0; /* Last on list of configs */ +static struct config *basis = 0; /* Top of list of basis configs */ +static struct config **basisend = 0; /* End of list of basis configs */ + +/* Return a pointer to a new configuration */ +PRIVATE struct config *newconfig(){ + struct config *newcfg; + if( freelist==0 ){ + int i; + int amt = 3; + freelist = (struct config *)calloc( amt, sizeof(struct config) ); + if( freelist==0 ){ + fprintf(stderr,"Unable to allocate memory for a new configuration."); + exit(1); + } + for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; + freelist[amt-1].next = 0; + } + newcfg = freelist; + freelist = freelist->next; + return newcfg; +} + +/* The configuration "old" is no longer used */ +PRIVATE void deleteconfig(struct config *old) +{ + old->next = freelist; + freelist = old; +} + +/* Initialized the configuration list builder */ +void Configlist_init(){ + current = 0; + currentend = ¤t; + basis = 0; + basisend = &basis; + Configtable_init(); + return; +} + +/* Initialized the configuration list builder */ +void Configlist_reset(){ + current = 0; + currentend = ¤t; + basis = 0; + basisend = &basis; + Configtable_clear(0); + return; +} + +/* Add another configuration to the configuration list */ +struct config *Configlist_add( + struct rule *rp, /* The rule */ + int dot /* Index into the RHS of the rule where the dot goes */ +){ + struct config *cfp, model; + + assert( currentend!=0 ); + model.rp = rp; + model.dot = dot; + cfp = Configtable_find(&model); + if( cfp==0 ){ + cfp = newconfig(); + cfp->rp = rp; + cfp->dot = dot; + cfp->fws = SetNew(); + cfp->stp = 0; + cfp->fplp = cfp->bplp = 0; + cfp->next = 0; + cfp->bp = 0; + *currentend = cfp; + currentend = &cfp->next; + Configtable_insert(cfp); + } + return cfp; +} + +/* Add a basis configuration to the configuration list */ +struct config *Configlist_addbasis(struct rule *rp, int dot) +{ + struct config *cfp, model; + + assert( basisend!=0 ); + assert( currentend!=0 ); + model.rp = rp; + model.dot = dot; + cfp = Configtable_find(&model); + if( cfp==0 ){ + cfp = newconfig(); + cfp->rp = rp; + cfp->dot = dot; + cfp->fws = SetNew(); + cfp->stp = 0; + cfp->fplp = cfp->bplp = 0; + cfp->next = 0; + cfp->bp = 0; + *currentend = cfp; + currentend = &cfp->next; + *basisend = cfp; + basisend = &cfp->bp; + Configtable_insert(cfp); + } + return cfp; +} + +/* Compute the closure of the configuration list */ +void Configlist_closure(struct lemon *lemp) +{ + struct config *cfp, *newcfp; + struct rule *rp, *newrp; + struct symbol *sp, *xsp; + int i, dot; + + assert( currentend!=0 ); + for(cfp=current; cfp; cfp=cfp->next){ + rp = cfp->rp; + dot = cfp->dot; + if( dot>=rp->nrhs ) continue; + sp = rp->rhs[dot]; + if( sp->type==NONTERMINAL ){ + if( sp->rule==0 && sp!=lemp->errsym ){ + ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.", + sp->name); + lemp->errorcnt++; + } + for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){ + newcfp = Configlist_add(newrp,0); + for(i=dot+1; i<rp->nrhs; i++){ + xsp = rp->rhs[i]; + if( xsp->type==TERMINAL ){ + SetAdd(newcfp->fws,xsp->index); + break; + }else if( xsp->type==MULTITERMINAL ){ + int k; + for(k=0; k<xsp->nsubsym; k++){ + SetAdd(newcfp->fws, xsp->subsym[k]->index); + } + break; + }else{ + SetUnion(newcfp->fws,xsp->firstset); + if( xsp->lambda==LEMON_FALSE ) break; + } + } + if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp); + } + } + } + return; +} + +/* Sort the configuration list */ +void Configlist_sort(){ + current = (struct config *)msort((char *)current,(char **)&(current->next),Configcmp); + currentend = 0; + return; +} + +/* Sort the basis configuration list */ +void Configlist_sortbasis(){ + basis = (struct config *)msort((char *)current,(char **)&(current->bp),Configcmp); + basisend = 0; + return; +} + +/* Return a pointer to the head of the configuration list and +** reset the list */ +struct config *Configlist_return(){ + struct config *old; + old = current; + current = 0; + currentend = 0; + return old; +} + +/* Return a pointer to the head of the configuration list and +** reset the list */ +struct config *Configlist_basis(){ + struct config *old; + old = basis; + basis = 0; + basisend = 0; + return old; +} + +/* Free all elements of the given configuration list */ +void Configlist_eat(struct config *cfp) +{ + struct config *nextcfp; + for(; cfp; cfp=nextcfp){ + nextcfp = cfp->next; + assert( cfp->fplp==0 ); + assert( cfp->bplp==0 ); + if( cfp->fws ) SetFree(cfp->fws); + deleteconfig(cfp); + } + return; +} +/***************** From the file "error.c" *********************************/ +/* +** Code for printing error message. +*/ + +void ErrorMsg(const char *filename, int lineno, const char *format, ...){ + va_list ap; + fprintf(stderr, "%s:%d: ", filename, lineno); + va_start(ap, format); + vfprintf(stderr,format,ap); + va_end(ap); + fprintf(stderr, "\n"); +} +/**************** From the file "main.c" ************************************/ +/* +** Main program file for the LEMON parser generator. +*/ + +/* Report an out-of-memory condition and abort. This function +** is used mostly by the "MemoryCheck" macro in struct.h +*/ +void memory_error(){ + fprintf(stderr,"Out of memory. Aborting...\n"); + exit(1); +} + +static int nDefine = 0; /* Number of -D options on the command line */ +static char **azDefine = 0; /* Name of the -D macros */ + +/* This routine is called with the argument to each -D command-line option. +** Add the macro defined to the azDefine array. +*/ +static void handle_D_option(char *z){ + char **paz; + nDefine++; + azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine); + if( azDefine==0 ){ + fprintf(stderr,"out of memory\n"); + exit(1); + } + paz = &azDefine[nDefine-1]; + *paz = (char *) malloc( lemonStrlen(z)+1 ); + if( *paz==0 ){ + fprintf(stderr,"out of memory\n"); + exit(1); + } + lemon_strcpy(*paz, z); + for(z=*paz; *z && *z!='='; z++){} + *z = 0; +} + +static char *user_templatename = NULL; +static void handle_T_option(char *z){ + user_templatename = (char *) malloc( lemonStrlen(z)+1 ); + if( user_templatename==0 ){ + memory_error(); + } + lemon_strcpy(user_templatename, z); +} + +/* The main program. Parse the command line and do it... */ +int main(int argc, char **argv) +{ + static int version = 0; + static int rpflag = 0; + static int basisflag = 0; + static int compress = 0; + static int quiet = 0; + static int statistics = 0; + static int mhflag = 0; + static int nolinenosflag = 0; + static int noResort = 0; + static struct s_options options[] = { + {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, + {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, + {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, + {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, + {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, + {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, + {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, + {OPT_FLAG, "p", (char*)&showPrecedenceConflict, + "Show conflicts resolved by precedence rules"}, + {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, + {OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"}, + {OPT_FLAG, "s", (char*)&statistics, + "Print parser stats to standard output."}, + {OPT_FLAG, "x", (char*)&version, "Print the version number."}, + {OPT_FLAG,0,0,0} + }; + int i; + int exitcode; + struct lemon lem; + + OptInit(argv,options,stderr); + if( version ){ + printf("Lemon version 1.0\n"); + exit(0); + } + if( OptNArgs()!=1 ){ + fprintf(stderr,"Exactly one filename argument is required.\n"); + exit(1); + } + memset(&lem, 0, sizeof(lem)); + lem.errorcnt = 0; + + /* Initialize the machine */ + Strsafe_init(); + Symbol_init(); + State_init(); + lem.argv0 = argv[0]; + lem.filename = OptArg(0); + lem.basisflag = basisflag; + lem.nolinenosflag = nolinenosflag; + Symbol_new("$"); + lem.errsym = Symbol_new("error"); + lem.errsym->useCnt = 0; + + /* Parse the input file */ + Parse(&lem); + if( lem.errorcnt ) exit(lem.errorcnt); + if( lem.nrule==0 ){ + fprintf(stderr,"Empty grammar.\n"); + exit(1); + } + + /* Count and index the symbols of the grammar */ + Symbol_new("{default}"); + lem.nsymbol = Symbol_count(); + lem.symbols = Symbol_arrayof(); + for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; + qsort(lem.symbols,lem.nsymbol,sizeof(struct symbol*), Symbolcmpp); + for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; + while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; } + assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 ); + lem.nsymbol = i - 1; + for(i=1; isupper(lem.symbols[i]->name[0]); i++); + lem.nterminal = i; + + /* Generate a reprint of the grammar, if requested on the command line */ + if( rpflag ){ + Reprint(&lem); + }else{ + /* Initialize the size for all follow and first sets */ + SetSize(lem.nterminal+1); + + /* Find the precedence for every production rule (that has one) */ + FindRulePrecedences(&lem); + + /* Compute the lambda-nonterminals and the first-sets for every + ** nonterminal */ + FindFirstSets(&lem); + + /* Compute all LR(0) states. Also record follow-set propagation + ** links so that the follow-set can be computed later */ + lem.nstate = 0; + FindStates(&lem); + lem.sorted = State_arrayof(); + + /* Tie up loose ends on the propagation links */ + FindLinks(&lem); + + /* Compute the follow set of every reducible configuration */ + FindFollowSets(&lem); + + /* Compute the action tables */ + FindActions(&lem); + + /* Compress the action tables */ + if( compress==0 ) CompressTables(&lem); + + /* Reorder and renumber the states so that states with fewer choices + ** occur at the end. This is an optimization that helps make the + ** generated parser tables smaller. */ + if( noResort==0 ) ResortStates(&lem); + + /* Generate a report of the parser generated. (the "y.output" file) */ + if( !quiet ) ReportOutput(&lem); + + /* Generate the source code for the parser */ + ReportTable(&lem, mhflag); + + /* Produce a header file for use by the scanner. (This step is + ** omitted if the "-m" option is used because makeheaders will + ** generate the file for us.) */ + if( !mhflag ) ReportHeader(&lem); + } + if( statistics ){ + printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", + lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); + printf(" %d states, %d parser table entries, %d conflicts\n", + lem.nstate, lem.tablesize, lem.nconflict); + } + if( lem.nconflict > 0 ){ + fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); + } + + /* return 0 on success, 1 on failure. */ + exitcode = ((lem.errorcnt > 0) || (lem.nconflict > 0)) ? 1 : 0; + exit(exitcode); + return (exitcode); +} +/******************** From the file "msort.c" *******************************/ +/* +** A generic merge-sort program. +** +** USAGE: +** Let "ptr" be a pointer to some structure which is at the head of +** a null-terminated list. Then to sort the list call: +** +** ptr = msort(ptr,&(ptr->next),cmpfnc); +** +** In the above, "cmpfnc" is a pointer to a function which compares +** two instances of the structure and returns an integer, as in +** strcmp. The second argument is a pointer to the pointer to the +** second element of the linked list. This address is used to compute +** the offset to the "next" field within the structure. The offset to +** the "next" field must be constant for all structures in the list. +** +** The function returns a new pointer which is the head of the list +** after sorting. +** +** ALGORITHM: +** Merge-sort. +*/ + +/* +** Return a pointer to the next structure in the linked list. +*/ +#define NEXT(A) (*(char**)(((char*)A)+offset)) + +/* +** Inputs: +** a: A sorted, null-terminated linked list. (May be null). +** b: A sorted, null-terminated linked list. (May be null). +** cmp: A pointer to the comparison function. +** offset: Offset in the structure to the "next" field. +** +** Return Value: +** A pointer to the head of a sorted list containing the elements +** of both a and b. +** +** Side effects: +** The "next" pointers for elements in the lists a and b are +** changed. +*/ +static char *merge( + char *a, + char *b, + int (*cmp)(const char*,const char*), + int offset +){ + char *ptr, *head; + + if( a==0 ){ + head = b; + }else if( b==0 ){ + head = a; + }else{ + if( (*cmp)(a,b)<=0 ){ + ptr = a; + a = NEXT(a); + }else{ + ptr = b; + b = NEXT(b); + } + head = ptr; + while( a && b ){ + if( (*cmp)(a,b)<=0 ){ + NEXT(ptr) = a; + ptr = a; + a = NEXT(a); + }else{ + NEXT(ptr) = b; + ptr = b; + b = NEXT(b); + } + } + if( a ) NEXT(ptr) = a; + else NEXT(ptr) = b; + } + return head; +} + +/* +** Inputs: +** list: Pointer to a singly-linked list of structures. +** next: Pointer to pointer to the second element of the list. +** cmp: A comparison function. +** +** Return Value: +** A pointer to the head of a sorted list containing the elements +** orginally in list. +** +** Side effects: +** The "next" pointers for elements in list are changed. +*/ +#define LISTSIZE 30 +static char *msort( + char *list, + char **next, + int (*cmp)(const char*,const char*) +){ + unsigned long offset; + char *ep; + char *set[LISTSIZE]; + int i; + offset = (unsigned long)next - (unsigned long)list; + for(i=0; i<LISTSIZE; i++) set[i] = 0; + while( list ){ + ep = list; + list = NEXT(list); + NEXT(ep) = 0; + for(i=0; i<LISTSIZE-1 && set[i]!=0; i++){ + ep = merge(ep,set[i],cmp,offset); + set[i] = 0; + } + set[i] = ep; + } + ep = 0; + for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(set[i],ep,cmp,offset); + return ep; +} +/************************ From the file "option.c" **************************/ +static char **argv; +static struct s_options *op; +static FILE *errstream; + +#define ISOPT(X) ((X)[0]=='-'||(X)[0]=='+'||strchr((X),'=')!=0) + +/* +** Print the command line with a carrot pointing to the k-th character +** of the n-th field. +*/ +static void errline(int n, int k, FILE *err) +{ + int spcnt, i; + if( argv[0] ) fprintf(err,"%s",argv[0]); + spcnt = lemonStrlen(argv[0]) + 1; + for(i=1; i<n && argv[i]; i++){ + fprintf(err," %s",argv[i]); + spcnt += lemonStrlen(argv[i])+1; + } + spcnt += k; + for(; argv[i]; i++) fprintf(err," %s",argv[i]); + if( spcnt<20 ){ + fprintf(err,"\n%*s^-- here\n",spcnt,""); + }else{ + fprintf(err,"\n%*shere --^\n",spcnt-7,""); + } +} + +/* +** Return the index of the N-th non-switch argument. Return -1 +** if N is out of range. +*/ +static int argindex(int n) +{ + int i; + int dashdash = 0; + if( argv!=0 && *argv!=0 ){ + for(i=1; argv[i]; i++){ + if( dashdash || !ISOPT(argv[i]) ){ + if( n==0 ) return i; + n--; + } + if( strcmp(argv[i],"--")==0 ) dashdash = 1; + } + } + return -1; +} + +static char emsg[] = "Command line syntax error: "; + +/* +** Process a flag command line argument. +*/ +static int handleflags(int i, FILE *err) +{ + int v; + int errcnt = 0; + int j; + for(j=0; op[j].label; j++){ + if( strncmp(&argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break; + } + v = argv[i][0]=='-' ? 1 : 0; + if( op[j].label==0 ){ + if( err ){ + fprintf(err,"%sundefined option.\n",emsg); + errline(i,1,err); + } + errcnt++; + }else if( op[j].type==OPT_FLAG ){ + *((int*)op[j].arg) = v; + }else if( op[j].type==OPT_FFLAG ){ + (*(void(*)(int))(op[j].arg))(v); + }else if( op[j].type==OPT_FSTR ){ + (*(void(*)(char *))(op[j].arg))(&argv[i][2]); + }else{ + if( err ){ + fprintf(err,"%smissing argument on switch.\n",emsg); + errline(i,1,err); + } + errcnt++; + } + return errcnt; +} + +/* +** Process a command line switch which has an argument. +*/ +static int handleswitch(int i, FILE *err) +{ + int lv = 0; + double dv = 0.0; + char *sv = 0, *end; + char *cp; + int j; + int errcnt = 0; + cp = strchr(argv[i],'='); + assert( cp!=0 ); + *cp = 0; + for(j=0; op[j].label; j++){ + if( strcmp(argv[i],op[j].label)==0 ) break; + } + *cp = '='; + if( op[j].label==0 ){ + if( err ){ + fprintf(err,"%sundefined option.\n",emsg); + errline(i,0,err); + } + errcnt++; + }else{ + cp++; + switch( op[j].type ){ + case OPT_FLAG: + case OPT_FFLAG: + if( err ){ + fprintf(err,"%soption requires an argument.\n",emsg); + errline(i,0,err); + } + errcnt++; + break; + case OPT_DBL: + case OPT_FDBL: + dv = strtod(cp,&end); + if( *end ){ + if( err ){ + fprintf(err,"%sillegal character in floating-point argument.\n",emsg); + errline(i,((unsigned long)end)-(unsigned long)argv[i],err); + } + errcnt++; + } + break; + case OPT_INT: + case OPT_FINT: + lv = strtol(cp,&end,0); + if( *end ){ + if( err ){ + fprintf(err,"%sillegal character in integer argument.\n",emsg); + errline(i,((unsigned long)end)-(unsigned long)argv[i],err); + } + errcnt++; + } + break; + case OPT_STR: + case OPT_FSTR: + sv = cp; + break; + } + switch( op[j].type ){ + case OPT_FLAG: + case OPT_FFLAG: + break; + case OPT_DBL: + *(double*)(op[j].arg) = dv; + break; + case OPT_FDBL: + (*(void(*)(double))(op[j].arg))(dv); + break; + case OPT_INT: + *(int*)(op[j].arg) = lv; + break; + case OPT_FINT: + (*(void(*)(int))(op[j].arg))((int)lv); + break; + case OPT_STR: + *(char**)(op[j].arg) = sv; + break; + case OPT_FSTR: + (*(void(*)(char *))(op[j].arg))(sv); + break; + } + } + return errcnt; +} + +int OptInit(char **a, struct s_options *o, FILE *err) +{ + int errcnt = 0; + argv = a; + op = o; + errstream = err; + if( argv && *argv && op ){ + int i; + for(i=1; argv[i]; i++){ + if( argv[i][0]=='+' || argv[i][0]=='-' ){ + errcnt += handleflags(i,err); + }else if( strchr(argv[i],'=') ){ + errcnt += handleswitch(i,err); + } + } + } + if( errcnt>0 ){ + fprintf(err,"Valid command line options for \"%s\" are:\n",*a); + OptPrint(); + exit(1); + } + return 0; +} + +int OptNArgs(){ + int cnt = 0; + int dashdash = 0; + int i; + if( argv!=0 && argv[0]!=0 ){ + for(i=1; argv[i]; i++){ + if( dashdash || !ISOPT(argv[i]) ) cnt++; + if( strcmp(argv[i],"--")==0 ) dashdash = 1; + } + } + return cnt; +} + +char *OptArg(int n) +{ + int i; + i = argindex(n); + return i>=0 ? argv[i] : 0; +} + +void OptErr(int n) +{ + int i; + i = argindex(n); + if( i>=0 ) errline(i,0,errstream); +} + +void OptPrint(){ + int i; + int max, len; + max = 0; + for(i=0; op[i].label; i++){ + len = lemonStrlen(op[i].label) + 1; + switch( op[i].type ){ + case OPT_FLAG: + case OPT_FFLAG: + break; + case OPT_INT: + case OPT_FINT: + len += 9; /* length of "<integer>" */ + break; + case OPT_DBL: + case OPT_FDBL: + len += 6; /* length of "<real>" */ + break; + case OPT_STR: + case OPT_FSTR: + len += 8; /* length of "<string>" */ + break; + } + if( len>max ) max = len; + } + for(i=0; op[i].label; i++){ + switch( op[i].type ){ + case OPT_FLAG: + case OPT_FFLAG: + fprintf(errstream," -%-*s %s\n",max,op[i].label,op[i].message); + break; + case OPT_INT: + case OPT_FINT: + fprintf(errstream," %s=<integer>%*s %s\n",op[i].label, + (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); + break; + case OPT_DBL: + case OPT_FDBL: + fprintf(errstream," %s=<real>%*s %s\n",op[i].label, + (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); + break; + case OPT_STR: + case OPT_FSTR: + fprintf(errstream," %s=<string>%*s %s\n",op[i].label, + (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); + break; + } + } +} +/*********************** From the file "parse.c" ****************************/ +/* +** Input file parser for the LEMON parser generator. +*/ + +/* The state of the parser */ +enum e_state { + INITIALIZE, + WAITING_FOR_DECL_OR_RULE, + WAITING_FOR_DECL_KEYWORD, + WAITING_FOR_DECL_ARG, + WAITING_FOR_PRECEDENCE_SYMBOL, + WAITING_FOR_ARROW, + IN_RHS, + LHS_ALIAS_1, + LHS_ALIAS_2, + LHS_ALIAS_3, + RHS_ALIAS_1, + RHS_ALIAS_2, + PRECEDENCE_MARK_1, + PRECEDENCE_MARK_2, + RESYNC_AFTER_RULE_ERROR, + RESYNC_AFTER_DECL_ERROR, + WAITING_FOR_DESTRUCTOR_SYMBOL, + WAITING_FOR_DATATYPE_SYMBOL, + WAITING_FOR_FALLBACK_ID, + WAITING_FOR_WILDCARD_ID, + WAITING_FOR_CLASS_ID, + WAITING_FOR_CLASS_TOKEN +}; +struct pstate { + char *filename; /* Name of the input file */ + int tokenlineno; /* Linenumber at which current token starts */ + int errorcnt; /* Number of errors so far */ + char *tokenstart; /* Text of current token */ + struct lemon *gp; /* Global state vector */ + enum e_state state; /* The state of the parser */ + struct symbol *fallback; /* The fallback token */ + struct symbol *tkclass; /* Token class symbol */ + struct symbol *lhs; /* Left-hand side of current rule */ + const char *lhsalias; /* Alias for the LHS */ + int nrhs; /* Number of right-hand side symbols seen */ + struct symbol *rhs[MAXRHS]; /* RHS symbols */ + const char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */ + struct rule *prevrule; /* Previous rule parsed */ + const char *declkeyword; /* Keyword of a declaration */ + char **declargslot; /* Where the declaration argument should be put */ + int insertLineMacro; /* Add #line before declaration insert */ + int *decllinenoslot; /* Where to write declaration line number */ + enum e_assoc declassoc; /* Assign this association to decl arguments */ + int preccounter; /* Assign this precedence to decl arguments */ + struct rule *firstrule; /* Pointer to first rule in the grammar */ + struct rule *lastrule; /* Pointer to the most recently parsed rule */ +}; + +/* Parse a single token */ +static void parseonetoken(struct pstate *psp) +{ + const char *x; + x = Strsafe(psp->tokenstart); /* Save the token permanently */ +#if 0 + printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno, + x,psp->state); +#endif + switch( psp->state ){ + case INITIALIZE: + psp->prevrule = 0; + psp->preccounter = 0; + psp->firstrule = psp->lastrule = 0; + psp->gp->nrule = 0; + /* Fall thru to next case */ + case WAITING_FOR_DECL_OR_RULE: + if( x[0]=='%' ){ + psp->state = WAITING_FOR_DECL_KEYWORD; + }else if( islower(x[0]) ){ + psp->lhs = Symbol_new(x); + psp->nrhs = 0; + psp->lhsalias = 0; + psp->state = WAITING_FOR_ARROW; + }else if( x[0]=='{' ){ + if( psp->prevrule==0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, +"There is no prior rule upon which to attach the code \ +fragment which begins on this line."); + psp->errorcnt++; + }else if( psp->prevrule->code!=0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, +"Code fragment beginning on this line is not the first \ +to follow the previous rule."); + psp->errorcnt++; + }else{ + psp->prevrule->line = psp->tokenlineno; + psp->prevrule->code = &x[1]; + } + }else if( x[0]=='[' ){ + psp->state = PRECEDENCE_MARK_1; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Token \"%s\" should be either \"%%\" or a nonterminal name.", + x); + psp->errorcnt++; + } + break; + case PRECEDENCE_MARK_1: + if( !isupper(x[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "The precedence symbol must be a terminal."); + psp->errorcnt++; + }else if( psp->prevrule==0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "There is no prior rule to assign precedence \"[%s]\".",x); + psp->errorcnt++; + }else if( psp->prevrule->precsym!=0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, +"Precedence mark on this line is not the first \ +to follow the previous rule."); + psp->errorcnt++; + }else{ + psp->prevrule->precsym = Symbol_new(x); + } + psp->state = PRECEDENCE_MARK_2; + break; + case PRECEDENCE_MARK_2: + if( x[0]!=']' ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \"]\" on precedence mark."); + psp->errorcnt++; + } + psp->state = WAITING_FOR_DECL_OR_RULE; + break; + case WAITING_FOR_ARROW: + if( x[0]==':' && x[1]==':' && x[2]=='=' ){ + psp->state = IN_RHS; + }else if( x[0]=='(' ){ + psp->state = LHS_ALIAS_1; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Expected to see a \":\" following the LHS symbol \"%s\".", + psp->lhs->name); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case LHS_ALIAS_1: + if( isalpha(x[0]) ){ + psp->lhsalias = x; + psp->state = LHS_ALIAS_2; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "\"%s\" is not a valid alias for the LHS \"%s\"\n", + x,psp->lhs->name); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case LHS_ALIAS_2: + if( x[0]==')' ){ + psp->state = LHS_ALIAS_3; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case LHS_ALIAS_3: + if( x[0]==':' && x[1]==':' && x[2]=='=' ){ + psp->state = IN_RHS; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \"->\" following: \"%s(%s)\".", + psp->lhs->name,psp->lhsalias); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case IN_RHS: + if( x[0]=='.' ){ + struct rule *rp; + rp = (struct rule *)calloc( sizeof(struct rule) + + sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1); + if( rp==0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Can't allocate enough memory for this rule."); + psp->errorcnt++; + psp->prevrule = 0; + }else{ + int i; + rp->ruleline = psp->tokenlineno; + rp->rhs = (struct symbol**)&rp[1]; + rp->rhsalias = (const char**)&(rp->rhs[psp->nrhs]); + for(i=0; i<psp->nrhs; i++){ + rp->rhs[i] = psp->rhs[i]; + rp->rhsalias[i] = psp->alias[i]; + } + rp->lhs = psp->lhs; + rp->lhsalias = psp->lhsalias; + rp->nrhs = psp->nrhs; + rp->code = 0; + rp->precsym = 0; + rp->index = psp->gp->nrule++; + rp->nextlhs = rp->lhs->rule; + rp->lhs->rule = rp; + rp->next = 0; + if( psp->firstrule==0 ){ + psp->firstrule = psp->lastrule = rp; + }else{ + psp->lastrule->next = rp; + psp->lastrule = rp; + } + psp->prevrule = rp; + } + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( isalpha(x[0]) ){ + if( psp->nrhs>=MAXRHS ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Too many symbols on RHS of rule beginning at \"%s\".", + x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + }else{ + psp->rhs[psp->nrhs] = Symbol_new(x); + psp->alias[psp->nrhs] = 0; + psp->nrhs++; + } + }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){ + struct symbol *msp = psp->rhs[psp->nrhs-1]; + if( msp->type!=MULTITERMINAL ){ + struct symbol *origsp = msp; + msp = (struct symbol *) calloc(1,sizeof(*msp)); + memset(msp, 0, sizeof(*msp)); + msp->type = MULTITERMINAL; + msp->nsubsym = 1; + msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*)); + msp->subsym[0] = origsp; + msp->name = origsp->name; + psp->rhs[psp->nrhs-1] = msp; + } + msp->nsubsym++; + msp->subsym = (struct symbol **) realloc(msp->subsym, + sizeof(struct symbol*)*msp->nsubsym); + msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]); + if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Cannot form a compound containing a non-terminal"); + psp->errorcnt++; + } + }else if( x[0]=='(' && psp->nrhs>0 ){ + psp->state = RHS_ALIAS_1; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Illegal character on RHS of rule: \"%s\".",x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case RHS_ALIAS_1: + if( isalpha(x[0]) ){ + psp->alias[psp->nrhs-1] = x; + psp->state = RHS_ALIAS_2; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n", + x,psp->rhs[psp->nrhs-1]->name); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case RHS_ALIAS_2: + if( x[0]==')' ){ + psp->state = IN_RHS; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case WAITING_FOR_DECL_KEYWORD: + if( isalpha(x[0]) ){ + psp->declkeyword = x; + psp->declargslot = 0; + psp->decllinenoslot = 0; + psp->insertLineMacro = 1; + psp->state = WAITING_FOR_DECL_ARG; + if( strcmp(x,"name")==0 ){ + psp->declargslot = &(psp->gp->name); + psp->insertLineMacro = 0; + }else if( strcmp(x,"include")==0 ){ + psp->declargslot = &(psp->gp->include); + }else if( strcmp(x,"code")==0 ){ + psp->declargslot = &(psp->gp->extracode); + }else if( strcmp(x,"token_destructor")==0 ){ + psp->declargslot = &psp->gp->tokendest; + }else if( strcmp(x,"default_destructor")==0 ){ + psp->declargslot = &psp->gp->vardest; + }else if( strcmp(x,"token_prefix")==0 ){ + psp->declargslot = &psp->gp->tokenprefix; + psp->insertLineMacro = 0; + }else if( strcmp(x,"syntax_error")==0 ){ + psp->declargslot = &(psp->gp->error); + }else if( strcmp(x,"parse_accept")==0 ){ + psp->declargslot = &(psp->gp->accept); + }else if( strcmp(x,"parse_failure")==0 ){ + psp->declargslot = &(psp->gp->failure); + }else if( strcmp(x,"stack_overflow")==0 ){ + psp->declargslot = &(psp->gp->overflow); + }else if( strcmp(x,"extra_argument")==0 ){ + psp->declargslot = &(psp->gp->arg); + psp->insertLineMacro = 0; + }else if( strcmp(x,"token_type")==0 ){ + psp->declargslot = &(psp->gp->tokentype); + psp->insertLineMacro = 0; + }else if( strcmp(x,"default_type")==0 ){ + psp->declargslot = &(psp->gp->vartype); + psp->insertLineMacro = 0; + }else if( strcmp(x,"stack_size")==0 ){ + psp->declargslot = &(psp->gp->stacksize); + psp->insertLineMacro = 0; + }else if( strcmp(x,"start_symbol")==0 ){ + psp->declargslot = &(psp->gp->start); + psp->insertLineMacro = 0; + }else if( strcmp(x,"left")==0 ){ + psp->preccounter++; + psp->declassoc = LEFT; + psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; + }else if( strcmp(x,"right")==0 ){ + psp->preccounter++; + psp->declassoc = RIGHT; + psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; + }else if( strcmp(x,"nonassoc")==0 ){ + psp->preccounter++; + psp->declassoc = NONE; + psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; + }else if( strcmp(x,"destructor")==0 ){ + psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL; + }else if( strcmp(x,"type")==0 ){ + psp->state = WAITING_FOR_DATATYPE_SYMBOL; + }else if( strcmp(x,"fallback")==0 ){ + psp->fallback = 0; + psp->state = WAITING_FOR_FALLBACK_ID; + }else if( strcmp(x,"wildcard")==0 ){ + psp->state = WAITING_FOR_WILDCARD_ID; + }else if( strcmp(x,"token_class")==0 ){ + psp->state = WAITING_FOR_CLASS_ID; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Unknown declaration keyword: \"%%%s\".",x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Illegal declaration keyword: \"%s\".",x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + break; + case WAITING_FOR_DESTRUCTOR_SYMBOL: + if( !isalpha(x[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol name missing after %%destructor keyword"); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + struct symbol *sp = Symbol_new(x); + psp->declargslot = &sp->destructor; + psp->decllinenoslot = &sp->destLineno; + psp->insertLineMacro = 1; + psp->state = WAITING_FOR_DECL_ARG; + } + break; + case WAITING_FOR_DATATYPE_SYMBOL: + if( !isalpha(x[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol name missing after %%type keyword"); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + struct symbol *sp = Symbol_find(x); + if((sp) && (sp->datatype)){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol %%type \"%s\" already defined", x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + if (!sp){ + sp = Symbol_new(x); + } + psp->declargslot = &sp->datatype; + psp->insertLineMacro = 0; + psp->state = WAITING_FOR_DECL_ARG; + } + } + break; + case WAITING_FOR_PRECEDENCE_SYMBOL: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( isupper(x[0]) ){ + struct symbol *sp; + sp = Symbol_new(x); + if( sp->prec>=0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol \"%s\" has already be given a precedence.",x); + psp->errorcnt++; + }else{ + sp->prec = psp->preccounter; + sp->assoc = psp->declassoc; + } + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Can't assign a precedence to \"%s\".",x); + psp->errorcnt++; + } + break; + case WAITING_FOR_DECL_ARG: + if( x[0]=='{' || x[0]=='\"' || isalnum(x[0]) ){ + const char *zOld, *zNew; + char *zBuf, *z; + int nOld, n, nLine, nNew, nBack; + int addLineMacro; + char zLine[50]; + zNew = x; + if( zNew[0]=='"' || zNew[0]=='{' ) zNew++; + nNew = lemonStrlen(zNew); + if( *psp->declargslot ){ + zOld = *psp->declargslot; + }else{ + zOld = ""; + } + nOld = lemonStrlen(zOld); + n = nOld + nNew + 20; + addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && + (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); + if( addLineMacro ){ + for(z=psp->filename, nBack=0; *z; z++){ + if( *z=='\\' ) nBack++; + } + lemon_sprintf(zLine, "#line %d ", psp->tokenlineno); + nLine = lemonStrlen(zLine); + n += nLine + lemonStrlen(psp->filename) + nBack; + } + *psp->declargslot = (char *) realloc(*psp->declargslot, n); + zBuf = *psp->declargslot + nOld; + if( addLineMacro ){ + if( nOld && zBuf[-1]!='\n' ){ + *(zBuf++) = '\n'; + } + memcpy(zBuf, zLine, nLine); + zBuf += nLine; + *(zBuf++) = '"'; + for(z=psp->filename; *z; z++){ + if( *z=='\\' ){ + *(zBuf++) = '\\'; + } + *(zBuf++) = *z; + } + *(zBuf++) = '"'; + *(zBuf++) = '\n'; + } + if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){ + psp->decllinenoslot[0] = psp->tokenlineno; + } + memcpy(zBuf, zNew, nNew); + zBuf += nNew; + *zBuf = 0; + psp->state = WAITING_FOR_DECL_OR_RULE; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Illegal argument to %%%s: %s",psp->declkeyword,x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + break; + case WAITING_FOR_FALLBACK_ID: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( !isupper(x[0]) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%fallback argument \"%s\" should be a token", x); + psp->errorcnt++; + }else{ + struct symbol *sp = Symbol_new(x); + if( psp->fallback==0 ){ + psp->fallback = sp; + }else if( sp->fallback ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "More than one fallback assigned to token %s", x); + psp->errorcnt++; + }else{ + sp->fallback = psp->fallback; + psp->gp->has_fallback = 1; + } + } + break; + case WAITING_FOR_WILDCARD_ID: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( !isupper(x[0]) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%wildcard argument \"%s\" should be a token", x); + psp->errorcnt++; + }else{ + struct symbol *sp = Symbol_new(x); + if( psp->gp->wildcard==0 ){ + psp->gp->wildcard = sp; + }else{ + ErrorMsg(psp->filename, psp->tokenlineno, + "Extra wildcard to token: %s", x); + psp->errorcnt++; + } + } + break; + case WAITING_FOR_CLASS_ID: + if( !islower(x[0]) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%token_class must be followed by an identifier: ", x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else if( Symbol_find(x) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "Symbol \"%s\" already used", x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + psp->tkclass = Symbol_new(x); + psp->tkclass->type = MULTITERMINAL; + psp->state = WAITING_FOR_CLASS_TOKEN; + } + break; + case WAITING_FOR_CLASS_TOKEN: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( isupper(x[0]) || ((x[0]=='|' || x[0]=='/') && isupper(x[1])) ){ + struct symbol *msp = psp->tkclass; + msp->nsubsym++; + msp->subsym = (struct symbol **) realloc(msp->subsym, + sizeof(struct symbol*)*msp->nsubsym); + if( !isupper(x[0]) ) x++; + msp->subsym[msp->nsubsym-1] = Symbol_new(x); + }else{ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%token_class argument \"%s\" should be a token", x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + break; + case RESYNC_AFTER_RULE_ERROR: +/* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; +** break; */ + case RESYNC_AFTER_DECL_ERROR: + if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; + if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD; + break; + } +} + +/* Run the preprocessor over the input file text. The global variables +** azDefine[0] through azDefine[nDefine-1] contains the names of all defined +** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and +** comments them out. Text in between is also commented out as appropriate. +*/ +static void preprocess_input(char *z){ + int i, j, k, n; + int exclude = 0; + int start = 0; + int lineno = 1; + int start_lineno = 1; + for(i=0; z[i]; i++){ + if( z[i]=='\n' ) lineno++; + if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue; + if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){ + if( exclude ){ + exclude--; + if( exclude==0 ){ + for(j=start; j<i; j++) if( z[j]!='\n' ) z[j] = ' '; + } + } + for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; + }else if( (strncmp(&z[i],"%ifdef",6)==0 && isspace(z[i+6])) + || (strncmp(&z[i],"%ifndef",7)==0 && isspace(z[i+7])) ){ + if( exclude ){ + exclude++; + }else{ + for(j=i+7; isspace(z[j]); j++){} + for(n=0; z[j+n] && !isspace(z[j+n]); n++){} + exclude = 1; + for(k=0; k<nDefine; k++){ + if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){ + exclude = 0; + break; + } + } + if( z[i+3]=='n' ) exclude = !exclude; + if( exclude ){ + start = i; + start_lineno = lineno; + } + } + for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; + } + } + if( exclude ){ + fprintf(stderr,"unterminated %%ifdef starting on line %d\n", start_lineno); + exit(1); + } +} + +/* In spite of its name, this function is really a scanner. It read +** in the entire input file (all at once) then tokenizes it. Each +** token is passed to the function "parseonetoken" which builds all +** the appropriate data structures in the global state vector "gp". +*/ +void Parse(struct lemon *gp) +{ + struct pstate ps; + FILE *fp; + char *filebuf; + int filesize; + int lineno; + int c; + char *cp, *nextcp; + int startline = 0; + + memset(&ps, '\0', sizeof(ps)); + ps.gp = gp; + ps.filename = gp->filename; + ps.errorcnt = 0; + ps.state = INITIALIZE; + + /* Begin by reading the input file */ + fp = fopen(ps.filename,"rb"); + if( fp==0 ){ + ErrorMsg(ps.filename,0,"Can't open this file for reading."); + gp->errorcnt++; + return; + } + fseek(fp,0,2); + filesize = ftell(fp); + rewind(fp); + filebuf = (char *)malloc( filesize+1 ); + if( filesize>100000000 || filebuf==0 ){ + ErrorMsg(ps.filename,0,"Input file too large."); + gp->errorcnt++; + fclose(fp); + return; + } + if( fread(filebuf,1,filesize,fp)!=filesize ){ + ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", + filesize); + free(filebuf); + gp->errorcnt++; + fclose(fp); + return; + } + fclose(fp); + filebuf[filesize] = 0; + + /* Make an initial pass through the file to handle %ifdef and %ifndef */ + preprocess_input(filebuf); + + /* Now scan the text of the input file */ + lineno = 1; + for(cp=filebuf; (c= *cp)!=0; ){ + if( c=='\n' ) lineno++; /* Keep track of the line number */ + if( isspace(c) ){ cp++; continue; } /* Skip all white space */ + if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */ + cp+=2; + while( (c= *cp)!=0 && c!='\n' ) cp++; + continue; + } + if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */ + cp+=2; + while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){ + if( c=='\n' ) lineno++; + cp++; + } + if( c ) cp++; + continue; + } + ps.tokenstart = cp; /* Mark the beginning of the token */ + ps.tokenlineno = lineno; /* Linenumber on which token begins */ + if( c=='\"' ){ /* String literals */ + cp++; + while( (c= *cp)!=0 && c!='\"' ){ + if( c=='\n' ) lineno++; + cp++; + } + if( c==0 ){ + ErrorMsg(ps.filename,startline, +"String starting on this line is not terminated before the end of the file."); + ps.errorcnt++; + nextcp = cp; + }else{ + nextcp = cp+1; + } + }else if( c=='{' ){ /* A block of C code */ + int level; + cp++; + for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){ + if( c=='\n' ) lineno++; + else if( c=='{' ) level++; + else if( c=='}' ) level--; + else if( c=='/' && cp[1]=='*' ){ /* Skip comments */ + int prevc; + cp = &cp[2]; + prevc = 0; + while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){ + if( c=='\n' ) lineno++; + prevc = c; + cp++; + } + }else if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments too */ + cp = &cp[2]; + while( (c= *cp)!=0 && c!='\n' ) cp++; + if( c ) lineno++; + }else if( c=='\'' || c=='\"' ){ /* String a character literals */ + int startchar, prevc; + startchar = c; + prevc = 0; + for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){ + if( c=='\n' ) lineno++; + if( prevc=='\\' ) prevc = 0; + else prevc = c; + } + } + } + if( c==0 ){ + ErrorMsg(ps.filename,ps.tokenlineno, +"C code starting on this line is not terminated before the end of the file."); + ps.errorcnt++; + nextcp = cp; + }else{ + nextcp = cp+1; + } + }else if( isalnum(c) ){ /* Identifiers */ + while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++; + nextcp = cp; + }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */ + cp += 3; + nextcp = cp; + }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){ + cp += 2; + while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++; + nextcp = cp; + }else{ /* All other (one character) operators */ + cp++; + nextcp = cp; + } + c = *cp; + *cp = 0; /* Null terminate the token */ + parseonetoken(&ps); /* Parse the token */ + *cp = c; /* Restore the buffer */ + cp = nextcp; + } + free(filebuf); /* Release the buffer after parsing */ + gp->rule = ps.firstrule; + gp->errorcnt = ps.errorcnt; +} +/*************************** From the file "plink.c" *********************/ +/* +** Routines processing configuration follow-set propagation links +** in the LEMON parser generator. +*/ +static struct plink *plink_freelist = 0; + +/* Allocate a new plink */ +struct plink *Plink_new(){ + struct plink *newlink; + + if( plink_freelist==0 ){ + int i; + int amt = 100; + plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) ); + if( plink_freelist==0 ){ + fprintf(stderr, + "Unable to allocate memory for a new follow-set propagation link.\n"); + exit(1); + } + for(i=0; i<amt-1; i++) plink_freelist[i].next = &plink_freelist[i+1]; + plink_freelist[amt-1].next = 0; + } + newlink = plink_freelist; + plink_freelist = plink_freelist->next; + return newlink; +} + +/* Add a plink to a plink list */ +void Plink_add(struct plink **plpp, struct config *cfp) +{ + struct plink *newlink; + newlink = Plink_new(); + newlink->next = *plpp; + *plpp = newlink; + newlink->cfp = cfp; +} + +/* Transfer every plink on the list "from" to the list "to" */ +void Plink_copy(struct plink **to, struct plink *from) +{ + struct plink *nextpl; + while( from ){ + nextpl = from->next; + from->next = *to; + *to = from; + from = nextpl; + } +} + +/* Delete every plink on the list */ +void Plink_delete(struct plink *plp) +{ + struct plink *nextpl; + + while( plp ){ + nextpl = plp->next; + plp->next = plink_freelist; + plink_freelist = plp; + plp = nextpl; + } +} +/*********************** From the file "report.c" **************************/ +/* +** Procedures for generating reports and tables in the LEMON parser generator. +*/ + +/* Generate a filename with the given suffix. Space to hold the +** name comes from malloc() and must be freed by the calling +** function. +*/ +PRIVATE char *file_makename(struct lemon *lemp, const char *suffix) +{ + char *name; + char *cp; + + name = (char*)malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 ); + if( name==0 ){ + fprintf(stderr,"Can't allocate space for a filename.\n"); + exit(1); + } + lemon_strcpy(name,lemp->filename); + cp = strrchr(name,'.'); + if( cp ) *cp = 0; + lemon_strcat(name,suffix); + return name; +} + +/* Open a file with a name based on the name of the input file, +** but with a different (specified) suffix, and return a pointer +** to the stream */ +PRIVATE FILE *file_open( + struct lemon *lemp, + const char *suffix, + const char *mode +){ + FILE *fp; + + if( lemp->outname ) free(lemp->outname); + lemp->outname = file_makename(lemp, suffix); + fp = fopen(lemp->outname,mode); + if( fp==0 && *mode=='w' ){ + fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname); + lemp->errorcnt++; + return 0; + } + return fp; +} + +/* Duplicate the input file without comments and without actions +** on rules */ +void Reprint(struct lemon *lemp) +{ + struct rule *rp; + struct symbol *sp; + int i, j, maxlen, len, ncolumns, skip; + printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename); + maxlen = 10; + for(i=0; i<lemp->nsymbol; i++){ + sp = lemp->symbols[i]; + len = lemonStrlen(sp->name); + if( len>maxlen ) maxlen = len; + } + ncolumns = 76/(maxlen+5); + if( ncolumns<1 ) ncolumns = 1; + skip = (lemp->nsymbol + ncolumns - 1)/ncolumns; + for(i=0; i<skip; i++){ + printf("//"); + for(j=i; j<lemp->nsymbol; j+=skip){ + sp = lemp->symbols[j]; + assert( sp->index==j ); + printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name); + } + printf("\n"); + } + for(rp=lemp->rule; rp; rp=rp->next){ + printf("%s",rp->lhs->name); + /* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */ + printf(" ::="); + for(i=0; i<rp->nrhs; i++){ + sp = rp->rhs[i]; + if( sp->type==MULTITERMINAL ){ + printf(" %s", sp->subsym[0]->name); + for(j=1; j<sp->nsubsym; j++){ + printf("|%s", sp->subsym[j]->name); + } + }else{ + printf(" %s", sp->name); + } + /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */ + } + printf("."); + if( rp->precsym ) printf(" [%s]",rp->precsym->name); + /* if( rp->code ) printf("\n %s",rp->code); */ + printf("\n"); + } +} + +void ConfigPrint(FILE *fp, struct config *cfp) +{ + struct rule *rp; + struct symbol *sp; + int i, j; + rp = cfp->rp; + fprintf(fp,"%s ::=",rp->lhs->name); + for(i=0; i<=rp->nrhs; i++){ + if( i==cfp->dot ) fprintf(fp," *"); + if( i==rp->nrhs ) break; + sp = rp->rhs[i]; + if( sp->type==MULTITERMINAL ){ + fprintf(fp," %s", sp->subsym[0]->name); + for(j=1; j<sp->nsubsym; j++){ + fprintf(fp,"|%s",sp->subsym[j]->name); + } + }else{ + fprintf(fp," %s", sp->name); + } + } +} + +/* #define TEST */ +#if 0 +/* Print a set */ +PRIVATE void SetPrint(out,set,lemp) +FILE *out; +char *set; +struct lemon *lemp; +{ + int i; + char *spacer; + spacer = ""; + fprintf(out,"%12s[",""); + for(i=0; i<lemp->nterminal; i++){ + if( SetFind(set,i) ){ + fprintf(out,"%s%s",spacer,lemp->symbols[i]->name); + spacer = " "; + } + } + fprintf(out,"]\n"); +} + +/* Print a plink chain */ +PRIVATE void PlinkPrint(out,plp,tag) +FILE *out; +struct plink *plp; +char *tag; +{ + while( plp ){ + fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum); + ConfigPrint(out,plp->cfp); + fprintf(out,"\n"); + plp = plp->next; + } +} +#endif + +/* Print an action to the given file descriptor. Return FALSE if +** nothing was actually printed. +*/ +int PrintAction(struct action *ap, FILE *fp, int indent){ + int result = 1; + switch( ap->type ){ + case SHIFT: + fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum); + break; + case REDUCE: + fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index); + break; + case ACCEPT: + fprintf(fp,"%*s accept",indent,ap->sp->name); + break; + case ERROR: + fprintf(fp,"%*s error",indent,ap->sp->name); + break; + case SRCONFLICT: + case RRCONFLICT: + fprintf(fp,"%*s reduce %-3d ** Parsing conflict **", + indent,ap->sp->name,ap->x.rp->index); + break; + case SSCONFLICT: + fprintf(fp,"%*s shift %-3d ** Parsing conflict **", + indent,ap->sp->name,ap->x.stp->statenum); + break; + case SH_RESOLVED: + if( showPrecedenceConflict ){ + fprintf(fp,"%*s shift %-3d -- dropped by precedence", + indent,ap->sp->name,ap->x.stp->statenum); + }else{ + result = 0; + } + break; + case RD_RESOLVED: + if( showPrecedenceConflict ){ + fprintf(fp,"%*s reduce %-3d -- dropped by precedence", + indent,ap->sp->name,ap->x.rp->index); + }else{ + result = 0; + } + break; + case NOT_USED: + result = 0; + break; + } + return result; +} + +/* Generate the "y.output" log file */ +void ReportOutput(struct lemon *lemp) +{ + int i; + struct state *stp; + struct config *cfp; + struct action *ap; + FILE *fp; + + fp = file_open(lemp,".out","wb"); + if( fp==0 ) return; + for(i=0; i<lemp->nstate; i++){ + stp = lemp->sorted[i]; + fprintf(fp,"State %d:\n",stp->statenum); + if( lemp->basisflag ) cfp=stp->bp; + else cfp=stp->cfp; + while( cfp ){ + char buf[20]; + if( cfp->dot==cfp->rp->nrhs ){ + lemon_sprintf(buf,"(%d)",cfp->rp->index); + fprintf(fp," %5s ",buf); + }else{ + fprintf(fp," "); + } + ConfigPrint(fp,cfp); + fprintf(fp,"\n"); +#if 0 + SetPrint(fp,cfp->fws,lemp); + PlinkPrint(fp,cfp->fplp,"To "); + PlinkPrint(fp,cfp->bplp,"From"); +#endif + if( lemp->basisflag ) cfp=cfp->bp; + else cfp=cfp->next; + } + fprintf(fp,"\n"); + for(ap=stp->ap; ap; ap=ap->next){ + if( PrintAction(ap,fp,30) ) fprintf(fp,"\n"); + } + fprintf(fp,"\n"); + } + fprintf(fp, "----------------------------------------------------\n"); + fprintf(fp, "Symbols:\n"); + for(i=0; i<lemp->nsymbol; i++){ + int j; + struct symbol *sp; + + sp = lemp->symbols[i]; + fprintf(fp, " %3d: %s", i, sp->name); + if( sp->type==NONTERMINAL ){ + fprintf(fp, ":"); + if( sp->lambda ){ + fprintf(fp, " <lambda>"); + } + for(j=0; j<lemp->nterminal; j++){ + if( sp->firstset && SetFind(sp->firstset, j) ){ + fprintf(fp, " %s", lemp->symbols[j]->name); + } + } + } + fprintf(fp, "\n"); + } + fclose(fp); + return; +} + +/* Search for the file "name" which is in the same directory as +** the exacutable */ +PRIVATE char *pathsearch(char *argv0, char *name, int modemask) +{ + const char *pathlist; + char *pathbufptr; + char *pathbuf; + char *path,*cp; + char c; + +#ifdef __WIN32__ + cp = strrchr(argv0,'\\'); +#else + cp = strrchr(argv0,'/'); +#endif + if( cp ){ + c = *cp; + *cp = 0; + path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 ); + if( path ) lemon_sprintf(path,"%s/%s",argv0,name); + *cp = c; + }else{ + pathlist = getenv("PATH"); + if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; + pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 ); + path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 ); + if( (pathbuf != 0) && (path!=0) ){ + pathbufptr = pathbuf; + lemon_strcpy(pathbuf, pathlist); + while( *pathbuf ){ + cp = strchr(pathbuf,':'); + if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)]; + c = *cp; + *cp = 0; + lemon_sprintf(path,"%s/%s",pathbuf,name); + *cp = c; + if( c==0 ) pathbuf[0] = 0; + else pathbuf = &cp[1]; + if( access(path,modemask)==0 ) break; + } + free(pathbufptr); + } + } + return path; +} + +/* Given an action, compute the integer value for that action +** which is to be put in the action table of the generated machine. +** Return negative if no action should be generated. +*/ +PRIVATE int compute_action(struct lemon *lemp, struct action *ap) +{ + int act; + switch( ap->type ){ + case SHIFT: act = ap->x.stp->statenum; break; + case REDUCE: act = ap->x.rp->index + lemp->nstate; break; + case ERROR: act = lemp->nstate + lemp->nrule; break; + case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break; + default: act = -1; break; + } + return act; +} + +#define LINESIZE 1000 +/* The next cluster of routines are for reading the template file +** and writing the results to the generated parser */ +/* The first function transfers data from "in" to "out" until +** a line is seen which begins with "%%". The line number is +** tracked. +** +** if name!=0, then any word that begin with "Parse" is changed to +** begin with *name instead. +*/ +PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno) +{ + int i, iStart; + char line[LINESIZE]; + while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){ + (*lineno)++; + iStart = 0; + if( name ){ + for(i=0; line[i]; i++){ + if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0 + && (i==0 || !isalpha(line[i-1])) + ){ + if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]); + fprintf(out,"%s",name); + i += 4; + iStart = i+1; + } + } + } + fprintf(out,"%s",&line[iStart]); + } +} + +/* The next function finds the template file and opens it, returning +** a pointer to the opened file. */ +PRIVATE FILE *tplt_open(struct lemon *lemp) +{ + static char templatename[] = "lempar.c"; + char buf[1000]; + FILE *in; + char *tpltname; + char *cp; + + /* first, see if user specified a template filename on the command line. */ + if (user_templatename != 0) { + if( access(user_templatename,004)==-1 ){ + fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", + user_templatename); + lemp->errorcnt++; + return 0; + } + in = fopen(user_templatename,"rb"); + if( in==0 ){ + fprintf(stderr,"Can't open the template file \"%s\".\n",user_templatename); + lemp->errorcnt++; + return 0; + } + return in; + } + + cp = strrchr(lemp->filename,'.'); + if( cp ){ + lemon_sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename); + }else{ + lemon_sprintf(buf,"%s.lt",lemp->filename); + } + if( access(buf,004)==0 ){ + tpltname = buf; + }else if( access(templatename,004)==0 ){ + tpltname = templatename; + }else{ + tpltname = pathsearch(lemp->argv0,templatename,0); + } + if( tpltname==0 ){ + fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", + templatename); + lemp->errorcnt++; + return 0; + } + in = fopen(tpltname,"rb"); + if( in==0 ){ + fprintf(stderr,"Can't open the template file \"%s\".\n",templatename); + lemp->errorcnt++; + return 0; + } + return in; +} + +/* Print a #line directive line to the output file. */ +PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename) +{ + fprintf(out,"#line %d \"",lineno); + while( *filename ){ + if( *filename == '\\' ) putc('\\',out); + putc(*filename,out); + filename++; + } + fprintf(out,"\"\n"); +} + +/* Print a string to the file and keep the linenumber up to date */ +PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno) +{ + if( str==0 ) return; + while( *str ){ + putc(*str,out); + if( *str=='\n' ) (*lineno)++; + str++; + } + if( str[-1]!='\n' ){ + putc('\n',out); + (*lineno)++; + } + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + return; +} + +/* +** The following routine emits code for the destructor for the +** symbol sp +*/ +void emit_destructor_code( + FILE *out, + struct symbol *sp, + struct lemon *lemp, + int *lineno +){ + char *cp = 0; + + if( sp->type==TERMINAL ){ + cp = lemp->tokendest; + if( cp==0 ) return; + fprintf(out,"{\n"); (*lineno)++; + }else if( sp->destructor ){ + cp = sp->destructor; + fprintf(out,"{\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,sp->destLineno,lemp->filename); } + }else if( lemp->vardest ){ + cp = lemp->vardest; + if( cp==0 ) return; + fprintf(out,"{\n"); (*lineno)++; + }else{ + assert( 0 ); /* Cannot happen */ + } + for(; *cp; cp++){ + if( *cp=='$' && cp[1]=='$' ){ + fprintf(out,"(yypminor->yy%d)",sp->dtnum); + cp++; + continue; + } + if( *cp=='\n' ) (*lineno)++; + fputc(*cp,out); + } + fprintf(out,"\n"); (*lineno)++; + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + fprintf(out,"}\n"); (*lineno)++; + return; +} + +/* +** Return TRUE (non-zero) if the given symbol has a destructor. +*/ +int has_destructor(struct symbol *sp, struct lemon *lemp) +{ + int ret; + if( sp->type==TERMINAL ){ + ret = lemp->tokendest!=0; + }else{ + ret = lemp->vardest!=0 || sp->destructor!=0; + } + return ret; +} + +/* +** Append text to a dynamically allocated string. If zText is 0 then +** reset the string to be empty again. Always return the complete text +** of the string (which is overwritten with each call). +** +** n bytes of zText are stored. If n==0 then all of zText up to the first +** \000 terminator is stored. zText can contain up to two instances of +** %d. The values of p1 and p2 are written into the first and second +** %d. +** +** If n==-1, then the previous character is overwritten. +*/ +PRIVATE char *append_str(const char *zText, int n, int p1, int p2){ + static char empty[1] = { 0 }; + static char *z = 0; + static int alloced = 0; + static int used = 0; + int c; + char zInt[40]; + if( zText==0 ){ + used = 0; + return z; + } + if( n<=0 ){ + if( n<0 ){ + used += n; + assert( used>=0 ); + } + n = lemonStrlen(zText); + } + if( (int) (n+sizeof(zInt)*2+used) >= alloced ){ + alloced = n + sizeof(zInt)*2 + used + 200; + z = (char *) realloc(z, alloced); + } + if( z==0 ) return empty; + while( n-- > 0 ){ + c = *(zText++); + if( c=='%' && n>0 && zText[0]=='d' ){ + lemon_sprintf(zInt, "%d", p1); + p1 = p2; + lemon_strcpy(&z[used], zInt); + used += lemonStrlen(&z[used]); + zText++; + n--; + }else{ + z[used++] = c; + } + } + z[used] = 0; + return z; +} + +/* +** zCode is a string that is the action associated with a rule. Expand +** the symbols in this string so that the refer to elements of the parser +** stack. +*/ +PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ + char *cp, *xp; + int i; + char lhsused = 0; /* True if the LHS element has been used */ + char used[MAXRHS]; /* True for each RHS element which is used */ + + for(i=0; i<rp->nrhs; i++) used[i] = 0; + lhsused = 0; + + if( rp->code==0 ){ + static char newlinestr[2] = { '\n', '\0' }; + rp->code = newlinestr; + rp->line = rp->ruleline; + } + + append_str(0,0,0,0); + + /* This const cast is wrong but harmless, if we're careful. */ + for(cp=(char *)rp->code; *cp; cp++){ + if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){ + char saved; + for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++); + saved = *xp; + *xp = 0; + if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){ + append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0); + cp = xp; + lhsused = 1; + }else{ + for(i=0; i<rp->nrhs; i++){ + if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){ + if( cp!=rp->code && cp[-1]=='@' ){ + /* If the argument is of the form @X then substituted + ** the token number of X, not the value of X */ + append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0); + }else{ + struct symbol *sp = rp->rhs[i]; + int dtnum; + if( sp->type==MULTITERMINAL ){ + dtnum = sp->subsym[0]->dtnum; + }else{ + dtnum = sp->dtnum; + } + append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum); + } + cp = xp; + used[i] = 1; + break; + } + } + } + *xp = saved; + } + append_str(cp, 1, 0, 0); + } /* End loop */ + + /* Check to make sure the LHS has been used */ + if( rp->lhsalias && !lhsused ){ + ErrorMsg(lemp->filename,rp->ruleline, + "Label \"%s\" for \"%s(%s)\" is never used.", + rp->lhsalias,rp->lhs->name,rp->lhsalias); + lemp->errorcnt++; + } + + /* Generate destructor code for RHS symbols which are not used in the + ** reduce code */ + for(i=0; i<rp->nrhs; i++){ + if( rp->rhsalias[i] && !used[i] ){ + ErrorMsg(lemp->filename,rp->ruleline, + "Label %s for \"%s(%s)\" is never used.", + rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); + lemp->errorcnt++; + }else if( rp->rhsalias[i]==0 ){ + if( has_destructor(rp->rhs[i],lemp) ){ + append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, + rp->rhs[i]->index,i-rp->nrhs+1); + }else{ + /* No destructor defined for this term */ + } + } + } + if( rp->code ){ + cp = append_str(0,0,0,0); + rp->code = Strsafe(cp?cp:""); + } +} + +/* +** Generate code which executes when the rule "rp" is reduced. Write +** the code to "out". Make sure lineno stays up-to-date. +*/ +PRIVATE void emit_code( + FILE *out, + struct rule *rp, + struct lemon *lemp, + int *lineno +){ + const char *cp; + + /* Generate code to do the reduce action */ + if( rp->code ){ + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,rp->line,lemp->filename); } + fprintf(out,"{%s",rp->code); + for(cp=rp->code; *cp; cp++){ + if( *cp=='\n' ) (*lineno)++; + } /* End loop */ + fprintf(out,"}\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); } + } /* End if( rp->code ) */ + + return; +} + +/* +** Print the definition of the union used for the parser's data stack. +** This union contains fields for every possible data type for tokens +** and nonterminals. In the process of computing and printing this +** union, also set the ".dtnum" field of every terminal and nonterminal +** symbol. +*/ +void print_stack_union( + FILE *out, /* The output stream */ + struct lemon *lemp, /* The main info structure for this parser */ + int *plineno, /* Pointer to the line number */ + int mhflag /* True if generating makeheaders output */ +){ + int lineno = *plineno; /* The line number of the output */ + char **types; /* A hash table of datatypes */ + int arraysize; /* Size of the "types" array */ + int maxdtlength; /* Maximum length of any ".datatype" field. */ + char *stddt; /* Standardized name for a datatype */ + int i,j; /* Loop counters */ + unsigned hash; /* For hashing the name of a type */ + const char *name; /* Name of the parser */ + + /* Allocate and initialize types[] and allocate stddt[] */ + arraysize = lemp->nsymbol * 2; + types = (char**)calloc( arraysize, sizeof(char*) ); + if( types==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } + for(i=0; i<arraysize; i++) types[i] = 0; + maxdtlength = 0; + if( lemp->vartype ){ + maxdtlength = lemonStrlen(lemp->vartype); + } + for(i=0; i<lemp->nsymbol; i++){ + int len; + struct symbol *sp = lemp->symbols[i]; + if( sp->datatype==0 ) continue; + len = lemonStrlen(sp->datatype); + if( len>maxdtlength ) maxdtlength = len; + } + stddt = (char*)malloc( maxdtlength*2 + 1 ); + if( stddt==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } + + /* Build a hash table of datatypes. The ".dtnum" field of each symbol + ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is + ** used for terminal symbols. If there is no %default_type defined then + ** 0 is also used as the .dtnum value for nonterminals which do not specify + ** a datatype using the %type directive. + */ + for(i=0; i<lemp->nsymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + char *cp; + if( sp==lemp->errsym ){ + sp->dtnum = arraysize+1; + continue; + } + if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){ + sp->dtnum = 0; + continue; + } + cp = sp->datatype; + if( cp==0 ) cp = lemp->vartype; + j = 0; + while( isspace(*cp) ) cp++; + while( *cp ) stddt[j++] = *cp++; + while( j>0 && isspace(stddt[j-1]) ) j--; + stddt[j] = 0; + if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){ + sp->dtnum = 0; + continue; + } + hash = 0; + for(j=0; stddt[j]; j++){ + hash = hash*53 + stddt[j]; + } + hash = (hash & 0x7fffffff)%arraysize; + while( types[hash] ){ + if( strcmp(types[hash],stddt)==0 ){ + sp->dtnum = hash + 1; + break; + } + hash++; + if( hash>=(unsigned)arraysize ) hash = 0; + } + if( types[hash]==0 ){ + sp->dtnum = hash + 1; + types[hash] = (char*)malloc( lemonStrlen(stddt)+1 ); + if( types[hash]==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } + lemon_strcpy(types[hash],stddt); + } + } + + /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */ + name = lemp->name ? lemp->name : "Parse"; + lineno = *plineno; + if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; } + fprintf(out,"#define %sTOKENTYPE %s\n",name, + lemp->tokentype?lemp->tokentype:"void*"); lineno++; + if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } + fprintf(out,"typedef union {\n"); lineno++; + fprintf(out," int yyinit;\n"); lineno++; + fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++; + for(i=0; i<arraysize; i++){ + if( types[i]==0 ) continue; + fprintf(out," %s yy%d;\n",types[i],i+1); lineno++; + free(types[i]); + } + if( lemp->errsym->useCnt ){ + fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++; + } + free(stddt); + free(types); + fprintf(out,"} YYMINORTYPE;\n"); lineno++; + *plineno = lineno; +} + +/* +** Return the name of a C datatype able to represent values between +** lwr and upr, inclusive. +*/ +static const char *minimum_size_type(int lwr, int upr){ + if( lwr>=0 ){ + if( upr<=255 ){ + return "unsigned char"; + }else if( upr<65535 ){ + return "unsigned short int"; + }else{ + return "unsigned int"; + } + }else if( lwr>=-127 && upr<=127 ){ + return "signed char"; + }else if( lwr>=-32767 && upr<32767 ){ + return "short"; + }else{ + return "int"; + } +} + +/* +** Each state contains a set of token transaction and a set of +** nonterminal transactions. Each of these sets makes an instance +** of the following structure. An array of these structures is used +** to order the creation of entries in the yy_action[] table. +*/ +struct axset { + struct state *stp; /* A pointer to a state */ + int isTkn; /* True to use tokens. False for non-terminals */ + int nAction; /* Number of actions */ + int iOrder; /* Original order of action sets */ +}; + +/* +** Compare to axset structures for sorting purposes +*/ +static int axset_compare(const void *a, const void *b){ + struct axset *p1 = (struct axset*)a; + struct axset *p2 = (struct axset*)b; + int c; + c = p2->nAction - p1->nAction; + if( c==0 ){ + c = p2->iOrder - p1->iOrder; + } + assert( c!=0 || p1==p2 ); + return c; +} + +/* +** Write text on "out" that describes the rule "rp". +*/ +static void writeRuleText(FILE *out, struct rule *rp){ + int j; + fprintf(out,"%s ::=", rp->lhs->name); + for(j=0; j<rp->nrhs; j++){ + struct symbol *sp = rp->rhs[j]; + if( sp->type!=MULTITERMINAL ){ + fprintf(out," %s", sp->name); + }else{ + int k; + fprintf(out," %s", sp->subsym[0]->name); + for(k=1; k<sp->nsubsym; k++){ + fprintf(out,"|%s",sp->subsym[k]->name); + } + } + } +} + + +/* Generate C source code for the parser */ +void ReportTable( + struct lemon *lemp, + int mhflag /* Output in makeheaders format if true */ +){ + FILE *out, *in; + char line[LINESIZE]; + int lineno; + struct state *stp; + struct action *ap; + struct rule *rp; + struct acttab *pActtab; + int i, j, n; + const char *name; + int mnTknOfst, mxTknOfst; + int mnNtOfst, mxNtOfst; + struct axset *ax; + + in = tplt_open(lemp); + if( in==0 ) return; + out = file_open(lemp,".c","wb"); + if( out==0 ){ + fclose(in); + return; + } + lineno = 1; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the include code, if any */ + tplt_print(out,lemp,lemp->include,&lineno); + if( mhflag ){ + char *name = file_makename(lemp, ".h"); + fprintf(out,"#include \"%s\"\n", name); lineno++; + free(name); + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate #defines for all tokens */ + if( mhflag ){ + const char *prefix; + fprintf(out,"#if INTERFACE\n"); lineno++; + if( lemp->tokenprefix ) prefix = lemp->tokenprefix; + else prefix = ""; + for(i=1; i<lemp->nterminal; i++){ + fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); + lineno++; + } + fprintf(out,"#endif\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the defines */ + fprintf(out,"#define YYCODETYPE %s\n", + minimum_size_type(0, lemp->nsymbol+1)); lineno++; + fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; + fprintf(out,"#define YYACTIONTYPE %s\n", + minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++; + if( lemp->wildcard ){ + fprintf(out,"#define YYWILDCARD %d\n", + lemp->wildcard->index); lineno++; + } + print_stack_union(out,lemp,&lineno,mhflag); + fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++; + if( lemp->stacksize ){ + fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++; + }else{ + fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++; + } + fprintf(out, "#endif\n"); lineno++; + if( mhflag ){ + fprintf(out,"#if INTERFACE\n"); lineno++; + } + name = lemp->name ? lemp->name : "Parse"; + if( lemp->arg && lemp->arg[0] ){ + int i; + i = lemonStrlen(lemp->arg); + while( i>=1 && isspace(lemp->arg[i-1]) ) i--; + while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; + fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++; + fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg); lineno++; + fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n", + name,lemp->arg,&lemp->arg[i]); lineno++; + fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n", + name,&lemp->arg[i],&lemp->arg[i]); lineno++; + }else{ + fprintf(out,"#define %sARG_SDECL\n",name); lineno++; + fprintf(out,"#define %sARG_PDECL\n",name); lineno++; + fprintf(out,"#define %sARG_FETCH\n",name); lineno++; + fprintf(out,"#define %sARG_STORE\n",name); lineno++; + } + if( mhflag ){ + fprintf(out,"#endif\n"); lineno++; + } + fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++; + fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; + if( lemp->errsym->useCnt ){ + fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; + fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; + } + if( lemp->has_fallback ){ + fprintf(out,"#define YYFALLBACK 1\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the action table and its associates: + ** + ** yy_action[] A single table containing all actions. + ** yy_lookahead[] A table containing the lookahead for each entry in + ** yy_action. Used to detect hash collisions. + ** yy_shift_ofst[] For each state, the offset into yy_action for + ** shifting terminals. + ** yy_reduce_ofst[] For each state, the offset into yy_action for + ** shifting non-terminals after a reduce. + ** yy_default[] Default action for each state. + */ + + /* Compute the actions on all states and count them up */ + ax = (struct axset *) calloc(lemp->nstate*2, sizeof(ax[0])); + if( ax==0 ){ + fprintf(stderr,"malloc failed\n"); + exit(1); + } + for(i=0; i<lemp->nstate; i++){ + stp = lemp->sorted[i]; + ax[i*2].stp = stp; + ax[i*2].isTkn = 1; + ax[i*2].nAction = stp->nTknAct; + ax[i*2+1].stp = stp; + ax[i*2+1].isTkn = 0; + ax[i*2+1].nAction = stp->nNtAct; + } + mxTknOfst = mnTknOfst = 0; + mxNtOfst = mnNtOfst = 0; + + /* Compute the action table. In order to try to keep the size of the + ** action table to a minimum, the heuristic of placing the largest action + ** sets first is used. + */ + for(i=0; i<lemp->nstate*2; i++) ax[i].iOrder = i; + qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare); + pActtab = acttab_alloc(); + for(i=0; i<lemp->nstate*2 && ax[i].nAction>0; i++){ + stp = ax[i].stp; + if( ax[i].isTkn ){ + for(ap=stp->ap; ap; ap=ap->next){ + int action; + if( ap->sp->index>=lemp->nterminal ) continue; + action = compute_action(lemp, ap); + if( action<0 ) continue; + acttab_action(pActtab, ap->sp->index, action); + } + stp->iTknOfst = acttab_insert(pActtab); + if( stp->iTknOfst<mnTknOfst ) mnTknOfst = stp->iTknOfst; + if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst; + }else{ + for(ap=stp->ap; ap; ap=ap->next){ + int action; + if( ap->sp->index<lemp->nterminal ) continue; + if( ap->sp->index==lemp->nsymbol ) continue; + action = compute_action(lemp, ap); + if( action<0 ) continue; + acttab_action(pActtab, ap->sp->index, action); + } + stp->iNtOfst = acttab_insert(pActtab); + if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst; + if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst; + } + } + free(ax); + + /* Output the yy_action table */ + n = acttab_size(pActtab); + fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++; + fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; + for(i=j=0; i<n; i++){ + int action = acttab_yyaction(pActtab, i); + if( action<0 ) action = lemp->nstate + lemp->nrule + 2; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", action); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the yy_lookahead table */ + fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; + for(i=j=0; i<n; i++){ + int la = acttab_yylookahead(pActtab, i); + if( la<0 ) la = lemp->nsymbol; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", la); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the yy_shift_ofst[] table */ + fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; + n = lemp->nstate; + while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; + fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; + fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; + fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; + fprintf(out, "static const %s yy_shift_ofst[] = {\n", + minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++; + for(i=j=0; i<n; i++){ + int ofst; + stp = lemp->sorted[i]; + ofst = stp->iTknOfst; + if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", ofst); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the yy_reduce_ofst[] table */ + fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; + n = lemp->nstate; + while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; + fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++; + fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++; + fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++; + fprintf(out, "static const %s yy_reduce_ofst[] = {\n", + minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; + for(i=j=0; i<n; i++){ + int ofst; + stp = lemp->sorted[i]; + ofst = stp->iNtOfst; + if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", ofst); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the default action table */ + fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; + n = lemp->nstate; + for(i=j=0; i<n; i++){ + stp = lemp->sorted[i]; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", stp->iDflt); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the table of fallback tokens. + */ + if( lemp->has_fallback ){ + int mx = lemp->nterminal - 1; + while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } + for(i=0; i<=mx; i++){ + struct symbol *p = lemp->symbols[i]; + if( p->fallback==0 ){ + fprintf(out, " 0, /* %10s => nothing */\n", p->name); + }else{ + fprintf(out, " %3d, /* %10s => %s */\n", p->fallback->index, + p->name, p->fallback->name); + } + lineno++; + } + } + tplt_xfer(lemp->name, in, out, &lineno); + + /* Generate a table containing the symbolic name of every symbol + */ + for(i=0; i<lemp->nsymbol; i++){ + lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name); + fprintf(out," %-15s",line); + if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; } + } + if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate a table containing a text string that describes every + ** rule in the rule set of the grammar. This information is used + ** when tracing REDUCE actions. + */ + for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ + assert( rp->index==i ); + fprintf(out," /* %3d */ \"", i); + writeRuleText(out, rp); + fprintf(out,"\",\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes every time a symbol is popped from + ** the stack while processing errors or while destroying the parser. + ** (In other words, generate the %destructor actions) + */ + if( lemp->tokendest ){ + int once = 1; + for(i=0; i<lemp->nsymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type!=TERMINAL ) continue; + if( once ){ + fprintf(out, " /* TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; + } + for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++); + if( i<lemp->nsymbol ){ + emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); + fprintf(out," break;\n"); lineno++; + } + } + if( lemp->vardest ){ + struct symbol *dflt_sp = 0; + int once = 1; + for(i=0; i<lemp->nsymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type==TERMINAL || + sp->index<=0 || sp->destructor!=0 ) continue; + if( once ){ + fprintf(out, " /* Default NON-TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; + dflt_sp = sp; + } + if( dflt_sp!=0 ){ + emit_destructor_code(out,dflt_sp,lemp,&lineno); + } + fprintf(out," break;\n"); lineno++; + } + for(i=0; i<lemp->nsymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; + + /* Combine duplicate destructors into a single case */ + for(j=i+1; j<lemp->nsymbol; j++){ + struct symbol *sp2 = lemp->symbols[j]; + if( sp2 && sp2->type!=TERMINAL && sp2->destructor + && sp2->dtnum==sp->dtnum + && strcmp(sp->destructor,sp2->destructor)==0 ){ + fprintf(out," case %d: /* %s */\n", + sp2->index, sp2->name); lineno++; + sp2->destructor = 0; + } + } + + emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); + fprintf(out," break;\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes whenever the parser stack overflows */ + tplt_print(out,lemp,lemp->overflow,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the table of rule information + ** + ** Note: This code depends on the fact that rules are number + ** sequentually beginning with 0. + */ + for(rp=lemp->rule; rp; rp=rp->next){ + fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which execution during each REDUCE action */ + for(rp=lemp->rule; rp; rp=rp->next){ + translate_code(lemp, rp); + } + /* First output rules other than the default: rule */ + for(rp=lemp->rule; rp; rp=rp->next){ + struct rule *rp2; /* Other rules with the same action */ + if( rp->code==0 ) continue; + if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ + fprintf(out," case %d: /* ", rp->index); + writeRuleText(out, rp); + fprintf(out, " */\n"); lineno++; + for(rp2=rp->next; rp2; rp2=rp2->next){ + if( rp2->code==rp->code ){ + fprintf(out," case %d: /* ", rp2->index); + writeRuleText(out, rp2); + fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->index); lineno++; + rp2->code = 0; + } + } + emit_code(out,rp,lemp,&lineno); + fprintf(out," break;\n"); lineno++; + rp->code = 0; + } + /* Finally, output the default: rule. We choose as the default: all + ** empty actions. */ + fprintf(out," default:\n"); lineno++; + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->code==0 ) continue; + assert( rp->code[0]=='\n' && rp->code[1]==0 ); + fprintf(out," /* (%d) ", rp->index); + writeRuleText(out, rp); + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->index); lineno++; + } + fprintf(out," break;\n"); lineno++; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes if a parse fails */ + tplt_print(out,lemp,lemp->failure,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes when a syntax error occurs */ + tplt_print(out,lemp,lemp->error,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes when the parser accepts its input */ + tplt_print(out,lemp,lemp->accept,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Append any addition code the user desires */ + tplt_print(out,lemp,lemp->extracode,&lineno); + + fclose(in); + fclose(out); + return; +} + +/* Generate a header file for the parser */ +void ReportHeader(struct lemon *lemp) +{ + FILE *out, *in; + const char *prefix; + char line[LINESIZE]; + char pattern[LINESIZE]; + int i; + + if( lemp->tokenprefix ) prefix = lemp->tokenprefix; + else prefix = ""; + in = file_open(lemp,".h","rb"); + if( in ){ + int nextChar; + for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){ + lemon_sprintf(pattern,"#define %s%-30s %3d\n", + prefix,lemp->symbols[i]->name,i); + if( strcmp(line,pattern) ) break; + } + nextChar = fgetc(in); + fclose(in); + if( i==lemp->nterminal && nextChar==EOF ){ + /* No change in the file. Don't rewrite it. */ + return; + } + } + out = file_open(lemp,".h","wb"); + if( out ){ + for(i=1; i<lemp->nterminal; i++){ + fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i); + } + fclose(out); + } + return; +} + +/* Reduce the size of the action tables, if possible, by making use +** of defaults. +** +** In this version, we take the most frequent REDUCE action and make +** it the default. Except, there is no default if the wildcard token +** is a possible look-ahead. +*/ +void CompressTables(struct lemon *lemp) +{ + struct state *stp; + struct action *ap, *ap2; + struct rule *rp, *rp2, *rbest; + int nbest, n; + int i; + int usesWildcard; + + for(i=0; i<lemp->nstate; i++){ + stp = lemp->sorted[i]; + nbest = 0; + rbest = 0; + usesWildcard = 0; + + for(ap=stp->ap; ap; ap=ap->next){ + if( ap->type==SHIFT && ap->sp==lemp->wildcard ){ + usesWildcard = 1; + } + if( ap->type!=REDUCE ) continue; + rp = ap->x.rp; + if( rp->lhsStart ) continue; + if( rp==rbest ) continue; + n = 1; + for(ap2=ap->next; ap2; ap2=ap2->next){ + if( ap2->type!=REDUCE ) continue; + rp2 = ap2->x.rp; + if( rp2==rbest ) continue; + if( rp2==rp ) n++; + } + if( n>nbest ){ + nbest = n; + rbest = rp; + } + } + + /* Do not make a default if the number of rules to default + ** is not at least 1 or if the wildcard token is a possible + ** lookahead. + */ + if( nbest<1 || usesWildcard ) continue; + + + /* Combine matching REDUCE actions into a single default */ + for(ap=stp->ap; ap; ap=ap->next){ + if( ap->type==REDUCE && ap->x.rp==rbest ) break; + } + assert( ap ); + ap->sp = Symbol_new("{default}"); + for(ap=ap->next; ap; ap=ap->next){ + if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED; + } + stp->ap = Action_sort(stp->ap); + } +} + + +/* +** Compare two states for sorting purposes. The smaller state is the +** one with the most non-terminal actions. If they have the same number +** of non-terminal actions, then the smaller is the one with the most +** token actions. +*/ +static int stateResortCompare(const void *a, const void *b){ + const struct state *pA = *(const struct state**)a; + const struct state *pB = *(const struct state**)b; + int n; + + n = pB->nNtAct - pA->nNtAct; + if( n==0 ){ + n = pB->nTknAct - pA->nTknAct; + if( n==0 ){ + n = pB->statenum - pA->statenum; + } + } + assert( n!=0 ); + return n; +} + + +/* +** Renumber and resort states so that states with fewer choices +** occur at the end. Except, keep state 0 as the first state. +*/ +void ResortStates(struct lemon *lemp) +{ + int i; + struct state *stp; + struct action *ap; + + for(i=0; i<lemp->nstate; i++){ + stp = lemp->sorted[i]; + stp->nTknAct = stp->nNtAct = 0; + stp->iDflt = lemp->nstate + lemp->nrule; + stp->iTknOfst = NO_OFFSET; + stp->iNtOfst = NO_OFFSET; + for(ap=stp->ap; ap; ap=ap->next){ + if( compute_action(lemp,ap)>=0 ){ + if( ap->sp->index<lemp->nterminal ){ + stp->nTknAct++; + }else if( ap->sp->index<lemp->nsymbol ){ + stp->nNtAct++; + }else{ + stp->iDflt = compute_action(lemp, ap); + } + } + } + } + qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]), + stateResortCompare); + for(i=0; i<lemp->nstate; i++){ + lemp->sorted[i]->statenum = i; + } +} + + +/***************** From the file "set.c" ************************************/ +/* +** Set manipulation routines for the LEMON parser generator. +*/ + +static int size = 0; + +/* Set the set size */ +void SetSize(int n) +{ + size = n+1; +} + +/* Allocate a new set */ +char *SetNew(){ + char *s; + s = (char*)calloc( size, 1); + if( s==0 ){ + extern void memory_error(); + memory_error(); + } + return s; +} + +/* Deallocate a set */ +void SetFree(char *s) +{ + free(s); +} + +/* Add a new element to the set. Return TRUE if the element was added +** and FALSE if it was already there. */ +int SetAdd(char *s, int e) +{ + int rv; + assert( e>=0 && e<size ); + rv = s[e]; + s[e] = 1; + return !rv; +} + +/* Add every element of s2 to s1. Return TRUE if s1 changes. */ +int SetUnion(char *s1, char *s2) +{ + int i, progress; + progress = 0; + for(i=0; i<size; i++){ + if( s2[i]==0 ) continue; + if( s1[i]==0 ){ + progress = 1; + s1[i] = 1; + } + } + return progress; +} +/********************** From the file "table.c" ****************************/ +/* +** All code in this file has been automatically generated +** from a specification in the file +** "table.q" +** by the associative array code building program "aagen". +** Do not edit this file! Instead, edit the specification +** file, then rerun aagen. +*/ +/* +** Code for processing tables in the LEMON parser generator. +*/ + +PRIVATE unsigned strhash(const char *x) +{ + unsigned h = 0; + while( *x ) h = h*13 + *(x++); + return h; +} + +/* Works like strdup, sort of. Save a string in malloced memory, but +** keep strings in a table so that the same string is not in more +** than one place. +*/ +const char *Strsafe(const char *y) +{ + const char *z; + char *cpy; + + if( y==0 ) return 0; + z = Strsafe_find(y); + if( z==0 && (cpy=(char *)malloc( lemonStrlen(y)+1 ))!=0 ){ + lemon_strcpy(cpy,y); + z = cpy; + Strsafe_insert(z); + } + MemoryCheck(z); + return z; +} + +/* There is one instance of the following structure for each +** associative array of type "x1". +*/ +struct s_x1 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x1node *tbl; /* The data stored here */ + struct s_x1node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x1". +*/ +typedef struct s_x1node { + const char *data; /* The data */ + struct s_x1node *next; /* Next entry with the same hash */ + struct s_x1node **from; /* Previous link */ +} x1node; + +/* There is only one instance of the array, which is the following */ +static struct s_x1 *x1a; + +/* Allocate a new associative array */ +void Strsafe_init(){ + if( x1a ) return; + x1a = (struct s_x1*)malloc( sizeof(struct s_x1) ); + if( x1a ){ + x1a->size = 1024; + x1a->count = 0; + x1a->tbl = (x1node*)calloc(1024, sizeof(x1node) + sizeof(x1node*)); + if( x1a->tbl==0 ){ + free(x1a); + x1a = 0; + }else{ + int i; + x1a->ht = (x1node**)&(x1a->tbl[1024]); + for(i=0; i<1024; i++) x1a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int Strsafe_insert(const char *data) +{ + x1node *np; + unsigned h; + unsigned ph; + + if( x1a==0 ) return 0; + ph = strhash(data); + h = ph & (x1a->size-1); + np = x1a->ht[h]; + while( np ){ + if( strcmp(np->data,data)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x1a->count>=x1a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x1 array; + array.size = size = x1a->size*2; + array.count = x1a->count; + array.tbl = (x1node*)calloc(size, sizeof(x1node) + sizeof(x1node*)); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x1node**)&(array.tbl[size]); + for(i=0; i<size; i++) array.ht[i] = 0; + for(i=0; i<x1a->count; i++){ + x1node *oldnp, *newnp; + oldnp = &(x1a->tbl[i]); + h = strhash(oldnp->data) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x1a->tbl); + *x1a = array; + } + /* Insert the new data */ + h = ph & (x1a->size-1); + np = &(x1a->tbl[x1a->count++]); + np->data = data; + if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next); + np->next = x1a->ht[h]; + x1a->ht[h] = np; + np->from = &(x1a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +const char *Strsafe_find(const char *key) +{ + unsigned h; + x1node *np; + + if( x1a==0 ) return 0; + h = strhash(key) & (x1a->size-1); + np = x1a->ht[h]; + while( np ){ + if( strcmp(np->data,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Return a pointer to the (terminal or nonterminal) symbol "x". +** Create a new symbol if this is the first time "x" has been seen. +*/ +struct symbol *Symbol_new(const char *x) +{ + struct symbol *sp; + + sp = Symbol_find(x); + if( sp==0 ){ + sp = (struct symbol *)calloc(1, sizeof(struct symbol) ); + MemoryCheck(sp); + sp->name = Strsafe(x); + sp->type = isupper(*x) ? TERMINAL : NONTERMINAL; + sp->rule = 0; + sp->fallback = 0; + sp->prec = -1; + sp->assoc = UNK; + sp->firstset = 0; + sp->lambda = LEMON_FALSE; + sp->destructor = 0; + sp->destLineno = 0; + sp->datatype = 0; + sp->useCnt = 0; + Symbol_insert(sp,sp->name); + } + sp->useCnt++; + return sp; +} + +/* Compare two symbols for sorting purposes. Return negative, +** zero, or positive if a is less then, equal to, or greater +** than b. +** +** Symbols that begin with upper case letters (terminals or tokens) +** must sort before symbols that begin with lower case letters +** (non-terminals). And MULTITERMINAL symbols (created using the +** %token_class directive) must sort at the very end. Other than +** that, the order does not matter. +** +** We find experimentally that leaving the symbols in their original +** order (the order they appeared in the grammar file) gives the +** smallest parser tables in SQLite. +*/ +int Symbolcmpp(const void *_a, const void *_b) +{ + const struct symbol *a = *(const struct symbol **) _a; + const struct symbol *b = *(const struct symbol **) _b; + int i1 = a->type==MULTITERMINAL ? 3 : a->name[0]>'Z' ? 2 : 1; + int i2 = b->type==MULTITERMINAL ? 3 : b->name[0]>'Z' ? 2 : 1; + return i1==i2 ? a->index - b->index : i1 - i2; +} + +/* There is one instance of the following structure for each +** associative array of type "x2". +*/ +struct s_x2 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x2node *tbl; /* The data stored here */ + struct s_x2node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x2". +*/ +typedef struct s_x2node { + struct symbol *data; /* The data */ + const char *key; /* The key */ + struct s_x2node *next; /* Next entry with the same hash */ + struct s_x2node **from; /* Previous link */ +} x2node; + +/* There is only one instance of the array, which is the following */ +static struct s_x2 *x2a; + +/* Allocate a new associative array */ +void Symbol_init(){ + if( x2a ) return; + x2a = (struct s_x2*)malloc( sizeof(struct s_x2) ); + if( x2a ){ + x2a->size = 128; + x2a->count = 0; + x2a->tbl = (x2node*)calloc(128, sizeof(x2node) + sizeof(x2node*)); + if( x2a->tbl==0 ){ + free(x2a); + x2a = 0; + }else{ + int i; + x2a->ht = (x2node**)&(x2a->tbl[128]); + for(i=0; i<128; i++) x2a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int Symbol_insert(struct symbol *data, const char *key) +{ + x2node *np; + unsigned h; + unsigned ph; + + if( x2a==0 ) return 0; + ph = strhash(key); + h = ph & (x2a->size-1); + np = x2a->ht[h]; + while( np ){ + if( strcmp(np->key,key)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x2a->count>=x2a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x2 array; + array.size = size = x2a->size*2; + array.count = x2a->count; + array.tbl = (x2node*)calloc(size, sizeof(x2node) + sizeof(x2node*)); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x2node**)&(array.tbl[size]); + for(i=0; i<size; i++) array.ht[i] = 0; + for(i=0; i<x2a->count; i++){ + x2node *oldnp, *newnp; + oldnp = &(x2a->tbl[i]); + h = strhash(oldnp->key) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->key = oldnp->key; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x2a->tbl); + *x2a = array; + } + /* Insert the new data */ + h = ph & (x2a->size-1); + np = &(x2a->tbl[x2a->count++]); + np->key = key; + np->data = data; + if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next); + np->next = x2a->ht[h]; + x2a->ht[h] = np; + np->from = &(x2a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +struct symbol *Symbol_find(const char *key) +{ + unsigned h; + x2node *np; + + if( x2a==0 ) return 0; + h = strhash(key) & (x2a->size-1); + np = x2a->ht[h]; + while( np ){ + if( strcmp(np->key,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Return the n-th data. Return NULL if n is out of range. */ +struct symbol *Symbol_Nth(int n) +{ + struct symbol *data; + if( x2a && n>0 && n<=x2a->count ){ + data = x2a->tbl[n-1].data; + }else{ + data = 0; + } + return data; +} + +/* Return the size of the array */ +int Symbol_count() +{ + return x2a ? x2a->count : 0; +} + +/* Return an array of pointers to all data in the table. +** The array is obtained from malloc. Return NULL if memory allocation +** problems, or if the array is empty. */ +struct symbol **Symbol_arrayof() +{ + struct symbol **array; + int i,size; + if( x2a==0 ) return 0; + size = x2a->count; + array = (struct symbol **)calloc(size, sizeof(struct symbol *)); + if( array ){ + for(i=0; i<size; i++) array[i] = x2a->tbl[i].data; + } + return array; +} + +/* Compare two configurations */ +int Configcmp(const char *_a,const char *_b) +{ + const struct config *a = (struct config *) _a; + const struct config *b = (struct config *) _b; + int x; + x = a->rp->index - b->rp->index; + if( x==0 ) x = a->dot - b->dot; + return x; +} + +/* Compare two states */ +PRIVATE int statecmp(struct config *a, struct config *b) +{ + int rc; + for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){ + rc = a->rp->index - b->rp->index; + if( rc==0 ) rc = a->dot - b->dot; + } + if( rc==0 ){ + if( a ) rc = 1; + if( b ) rc = -1; + } + return rc; +} + +/* Hash a state */ +PRIVATE unsigned statehash(struct config *a) +{ + unsigned h=0; + while( a ){ + h = h*571 + a->rp->index*37 + a->dot; + a = a->bp; + } + return h; +} + +/* Allocate a new state structure */ +struct state *State_new() +{ + struct state *newstate; + newstate = (struct state *)calloc(1, sizeof(struct state) ); + MemoryCheck(newstate); + return newstate; +} + +/* There is one instance of the following structure for each +** associative array of type "x3". +*/ +struct s_x3 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x3node *tbl; /* The data stored here */ + struct s_x3node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x3". +*/ +typedef struct s_x3node { + struct state *data; /* The data */ + struct config *key; /* The key */ + struct s_x3node *next; /* Next entry with the same hash */ + struct s_x3node **from; /* Previous link */ +} x3node; + +/* There is only one instance of the array, which is the following */ +static struct s_x3 *x3a; + +/* Allocate a new associative array */ +void State_init(){ + if( x3a ) return; + x3a = (struct s_x3*)malloc( sizeof(struct s_x3) ); + if( x3a ){ + x3a->size = 128; + x3a->count = 0; + x3a->tbl = (x3node*)calloc(128, sizeof(x3node) + sizeof(x3node*)); + if( x3a->tbl==0 ){ + free(x3a); + x3a = 0; + }else{ + int i; + x3a->ht = (x3node**)&(x3a->tbl[128]); + for(i=0; i<128; i++) x3a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int State_insert(struct state *data, struct config *key) +{ + x3node *np; + unsigned h; + unsigned ph; + + if( x3a==0 ) return 0; + ph = statehash(key); + h = ph & (x3a->size-1); + np = x3a->ht[h]; + while( np ){ + if( statecmp(np->key,key)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x3a->count>=x3a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x3 array; + array.size = size = x3a->size*2; + array.count = x3a->count; + array.tbl = (x3node*)calloc(size, sizeof(x3node) + sizeof(x3node*)); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x3node**)&(array.tbl[size]); + for(i=0; i<size; i++) array.ht[i] = 0; + for(i=0; i<x3a->count; i++){ + x3node *oldnp, *newnp; + oldnp = &(x3a->tbl[i]); + h = statehash(oldnp->key) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->key = oldnp->key; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x3a->tbl); + *x3a = array; + } + /* Insert the new data */ + h = ph & (x3a->size-1); + np = &(x3a->tbl[x3a->count++]); + np->key = key; + np->data = data; + if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next); + np->next = x3a->ht[h]; + x3a->ht[h] = np; + np->from = &(x3a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +struct state *State_find(struct config *key) +{ + unsigned h; + x3node *np; + + if( x3a==0 ) return 0; + h = statehash(key) & (x3a->size-1); + np = x3a->ht[h]; + while( np ){ + if( statecmp(np->key,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Return an array of pointers to all data in the table. +** The array is obtained from malloc. Return NULL if memory allocation +** problems, or if the array is empty. */ +struct state **State_arrayof() +{ + struct state **array; + int i,size; + if( x3a==0 ) return 0; + size = x3a->count; + array = (struct state **)calloc(size, sizeof(struct state *)); + if( array ){ + for(i=0; i<size; i++) array[i] = x3a->tbl[i].data; + } + return array; +} + +/* Hash a configuration */ +PRIVATE unsigned confighash(struct config *a) +{ + unsigned h=0; + h = h*571 + a->rp->index*37 + a->dot; + return h; +} + +/* There is one instance of the following structure for each +** associative array of type "x4". +*/ +struct s_x4 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x4node *tbl; /* The data stored here */ + struct s_x4node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x4". +*/ +typedef struct s_x4node { + struct config *data; /* The data */ + struct s_x4node *next; /* Next entry with the same hash */ + struct s_x4node **from; /* Previous link */ +} x4node; + +/* There is only one instance of the array, which is the following */ +static struct s_x4 *x4a; + +/* Allocate a new associative array */ +void Configtable_init(){ + if( x4a ) return; + x4a = (struct s_x4*)malloc( sizeof(struct s_x4) ); + if( x4a ){ + x4a->size = 64; + x4a->count = 0; + x4a->tbl = (x4node*)calloc(64, sizeof(x4node) + sizeof(x4node*)); + if( x4a->tbl==0 ){ + free(x4a); + x4a = 0; + }else{ + int i; + x4a->ht = (x4node**)&(x4a->tbl[64]); + for(i=0; i<64; i++) x4a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int Configtable_insert(struct config *data) +{ + x4node *np; + unsigned h; + unsigned ph; + + if( x4a==0 ) return 0; + ph = confighash(data); + h = ph & (x4a->size-1); + np = x4a->ht[h]; + while( np ){ + if( Configcmp((const char *) np->data,(const char *) data)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x4a->count>=x4a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x4 array; + array.size = size = x4a->size*2; + array.count = x4a->count; + array.tbl = (x4node*)calloc(size, sizeof(x4node) + sizeof(x4node*)); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x4node**)&(array.tbl[size]); + for(i=0; i<size; i++) array.ht[i] = 0; + for(i=0; i<x4a->count; i++){ + x4node *oldnp, *newnp; + oldnp = &(x4a->tbl[i]); + h = confighash(oldnp->data) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x4a->tbl); + *x4a = array; + } + /* Insert the new data */ + h = ph & (x4a->size-1); + np = &(x4a->tbl[x4a->count++]); + np->data = data; + if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next); + np->next = x4a->ht[h]; + x4a->ht[h] = np; + np->from = &(x4a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +struct config *Configtable_find(struct config *key) +{ + int h; + x4node *np; + + if( x4a==0 ) return 0; + h = confighash(key) & (x4a->size-1); + np = x4a->ht[h]; + while( np ){ + if( Configcmp((const char *) np->data,(const char *) key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Remove all data from the table. Pass each data to the function "f" +** as it is removed. ("f" may be null to avoid this step.) */ +void Configtable_clear(int(*f)(struct config *)) +{ + int i; + if( x4a==0 || x4a->count==0 ) return; + if( f ) for(i=0; i<x4a->count; i++) (*f)(x4a->tbl[i].data); + for(i=0; i<x4a->size; i++) x4a->ht[i] = 0; + x4a->count = 0; + return; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp index 77036f7..f6a23a0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp @@ -282,7 +282,7 @@ QString Lexer::detokenize(const TokenList& tokens) return ""; QString str; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) str += detokenize(token); return str; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp index 0f9aa91..9a0d3d2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp @@ -51,7 +51,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole { if (charAt(z, 1) == '-') { - for (i=2; (c = charAt(z, i)) != 0 && c != '\n'; i++) {} + for (i=2; !(c = charAt(z, i)).isNull() && c != '\n'; i++) {} token->lemonType = v3 ? TK3_COMMENT : TK2_COMMENT; token->type = Token::COMMENT; return i; @@ -99,7 +99,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole return 1; } - if ( charAt(z, 2) == 0 ) + if ( charAt(z, 2).isNull() ) { token->lemonType = v3 ? TK3_COMMENT : TK2_COMMENT; token->type = Token::COMMENT; @@ -108,12 +108,16 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole return 2; } - for (i = 3, c = charAt(z, 2); (c != '*' || charAt(z, i) != '/') && (c = charAt(z, i)) != 0; i++) {} + for (i = 3, c = charAt(z, 2); (c != '*' || charAt(z, i) != '/') && !(c = charAt(z, i)).isNull(); i++) {} if (tolerant && (c != '*' || charAt(z, i) != '/')) token.dynamicCast<TolerantToken>()->invalid = true; +#if QT_VERSION >= 0x050800 + if ( c.unicode() > 0 ) +#else if ( c > 0 ) +#endif i++; token->lemonType = v3 ? TK3_COMMENT : TK2_COMMENT; token->type = Token::COMMENT; @@ -232,7 +236,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole z0 == '"') { QChar delim = z0; - for (i = 1; (c = charAt(z, i)) != 0; i++) + for (i = 1; !(c = charAt(z, i)).isNull(); i++) { if ( c == delim ) { @@ -248,7 +252,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole token->type = Token::STRING; return i+1; } - else if ( c != 0 ) + else if ( !c.isNull() ) { token->lemonType = v3 ? TK3_ID : TK2_ID; token->type = Token::OTHER; @@ -289,7 +293,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole * number that begins with ".". Fall thru into the next case */ } - if (z0.isDigit()) + if (z0.isDigit() || z0 == '.') { token->lemonType = v3 ? TK3_INTEGER : TK2_INTEGER; token->type = Token::INTEGER; @@ -331,7 +335,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole } if (z0 == '[') { - for (i = 1, c = z0; c!=']' && (c = charAt(z, i)) != 0; i++) {} + for (i = 1, c = z0; c!=']' && !(c = charAt(z, i)).isNull(); i++) {} if (c == ']') { token->lemonType = v3 ? TK3_ID : TK2_ID; @@ -364,7 +368,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole int n = 0; token->lemonType = v3 ? TK3_VARIABLE : TK2_VARIABLE; token->type = Token::BIND_PARAM; - for (i = 1; (c = charAt(z, i)) != 0; i++) + for (i = 1; !(c = charAt(z, i)).isNull(); i++) { if ( isIdChar(c) ) { @@ -376,7 +380,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole { i++; } - while ( (c = charAt(z, i)) != 0 && !c.isSpace() && c != ')' ); + while ( !(c = charAt(z, i)).isNull() && !c.isSpace() && c != ')' ); if ( c==')' ) { @@ -428,10 +432,18 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole token->lemonType = TK3_ILLEGAL; token->type = Token::INVALID; } +#if QT_VERSION >= 0x050800 + while (charAt(z, i).unicode() > 0 && charAt(z, i).unicode() != '\'') +#else while (charAt(z, i) > 0 && charAt(z, i) != '\'') +#endif i++; } +#if QT_VERSION >= 0x050800 + if ( charAt(z, i).unicode() > 0 ) +#else if ( charAt(z, i) > 0 ) +#endif i++; return i; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h index 87ba7e5..9027d04 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h @@ -3,6 +3,7 @@ #include "parser/token.h" #include <QString> +#include <QTextStream> /** @file */ diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp index 23a4b55..55669a5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp @@ -55,7 +55,7 @@ void Parser::cleanUp() void Parser::fillSqliteDialect() { - foreach (SqliteQueryPtr query, context->parsedQueries) + for (SqliteQueryPtr query : context->parsedQueries) query->setSqliteDialect(dialect); } @@ -263,7 +263,7 @@ void Parser::expectedTokenLookup(void* pParser) Token::CTX_ROWID_KW, Token::INVALID }); - foreach (TokenPtr token, tokenSet) + for (TokenPtr token : tokenSet) { parse(pParser, token->lemonType, token, &tempContext); @@ -290,7 +290,7 @@ const QList<ParserError *> &Parser::getErrors() QString Parser::getErrorString() { QStringList msgs; - foreach (ParserError* error, getErrors()) + for (ParserError* error : getErrors()) { msgs += error->getMessage(); } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser.h b/SQLiteStudio3/coreSQLiteStudio/parser/parser.h index aaf3962..8fe25f2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/parser.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser.h @@ -23,7 +23,7 @@ class ParserError; * { * QList<SqliteQueryPtr> queries = parser.getQueries(); * qDebug() << "number of queries parsed:" << queries.size(); - * foreach (SqliteQueryPtr query, queries) + * for (SqliteQueryPtr query : queries) * { * // do stuff with parsed queries * // ... diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h b/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h index 97a6393..ae52989 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h @@ -73,10 +73,9 @@ typedef QList<SqliteForeignKey::Condition*> ParserFkConditionList; typedef QList<SqliteExpr*> ParserExprList; typedef QList<SqliteSelect::Core::ResultColumn*> ParserResultColumnList; typedef QList<SqliteSelect::Core::JoinSourceOther*> ParserOtherSourceList; -typedef QList<QString> ParserStringList; typedef QList<SqliteOrderBy*> ParserOrderByList; typedef QList<SqliteQuery*> ParserQueryList; -typedef QPair<QString,SqliteExpr*> ParserSetValue; +typedef QPair<QVariant,SqliteExpr*> ParserSetValue; typedef QList<ParserSetValue> ParserSetValueList; typedef QList<SqliteIndexedColumn*> ParserIndexedColumnList; typedef QList<ParserExprList> ParserExprNestedList; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp index 7f8ad7a..d9832bc 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp @@ -130,7 +130,7 @@ TokenPtr ParserContext::getTokenPtr(Token* token) TokenList ParserContext::getTokenPtrList(const QList<Token*>& tokens) { TokenList resList; - foreach (Token* token, tokens) + for (Token* token : tokens) resList << getTokenPtr(token); return resList; @@ -196,7 +196,7 @@ bool ParserContext::isCandidateForMaxNegativeNumber() const void ParserContext::cleanUp() { - foreach (ParserError* err, errors) + for (ParserError* err : errors) delete err; parsedQueries.clear(); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.bat b/SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.bat new file mode 100644 index 0000000..961e21e --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.bat @@ -0,0 +1,8 @@ +set LEMON=C:\utils\lemon.exe + +rem %LEMON% -l -q -s sqlite3_parse.y +%LEMON% -l -q sqlite3_parse.y +move sqlite3_parse.c sqlite3_parse.cpp + +%LEMON% -l -q sqlite2_parse.y +move sqlite2_parse.c sqlite2_parse.cpp diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp index 81e242d..ea60ecc 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp @@ -120,6 +120,7 @@ typedef union { QVariant* yy69; SqliteCreateTrigger::Scope* yy83; ParserStubExplain* yy91; + QStringList* yy95; ParserFullName* yy120; SqliteSelect::Core::SingleSource* yy121; ParserOtherSourceList* yy131; @@ -131,7 +132,6 @@ typedef union { SqliteExpr* yy192; ParserSetValueList* yy201; SqliteQuery* yy203; - ParserStringList* yy207; ParserResultColumnList* yy213; SqliteSelect::Core::JoinOp* yy221; int* yy226; @@ -347,7 +347,7 @@ static const YYACTIONTYPE yy_action[] = { /* 1050 */ 523, 328, 523, 570, 65, 531, 500, 13, 523, 101, /* 1060 */ 185, 184, 35, 570, 172, 171, 170, 197, 290, 503, /* 1070 */ 328, 523, 75, 570, 531, 301, 13, 523, 32, 33, - /* 1080 */ 380, 35, 10, 568, 567, 479, 34, 489, 540, 539, + /* 1080 */ 380, 35, 10, 568, 567, 479, 34, 490, 540, 539, /* 1090 */ 568, 567, 570, 325, 7, 211, 666, 32, 33, 523, /* 1100 */ 179, 423, 336, 335, 570, 34, 549, 548, 550, 80, /* 1110 */ 569, 570, 490, 7, 480, 489, 391, 570, 523, 568, @@ -983,9 +983,9 @@ static const char *const yyTokenName[] = { "from", "where_opt", "groupby_opt", "having_opt", "orderby_opt", "limit_opt", "sclp", "as", "joinsrc", "singlesrc", "seltablist", "joinop", - "joinconstr_opt", "dbnm", "inscollist", "sortlist", + "joinconstr_opt", "dbnm", "idlist", "sortlist", "collate", "nexprlist", "delete_stmt", "update_stmt", - "setlist", "insert_stmt", "insert_cmd", "inscollist_opt", + "setlist", "insert_stmt", "insert_cmd", "idlist_opt", "exprlist", "exprx", "not_opt", "likeop", "case_operand", "case_exprlist", "case_else", "raisetype", "uniqueflag", "idxlist_single", "nmnum", "number", @@ -1151,7 +1151,7 @@ static const char *const yyRuleName[] = { /* 150 */ "singlesrc ::= nm DOT ID_VIEW", /* 151 */ "singlesrc ::= ID_DB|ID_VIEW", /* 152 */ "joinconstr_opt ::= ON expr", - /* 153 */ "joinconstr_opt ::= USING LP inscollist RP", + /* 153 */ "joinconstr_opt ::= USING LP idlist RP", /* 154 */ "joinconstr_opt ::=", /* 155 */ "dbnm ::=", /* 156 */ "dbnm ::= DOT nm", @@ -1202,21 +1202,21 @@ static const char *const yyRuleName[] = { /* 201 */ "setlist ::= setlist COMMA ID_COL", /* 202 */ "setlist ::= ID_COL", /* 203 */ "cmd ::= insert_stmt", - /* 204 */ "insert_stmt ::= insert_cmd INTO fullname inscollist_opt VALUES LP exprlist RP", - /* 205 */ "insert_stmt ::= insert_cmd INTO fullname inscollist_opt select", + /* 204 */ "insert_stmt ::= insert_cmd INTO fullname idlist_opt VALUES LP exprlist RP", + /* 205 */ "insert_stmt ::= insert_cmd INTO fullname idlist_opt select", /* 206 */ "insert_stmt ::= insert_cmd INTO", /* 207 */ "insert_stmt ::= insert_cmd INTO nm DOT", /* 208 */ "insert_stmt ::= insert_cmd INTO ID_DB|ID_TAB", /* 209 */ "insert_stmt ::= insert_cmd INTO nm DOT ID_TAB", /* 210 */ "insert_cmd ::= INSERT orconf", /* 211 */ "insert_cmd ::= REPLACE", - /* 212 */ "inscollist_opt ::=", - /* 213 */ "inscollist_opt ::= LP inscollist RP", - /* 214 */ "inscollist ::= inscollist COMMA nm", - /* 215 */ "inscollist ::= nm", - /* 216 */ "inscollist ::=", - /* 217 */ "inscollist ::= inscollist COMMA ID_COL", - /* 218 */ "inscollist ::= ID_COL", + /* 212 */ "idlist_opt ::=", + /* 213 */ "idlist_opt ::= LP idlist RP", + /* 214 */ "idlist ::= idlist COMMA nm", + /* 215 */ "idlist ::= nm", + /* 216 */ "idlist ::=", + /* 217 */ "idlist ::= idlist COMMA ID_COL", + /* 218 */ "idlist ::= ID_COL", /* 219 */ "exprx ::= NULL", /* 220 */ "exprx ::= INTEGER", /* 221 */ "exprx ::= FLOAT", @@ -1328,7 +1328,7 @@ static const char *const yyRuleName[] = { /* 327 */ "trigger_event ::= DELETE", /* 328 */ "trigger_event ::= INSERT", /* 329 */ "trigger_event ::= UPDATE", - /* 330 */ "trigger_event ::= UPDATE OF inscollist", + /* 330 */ "trigger_event ::= UPDATE OF idlist", /* 331 */ "foreach_clause ::=", /* 332 */ "foreach_clause ::= FOR EACH ROW", /* 333 */ "foreach_clause ::= FOR EACH STATEMENT", @@ -1654,10 +1654,10 @@ delete (yypminor->yy221); delete (yypminor->yy455); } break; - case 210: /* inscollist */ - case 219: /* inscollist_opt */ + case 210: /* idlist */ + case 219: /* idlist_opt */ { -delete (yypminor->yy207); +delete (yypminor->yy95); } break; case 212: /* collate */ @@ -3223,10 +3223,10 @@ static void yy_reduce( objectForTokens = yygotominor.yy455; } break; - case 153: /* joinconstr_opt ::= USING LP inscollist RP */ + case 153: /* joinconstr_opt ::= USING LP idlist RP */ { - yygotominor.yy455 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy207)); - delete yymsp[-1].minor.yy207; + yygotominor.yy455 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy95)); + delete yymsp[-1].minor.yy95; objectForTokens = yygotominor.yy455; } break; @@ -3540,39 +3540,39 @@ static void yy_reduce( { yy_destructor(yypParser,216,&yymsp[-2].minor); } break; - case 204: /* insert_stmt ::= insert_cmd INTO fullname inscollist_opt VALUES LP exprlist RP */ + case 204: /* insert_stmt ::= insert_cmd INTO fullname idlist_opt VALUES LP exprlist RP */ { yygotominor.yy203 = new SqliteInsert( yymsp[-7].minor.yy344->replace, yymsp[-7].minor.yy344->orConflict, yymsp[-5].minor.yy120->name1, yymsp[-5].minor.yy120->name2, - *(yymsp[-4].minor.yy207), + *(yymsp[-4].minor.yy95), *(yymsp[-1].minor.yy231), nullptr ); delete yymsp[-5].minor.yy120; delete yymsp[-7].minor.yy344; delete yymsp[-1].minor.yy231; - delete yymsp[-4].minor.yy207; + delete yymsp[-4].minor.yy95; // since it's used in trigger: objectForTokens = yygotominor.yy203; } break; - case 205: /* insert_stmt ::= insert_cmd INTO fullname inscollist_opt select */ + case 205: /* insert_stmt ::= insert_cmd INTO fullname idlist_opt select */ { yygotominor.yy203 = new SqliteInsert( yymsp[-4].minor.yy344->replace, yymsp[-4].minor.yy344->orConflict, yymsp[-2].minor.yy120->name1, yymsp[-2].minor.yy120->name2, - *(yymsp[-1].minor.yy207), + *(yymsp[-1].minor.yy95), yymsp[0].minor.yy153, nullptr ); delete yymsp[-2].minor.yy120; delete yymsp[-4].minor.yy344; - delete yymsp[-1].minor.yy207; + delete yymsp[-1].minor.yy95; // since it's used in trigger: objectForTokens = yygotominor.yy203; } @@ -3619,35 +3619,35 @@ static void yy_reduce( case 211: /* insert_cmd ::= REPLACE */ {yygotominor.yy344 = new ParserStubInsertOrReplace(true);} break; - case 212: /* inscollist_opt ::= */ -{yygotominor.yy207 = new ParserStringList();} + case 212: /* idlist_opt ::= */ +{yygotominor.yy95 = new QStringList();} break; - case 213: /* inscollist_opt ::= LP inscollist RP */ -{yygotominor.yy207 = yymsp[-1].minor.yy207;} + case 213: /* idlist_opt ::= LP idlist RP */ +{yygotominor.yy95 = yymsp[-1].minor.yy95;} break; - case 214: /* inscollist ::= inscollist COMMA nm */ + case 214: /* idlist ::= idlist COMMA nm */ { - yymsp[-2].minor.yy207->append(*(yymsp[0].minor.yy319)); - yygotominor.yy207 = yymsp[-2].minor.yy207; + yymsp[-2].minor.yy95->append(*(yymsp[0].minor.yy319)); + yygotominor.yy95 = yymsp[-2].minor.yy95; delete yymsp[0].minor.yy319; - DONT_INHERIT_TOKENS("inscollist"); + DONT_INHERIT_TOKENS("idlist"); } break; - case 215: /* inscollist ::= nm */ + case 215: /* idlist ::= nm */ { - yygotominor.yy207 = new ParserStringList(); - yygotominor.yy207->append(*(yymsp[0].minor.yy319)); + yygotominor.yy95 = new QStringList(); + yygotominor.yy95->append(*(yymsp[0].minor.yy319)); delete yymsp[0].minor.yy319; } break; - case 216: /* inscollist ::= */ + case 216: /* idlist ::= */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy207 = new ParserStringList(); + yygotominor.yy95 = new QStringList(); } break; - case 217: /* inscollist ::= inscollist COMMA ID_COL */ - case 218: /* inscollist ::= ID_COL */ yytestcase(yyruleno==218); + case 217: /* idlist ::= idlist COMMA ID_COL */ + case 218: /* idlist ::= ID_COL */ yytestcase(yyruleno==218); { yy_destructor(yypParser,210,&yymsp[-2].minor); } break; @@ -4256,10 +4256,10 @@ static void yy_reduce( objectForTokens = yygotominor.yy151; } break; - case 330: /* trigger_event ::= UPDATE OF inscollist */ + case 330: /* trigger_event ::= UPDATE OF idlist */ { - yygotominor.yy151 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy207)); - delete yymsp[0].minor.yy207; + yygotominor.yy151 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy95)); + delete yymsp[0].minor.yy95; objectForTokens = yygotominor.yy151; } break; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y index 472725e..621d92e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y @@ -907,7 +907,7 @@ joinconstr_opt(X) ::= ON expr(E). { objectForTokens = X; } joinconstr_opt(X) ::= USING LP - inscollist(L) RP. { + idlist(L) RP. { X = new SqliteSelect::Core::JoinConstraint(*(L)); delete L; objectForTokens = X; @@ -1227,7 +1227,7 @@ cmd(X) ::= insert_stmt(S). { %type insert_stmt {SqliteQuery*} %destructor insert_stmt {delete $$;} insert_stmt(X) ::= insert_cmd(C) INTO - fullname(N) inscollist_opt(I) + fullname(N) idlist_opt(I) VALUES LP exprlist(L) RP. { X = new SqliteInsert( C->replace, @@ -1246,7 +1246,7 @@ insert_stmt(X) ::= insert_cmd(C) INTO objectForTokens = X; } insert_stmt(X) ::= insert_cmd(C) INTO - fullname(N) inscollist_opt(I) + fullname(N) idlist_opt(I) select(S). { X = new SqliteInsert( C->replace, @@ -1298,32 +1298,32 @@ insert_cmd(X) ::= INSERT orconf(C). { } insert_cmd(X) ::= REPLACE. {X = new ParserStubInsertOrReplace(true);} -%type inscollist_opt {ParserStringList*} -%destructor inscollist_opt {delete $$;} -inscollist_opt(X) ::= . {X = new ParserStringList();} -inscollist_opt(X) ::= LP inscollist(L) RP. {X = L;} +%type idlist_opt {QStringList*} +%destructor idlist_opt {delete $$;} +idlist_opt(X) ::= . {X = new QStringList();} +idlist_opt(X) ::= LP idlist(L) RP. {X = L;} -%type inscollist {ParserStringList*} -%destructor inscollist {delete $$;} -inscollist(X) ::= inscollist(L) COMMA +%type idlist {QStringList*} +%destructor idlist {delete $$;} +idlist(X) ::= idlist(L) COMMA nm(N). { L->append(*(N)); X = L; delete N; - DONT_INHERIT_TOKENS("inscollist"); + DONT_INHERIT_TOKENS("idlist"); } -inscollist(X) ::= nm(N). { - X = new ParserStringList(); +idlist(X) ::= nm(N). { + X = new QStringList(); X->append(*(N)); delete N; } -inscollist(X) ::= . { +idlist(X) ::= . { parserContext->minorErrorBeforeNextToken("Syntax error"); - X = new ParserStringList(); + X = new QStringList(); } -inscollist ::= inscollist COMMA ID_COL. {} -inscollist ::= ID_COL. {} +idlist ::= idlist COMMA ID_COL. {} +idlist ::= ID_COL. {} /////////////////////////// Expression Processing ///////////////////////////// @@ -1984,7 +1984,7 @@ trigger_event(X) ::= UPDATE. { objectForTokens = X; } trigger_event(X) ::= UPDATE OF - inscollist(L). { + idlist(L). { X = new SqliteCreateTrigger::Event(*(L)); delete L; objectForTokens = X; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp index 3884655..ffe6981 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp @@ -49,6 +49,7 @@ #include "parser/ast/sqliteindexedcolumn.h" #include "parser/ast/sqliteforeignkey.h" #include "parser/ast/sqlitewith.h" +#include "parser/ast/sqliteupsert.h" #include <QObject> #include <QDebug> #include <limits.h> @@ -106,62 +107,63 @@ ** defined, then do no error processing. */ #define YYCODETYPE unsigned short int -#define YYNOCODE 278 +#define YYNOCODE 281 #define YYACTIONTYPE unsigned short int #define YYWILDCARD 61 #define sqlite3_parseTOKENTYPE Token* typedef union { int yyinit; sqlite3_parseTOKENTYPE yy0; - SqliteCreateTable::Column::Constraint* yy4; - SqliteCreateTable::Constraint* yy8; - ParserExprList* yy13; - QVariant* yy21; - ParserStubAlias* yy28; - SqliteConflictAlgo* yy30; - ParserFullName* yy66; - ParserCreateTableConstraintList* yy87; - SqliteIndexedColumn* yy90; - ParserFkConditionList* yy108; - SqliteSelect::Core::JoinConstraint* yy117; - ParserCreateTableColumnList* yy118; - SqliteSelect* yy123; - SqliteLimit* yy128; - ParserDeferSubClause* yy131; - ParserIndexedColumnList* yy139; - SqliteCreateTrigger::Time* yy152; - SqliteSelect::CompoundOperator* yy168; - SqliteSelect::Core::SingleSource* yy173; - QString* yy211; - ParserQueryList* yy214; - ParserStubExplain* yy225; - SqliteSortOrder* yy226; - bool* yy237; - ParserStubInsertOrReplace* yy250; - ParserResultColumnList* yy263; - SqliteForeignKey::Condition* yy271; - SqliteColumnType* yy299; - ParserStubTransDetails* yy300; - SqliteCreateTrigger::Event* yy309; - SqliteForeignKey::Condition::Reaction* yy312; - ParserOtherSourceList* yy359; - SqliteWith* yy367; - SqliteSelect::Core::JoinSource* yy373; - SqliteExpr::LikeOp* yy374; - int* yy376; - ParserSetValueList* yy381; - SqliteQuery* yy399; - SqliteCreateTrigger::Scope* yy409; - ParserExprNestedList* yy416; - SqliteCreateTable::Column* yy425; - ParserStringList* yy445; - ParserCreateTableColumnConstraintList* yy449; - SqliteSelect::Core* yy468; - ParserIndexedBy* yy472; - SqliteSelect::Core::JoinOp* yy473; - SqliteExpr* yy490; - ParserOrderByList* yy495; - SqliteInitially* yy498; + SqliteCreateTrigger::Scope* yy3; + ParserCreateTableColumnConstraintList* yy51; + QStringList* yy95; + SqliteForeignKey::Condition::Reaction* yy104; + ParserStubInsertOrReplace* yy105; + SqliteIndexedColumn* yy108; + ParserOtherSourceList* yy131; + SqliteCreateTrigger::Time* yy132; + int* yy146; + ParserOrderByList* yy163; + ParserExprNestedList* yy166; + ParserFkConditionList* yy184; + ParserIndexedBy* yy192; + ParserStubAlias* yy200; + SqliteSelect::Core::SingleSource* yy201; + ParserCreateTableColumnList* yy202; + ParserIndexedColumnList* yy223; + SqliteCreateTable::Column* yy227; + SqliteQuery* yy283; + SqliteSelect::Core::JoinConstraint* yy295; + SqliteSelect::Core::JoinOp* yy301; + SqliteCreateTable::Column::Constraint* yy304; + SqliteSortOrder* yy309; + SqliteSelect::Core* yy310; + SqliteWith* yy321; + ParserDeferSubClause* yy329; + ParserCreateTableConstraintList* yy333; + SqliteConflictAlgo* yy338; + SqliteForeignKey::Condition* yy347; + SqliteExpr* yy352; + ParserFullName* yy360; + ParserResultColumnList* yy373; + SqliteInitially* yy392; + QString* yy399; + ParserStubTransDetails* yy404; + SqliteCreateTable::Constraint* yy406; + ParserStubExplain* yy411; + ParserQueryList* yy430; + bool* yy451; + SqliteSelect::CompoundOperator* yy462; + QVariant* yy469; + SqliteSelect* yy473; + SqliteLimit* yy484; + SqliteSelect::Core::JoinSource* yy511; + SqliteExpr::LikeOp* yy520; + ParserSetValueList* yy521; + SqliteColumnType* yy537; + ParserExprList* yy551; + SqliteCreateTrigger::Event* yy552; + SqliteUpsert* yy560; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 @@ -170,8 +172,8 @@ typedef union { #define sqlite3_parseARG_PDECL ,ParserContext* parserContext #define sqlite3_parseARG_FETCH ParserContext* parserContext = yypParser->parserContext #define sqlite3_parseARG_STORE yypParser->parserContext = parserContext -#define YYNSTATE 725 -#define YYNRULE 424 +#define YYNSTATE 754 +#define YYNRULE 431 #define YYFALLBACK 1 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) @@ -243,629 +245,658 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ -#define YY_ACTTAB_COUNT (2271) +#define YY_ACTTAB_COUNT (2384) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 432, 565, 566, 717, 50, 50, 49, 49, 49, 48, - /* 10 */ 215, 420, 53, 53, 53, 53, 28, 51, 51, 51, - /* 20 */ 51, 50, 50, 49, 49, 49, 48, 215, 717, 1026, - /* 30 */ 1026, 336, 666, 665, 53, 53, 53, 53, 425, 51, - /* 40 */ 51, 51, 51, 50, 50, 49, 49, 49, 48, 215, - /* 50 */ 722, 81, 205, 204, 203, 672, 592, 592, 1026, 1026, - /* 60 */ 41, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, - /* 70 */ 1026, 1026, 639, 1026, 1026, 1026, 1026, 38, 39, 1026, - /* 80 */ 1026, 1026, 1026, 1026, 40, 432, 529, 285, 717, 56, - /* 90 */ 108, 684, 3, 717, 668, 301, 420, 678, 661, 417, - /* 100 */ 716, 67, 688, 430, 552, 715, 714, 691, 130, 331, - /* 110 */ 60, 377, 374, 373, 678, 690, 689, 688, 674, 507, - /* 120 */ 61, 216, 717, 425, 49, 49, 49, 48, 215, 372, - /* 130 */ 715, 714, 212, 131, 1143, 1143, 242, 629, 246, 674, - /* 140 */ 672, 421, 685, 48, 215, 41, 508, 510, 678, 509, - /* 150 */ 9, 678, 33, 669, 144, 95, 281, 380, 276, 379, - /* 160 */ 132, 674, 38, 39, 609, 229, 228, 7, 356, 40, - /* 170 */ 885, 717, 403, 717, 274, 484, 685, 3, 885, 529, - /* 180 */ 248, 610, 678, 68, 417, 885, 411, 688, 430, 209, - /* 190 */ 715, 714, 691, 684, 457, 715, 714, 717, 209, 678, - /* 200 */ 690, 689, 688, 663, 662, 432, 453, 459, 460, 458, - /* 210 */ 306, 486, 507, 61, 717, 885, 420, 885, 885, 492, - /* 220 */ 725, 716, 320, 885, 715, 714, 461, 462, 885, 885, - /* 230 */ 885, 885, 885, 678, 297, 9, 678, 772, 669, 508, - /* 240 */ 510, 687, 509, 425, 717, 339, 244, 51, 51, 51, - /* 250 */ 51, 50, 50, 49, 49, 49, 48, 215, 543, 570, - /* 260 */ 672, 357, 713, 283, 688, 41, 544, 711, 448, 691, - /* 270 */ 445, 577, 712, 715, 714, 715, 714, 690, 689, 688, - /* 280 */ 492, 576, 38, 39, 449, 448, 512, 445, 487, 40, - /* 290 */ 947, 463, 661, 389, 497, 603, 602, 3, 947, 715, - /* 300 */ 714, 230, 678, 684, 417, 947, 13, 688, 430, 723, - /* 310 */ 17, 617, 691, 448, 513, 445, 715, 714, 81, 678, - /* 320 */ 690, 689, 688, 307, 1135, 679, 460, 654, 618, 360, - /* 330 */ 774, 1135, 1028, 1028, 89, 947, 1, 947, 947, 716, - /* 340 */ 110, 595, 716, 617, 461, 342, 715, 714, 947, 947, - /* 350 */ 947, 947, 1080, 678, 692, 9, 678, 497, 669, 693, - /* 360 */ 717, 54, 55, 427, 295, 1028, 1028, 681, 681, 52, - /* 370 */ 52, 53, 53, 53, 53, 717, 51, 51, 51, 51, - /* 380 */ 50, 50, 49, 49, 49, 48, 215, 432, 496, 382, - /* 390 */ 717, 553, 347, 254, 363, 258, 298, 139, 420, 218, - /* 400 */ 539, 69, 286, 287, 716, 684, 143, 231, 390, 343, - /* 410 */ 661, 54, 55, 427, 295, 716, 716, 681, 681, 52, - /* 420 */ 52, 53, 53, 53, 53, 425, 51, 51, 51, 51, - /* 430 */ 50, 50, 49, 49, 49, 48, 215, 684, 954, 608, - /* 440 */ 628, 692, 672, 663, 662, 585, 693, 41, 429, 207, - /* 450 */ 601, 491, 388, 954, 130, 652, 499, 377, 374, 373, - /* 460 */ 500, 431, 715, 714, 38, 39, 651, 199, 198, 673, - /* 470 */ 186, 40, 932, 699, 685, 372, 717, 715, 714, 3, - /* 480 */ 932, 351, 57, 653, 678, 616, 417, 932, 135, 688, - /* 490 */ 430, 59, 688, 157, 691, 717, 680, 691, 340, 1046, - /* 500 */ 954, 678, 690, 689, 688, 690, 689, 688, 685, 419, - /* 510 */ 666, 665, 724, 2, 1028, 1028, 636, 932, 208, 932, - /* 520 */ 932, 43, 386, 141, 294, 615, 611, 264, 284, 267, - /* 530 */ 932, 139, 932, 932, 122, 678, 400, 9, 678, 684, - /* 540 */ 669, 716, 142, 54, 55, 427, 295, 1028, 1028, 681, - /* 550 */ 681, 52, 52, 53, 53, 53, 53, 339, 51, 51, - /* 560 */ 51, 51, 50, 50, 49, 49, 49, 48, 215, 652, - /* 570 */ 91, 299, 483, 483, 628, 717, 661, 717, 715, 714, - /* 580 */ 651, 18, 717, 605, 717, 37, 677, 399, 311, 717, - /* 590 */ 34, 535, 535, 1028, 1028, 427, 295, 715, 714, 681, - /* 600 */ 681, 52, 52, 53, 53, 53, 53, 234, 51, 51, - /* 610 */ 51, 51, 50, 50, 49, 49, 49, 48, 215, 1027, - /* 620 */ 1027, 723, 54, 55, 427, 295, 1028, 1028, 681, 681, - /* 630 */ 52, 52, 53, 53, 53, 53, 42, 51, 51, 51, - /* 640 */ 51, 50, 50, 49, 49, 49, 48, 215, 1027, 1027, - /* 650 */ 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, - /* 660 */ 1027, 1027, 717, 1027, 1027, 1027, 1027, 1027, 1027, 1027, - /* 670 */ 1027, 1027, 1027, 1027, 1028, 1028, 718, 715, 714, 715, - /* 680 */ 714, 454, 324, 201, 715, 714, 715, 714, 321, 695, - /* 690 */ 315, 715, 714, 658, 554, 214, 676, 46, 568, 32, - /* 700 */ 81, 88, 675, 54, 55, 427, 295, 1028, 1028, 681, - /* 710 */ 681, 52, 52, 53, 53, 53, 53, 1095, 51, 51, - /* 720 */ 51, 51, 50, 50, 49, 49, 49, 48, 215, 54, - /* 730 */ 55, 427, 295, 667, 423, 681, 681, 52, 52, 53, - /* 740 */ 53, 53, 53, 454, 51, 51, 51, 51, 50, 50, - /* 750 */ 49, 49, 49, 48, 215, 358, 955, 656, 643, 1150, - /* 760 */ 154, 436, 2, 487, 715, 714, 350, 54, 55, 427, - /* 770 */ 295, 955, 484, 681, 681, 52, 52, 53, 53, 53, - /* 780 */ 53, 160, 51, 51, 51, 51, 50, 50, 49, 49, - /* 790 */ 49, 48, 215, 600, 1095, 22, 717, 280, 307, 1134, - /* 800 */ 34, 717, 501, 502, 353, 629, 1134, 306, 485, 697, - /* 810 */ 268, 717, 229, 228, 337, 279, 717, 558, 955, 54, - /* 820 */ 55, 427, 295, 716, 717, 681, 681, 52, 52, 53, - /* 830 */ 53, 53, 53, 655, 51, 51, 51, 51, 50, 50, - /* 840 */ 49, 49, 49, 48, 215, 432, 1109, 81, 717, 225, - /* 850 */ 663, 662, 54, 55, 427, 295, 420, 153, 681, 681, - /* 860 */ 52, 52, 53, 53, 53, 53, 641, 51, 51, 51, - /* 870 */ 51, 50, 50, 49, 49, 49, 48, 215, 586, 89, - /* 880 */ 717, 231, 390, 425, 15, 717, 694, 413, 13, 895, - /* 890 */ 721, 207, 601, 617, 388, 435, 81, 574, 715, 714, - /* 900 */ 672, 272, 553, 715, 714, 41, 529, 537, 89, 14, - /* 910 */ 618, 698, 69, 715, 714, 716, 13, 209, 715, 714, - /* 920 */ 359, 617, 38, 39, 159, 617, 715, 714, 645, 40, - /* 930 */ 1143, 1143, 717, 345, 222, 674, 540, 3, 618, 469, - /* 940 */ 61, 285, 678, 625, 417, 473, 716, 688, 430, 45, - /* 950 */ 715, 714, 691, 617, 716, 416, 674, 402, 581, 678, - /* 960 */ 690, 689, 688, 429, 901, 901, 468, 467, 284, 466, - /* 970 */ 629, 81, 706, 633, 495, 580, 431, 526, 674, 1143, - /* 980 */ 1143, 716, 715, 714, 673, 92, 716, 715, 714, 91, - /* 990 */ 473, 401, 438, 678, 526, 9, 678, 370, 669, 409, - /* 1000 */ 54, 55, 427, 295, 89, 505, 681, 681, 52, 52, - /* 1010 */ 53, 53, 53, 53, 620, 51, 51, 51, 51, 50, - /* 1020 */ 50, 49, 49, 49, 48, 215, 717, 638, 311, 717, - /* 1030 */ 406, 658, 418, 214, 715, 714, 90, 642, 131, 334, - /* 1040 */ 415, 644, 54, 55, 427, 295, 451, 640, 681, 681, - /* 1050 */ 52, 52, 53, 53, 53, 53, 158, 51, 51, 51, - /* 1060 */ 51, 50, 50, 49, 49, 49, 48, 215, 369, 54, - /* 1070 */ 55, 427, 295, 12, 451, 681, 681, 52, 52, 53, - /* 1080 */ 53, 53, 53, 633, 51, 51, 51, 51, 50, 50, - /* 1090 */ 49, 49, 49, 48, 215, 36, 716, 8, 209, 54, - /* 1100 */ 55, 427, 295, 34, 589, 681, 681, 52, 52, 53, - /* 1110 */ 53, 53, 53, 704, 51, 51, 51, 51, 50, 50, - /* 1120 */ 49, 49, 49, 48, 215, 87, 138, 320, 715, 714, - /* 1130 */ 412, 715, 714, 274, 572, 54, 55, 427, 295, 30, - /* 1140 */ 624, 681, 681, 52, 52, 53, 53, 53, 53, 326, - /* 1150 */ 51, 51, 51, 51, 50, 50, 49, 49, 49, 48, - /* 1160 */ 215, 408, 717, 137, 91, 54, 55, 427, 295, 614, - /* 1170 */ 271, 681, 681, 52, 52, 53, 53, 53, 53, 465, - /* 1180 */ 51, 51, 51, 51, 50, 50, 49, 49, 49, 48, - /* 1190 */ 215, 136, 716, 538, 612, 91, 99, 54, 55, 427, - /* 1200 */ 295, 23, 607, 681, 681, 52, 52, 53, 53, 53, - /* 1210 */ 53, 395, 51, 51, 51, 51, 50, 50, 49, 49, - /* 1220 */ 49, 48, 215, 533, 1110, 516, 717, 91, 54, 55, - /* 1230 */ 427, 295, 141, 393, 681, 681, 52, 52, 53, 53, - /* 1240 */ 53, 53, 5, 51, 51, 51, 51, 50, 50, 49, - /* 1250 */ 49, 49, 48, 215, 717, 1108, 606, 91, 717, 476, - /* 1260 */ 54, 55, 427, 295, 715, 714, 681, 681, 52, 52, - /* 1270 */ 53, 53, 53, 53, 684, 51, 51, 51, 51, 50, - /* 1280 */ 50, 49, 49, 49, 48, 215, 684, 54, 58, 427, - /* 1290 */ 295, 476, 717, 681, 681, 52, 52, 53, 53, 53, - /* 1300 */ 53, 633, 51, 51, 51, 51, 50, 50, 49, 49, - /* 1310 */ 49, 48, 215, 432, 716, 251, 518, 604, 1035, 11, - /* 1320 */ 107, 629, 36, 531, 420, 55, 427, 295, 715, 714, - /* 1330 */ 681, 681, 52, 52, 53, 53, 53, 53, 224, 51, - /* 1340 */ 51, 51, 51, 50, 50, 49, 49, 49, 48, 215, - /* 1350 */ 91, 425, 717, 583, 531, 582, 715, 714, 429, 20, - /* 1360 */ 715, 714, 429, 684, 429, 619, 384, 352, 672, 562, - /* 1370 */ 387, 431, 623, 41, 489, 431, 684, 431, 657, 673, - /* 1380 */ 186, 308, 717, 673, 186, 673, 186, 622, 684, 470, - /* 1390 */ 38, 39, 599, 597, 715, 714, 432, 40, 719, 683, - /* 1400 */ 91, 830, 634, 596, 91, 3, 571, 420, 541, 591, - /* 1410 */ 678, 716, 417, 391, 385, 688, 430, 332, 707, 333, - /* 1420 */ 691, 525, 429, 582, 717, 65, 429, 678, 690, 689, - /* 1430 */ 688, 716, 316, 717, 425, 431, 316, 564, 316, 431, - /* 1440 */ 717, 590, 376, 673, 186, 64, 429, 673, 186, 429, - /* 1450 */ 273, 672, 19, 470, 715, 714, 41, 371, 378, 431, - /* 1460 */ 684, 678, 431, 9, 678, 684, 669, 673, 186, 563, - /* 1470 */ 673, 92, 717, 38, 39, 63, 648, 391, 383, 432, - /* 1480 */ 40, 391, 392, 129, 715, 714, 717, 279, 3, 270, - /* 1490 */ 420, 367, 613, 678, 705, 417, 316, 534, 688, 430, - /* 1500 */ 316, 404, 4, 691, 717, 553, 717, 716, 156, 284, - /* 1510 */ 678, 690, 689, 688, 441, 69, 325, 425, 716, 630, - /* 1520 */ 316, 717, 716, 642, 125, 79, 715, 714, 703, 27, - /* 1530 */ 26, 85, 517, 77, 672, 715, 714, 520, 447, 41, - /* 1540 */ 717, 716, 715, 714, 678, 549, 9, 678, 717, 669, - /* 1550 */ 511, 329, 700, 506, 520, 354, 38, 39, 504, 702, - /* 1560 */ 83, 432, 684, 40, 265, 716, 447, 286, 266, 226, - /* 1570 */ 141, 3, 420, 556, 715, 714, 678, 716, 417, 696, - /* 1580 */ 716, 688, 430, 515, 686, 422, 691, 717, 715, 714, - /* 1590 */ 498, 429, 716, 678, 690, 689, 688, 716, 716, 425, - /* 1600 */ 515, 480, 335, 439, 431, 253, 715, 714, 715, 714, - /* 1610 */ 119, 479, 673, 194, 250, 260, 672, 717, 480, 220, - /* 1620 */ 439, 41, 717, 715, 714, 10, 152, 678, 716, 9, - /* 1630 */ 678, 161, 669, 1036, 286, 594, 456, 455, 38, 39, - /* 1640 */ 72, 111, 715, 714, 432, 40, 635, 716, 646, 429, - /* 1650 */ 715, 714, 338, 3, 1038, 420, 437, 209, 678, 716, - /* 1660 */ 417, 202, 431, 688, 430, 642, 429, 96, 691, 221, - /* 1670 */ 673, 181, 631, 717, 223, 678, 690, 689, 688, 431, - /* 1680 */ 717, 429, 425, 206, 86, 716, 717, 673, 185, 715, - /* 1690 */ 714, 319, 626, 257, 431, 429, 522, 219, 720, 672, - /* 1700 */ 530, 559, 673, 189, 41, 716, 716, 318, 431, 678, - /* 1710 */ 710, 9, 678, 717, 669, 646, 673, 187, 490, 715, - /* 1720 */ 714, 38, 39, 642, 715, 714, 432, 150, 40, 134, - /* 1730 */ 709, 542, 429, 717, 149, 429, 3, 420, 708, 286, - /* 1740 */ 642, 678, 716, 417, 434, 431, 688, 430, 431, 286, - /* 1750 */ 429, 691, 716, 673, 195, 642, 673, 193, 678, 690, - /* 1760 */ 689, 688, 716, 431, 425, 398, 256, 621, 368, 642, - /* 1770 */ 255, 673, 196, 147, 328, 715, 714, 429, 716, 716, - /* 1780 */ 716, 672, 715, 714, 327, 82, 41, 433, 715, 714, - /* 1790 */ 431, 16, 678, 701, 9, 678, 598, 669, 673, 200, - /* 1800 */ 503, 532, 145, 38, 39, 215, 642, 232, 432, 642, - /* 1810 */ 40, 47, 671, 247, 31, 715, 714, 482, 3, 420, - /* 1820 */ 646, 275, 475, 678, 642, 417, 716, 528, 715, 430, - /* 1830 */ 646, 569, 429, 691, 716, 715, 714, 550, 231, 291, - /* 1840 */ 678, 690, 689, 688, 716, 431, 425, 524, 245, 18, - /* 1850 */ 716, 642, 478, 673, 233, 98, 290, 239, 243, 217, - /* 1860 */ 429, 716, 474, 672, 717, 241, 35, 405, 238, 471, - /* 1870 */ 303, 716, 289, 431, 678, 288, 9, 678, 716, 669, - /* 1880 */ 235, 673, 296, 670, 322, 38, 39, 414, 102, 44, - /* 1890 */ 717, 300, 40, 716, 407, 302, 148, 66, 227, 151, - /* 1900 */ 3, 213, 81, 269, 97, 678, 642, 417, 410, 140, - /* 1910 */ 688, 430, 717, 262, 429, 691, 716, 361, 109, 348, - /* 1920 */ 394, 390, 678, 690, 689, 688, 716, 431, 584, 429, - /* 1930 */ 716, 429, 716, 429, 642, 673, 192, 593, 133, 304, - /* 1940 */ 717, 146, 431, 381, 431, 579, 431, 429, 277, 429, - /* 1950 */ 673, 184, 673, 172, 673, 163, 678, 578, 9, 678, - /* 1960 */ 431, 669, 431, 330, 429, 575, 715, 714, 673, 171, - /* 1970 */ 673, 183, 717, 574, 717, 573, 429, 431, 317, 310, - /* 1980 */ 548, 555, 443, 547, 546, 673, 188, 429, 642, 431, - /* 1990 */ 545, 309, 715, 714, 536, 716, 128, 673, 314, 428, - /* 2000 */ 431, 80, 127, 642, 519, 642, 429, 642, 673, 313, - /* 2010 */ 366, 429, 716, 341, 715, 714, 717, 106, 429, 431, - /* 2020 */ 211, 642, 261, 642, 431, 472, 493, 673, 312, 126, - /* 2030 */ 717, 431, 673, 170, 355, 429, 282, 25, 642, 673, - /* 2040 */ 93, 429, 715, 714, 124, 527, 429, 263, 431, 716, - /* 2050 */ 642, 429, 252, 78, 431, 105, 673, 169, 249, 431, - /* 2060 */ 716, 642, 673, 168, 431, 716, 429, 673, 166, 429, - /* 2070 */ 84, 716, 673, 165, 715, 714, 715, 714, 717, 431, - /* 2080 */ 642, 717, 431, 429, 123, 642, 444, 673, 182, 429, - /* 2090 */ 673, 164, 642, 240, 236, 364, 431, 717, 121, 464, - /* 2100 */ 429, 717, 431, 477, 673, 190, 716, 716, 717, 642, - /* 2110 */ 673, 191, 442, 431, 429, 642, 155, 429, 715, 714, - /* 2120 */ 642, 673, 174, 717, 429, 642, 514, 431, 429, 237, - /* 2130 */ 431, 429, 715, 714, 429, 673, 173, 431, 673, 175, - /* 2140 */ 642, 431, 716, 642, 431, 673, 178, 431, 429, 673, - /* 2150 */ 94, 349, 673, 177, 429, 673, 176, 642, 104, 120, - /* 2160 */ 494, 431, 103, 642, 429, 346, 118, 431, 344, 673, - /* 2170 */ 180, 117, 76, 75, 642, 673, 179, 431, 647, 116, - /* 2180 */ 715, 714, 74, 715, 714, 673, 167, 115, 642, 73, - /* 2190 */ 114, 642, 481, 643, 323, 113, 397, 24, 642, 715, - /* 2200 */ 714, 452, 642, 715, 714, 642, 21, 450, 642, 431, - /* 2210 */ 715, 714, 101, 100, 446, 112, 62, 673, 70, 440, - /* 2220 */ 162, 292, 642, 664, 552, 715, 714, 570, 642, 632, - /* 2230 */ 426, 650, 637, 627, 278, 197, 375, 660, 642, 259, - /* 2240 */ 362, 523, 6, 305, 682, 659, 649, 557, 210, 521, - /* 2250 */ 29, 365, 424, 293, 71, 567, 561, 560, 488, 588, - /* 2260 */ 587, 81, 551, 1151, 1151, 1151, 1151, 1151, 1151, 1151, - /* 2270 */ 642, + /* 0 */ 457, 54, 54, 53, 53, 53, 52, 225, 277, 746, + /* 10 */ 280, 445, 57, 57, 57, 57, 32, 55, 55, 55, + /* 20 */ 55, 54, 54, 53, 53, 53, 52, 225, 658, 1062, + /* 30 */ 1062, 63, 746, 165, 57, 57, 57, 57, 450, 55, + /* 40 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 50 */ 697, 87, 312, 644, 746, 701, 143, 71, 1062, 1062, + /* 60 */ 45, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 70 */ 1062, 1062, 652, 1062, 1062, 1062, 1062, 42, 43, 1062, + /* 80 */ 1062, 1062, 1062, 1062, 44, 457, 53, 53, 53, 52, + /* 90 */ 225, 746, 3, 643, 639, 717, 445, 707, 751, 442, + /* 100 */ 720, 1, 717, 455, 293, 454, 623, 720, 719, 718, + /* 110 */ 717, 744, 743, 411, 707, 719, 718, 717, 456, 746, + /* 120 */ 454, 683, 292, 450, 15, 485, 702, 196, 96, 645, + /* 130 */ 1179, 1179, 665, 456, 744, 743, 378, 454, 745, 149, + /* 140 */ 701, 702, 196, 486, 487, 45, 646, 98, 707, 537, + /* 150 */ 456, 473, 10, 707, 658, 698, 744, 743, 702, 196, + /* 160 */ 350, 645, 42, 43, 637, 543, 298, 474, 473, 44, + /* 170 */ 914, 721, 931, 931, 722, 424, 407, 3, 914, 745, + /* 180 */ 329, 87, 707, 746, 442, 914, 138, 717, 455, 401, + /* 190 */ 398, 397, 720, 744, 743, 329, 473, 457, 638, 707, + /* 200 */ 719, 718, 717, 724, 914, 454, 139, 396, 445, 488, + /* 210 */ 690, 92, 410, 349, 307, 1116, 219, 914, 456, 914, + /* 220 */ 914, 744, 743, 914, 746, 241, 702, 99, 914, 914, + /* 230 */ 914, 914, 914, 707, 19, 450, 222, 10, 707, 314, + /* 240 */ 698, 55, 55, 55, 55, 54, 54, 53, 53, 53, + /* 250 */ 52, 225, 701, 427, 746, 454, 746, 45, 152, 102, + /* 260 */ 294, 404, 289, 403, 140, 310, 436, 550, 456, 215, + /* 270 */ 214, 213, 431, 296, 42, 43, 702, 196, 287, 746, + /* 280 */ 671, 44, 977, 746, 580, 744, 743, 426, 138, 3, + /* 290 */ 977, 401, 398, 397, 707, 333, 442, 977, 509, 717, + /* 300 */ 455, 593, 594, 557, 720, 413, 668, 631, 630, 396, + /* 310 */ 351, 707, 719, 718, 717, 521, 977, 457, 509, 365, + /* 320 */ 508, 508, 526, 527, 371, 713, 744, 743, 445, 977, + /* 330 */ 329, 977, 977, 319, 511, 636, 532, 65, 613, 226, + /* 340 */ 977, 977, 977, 977, 64, 707, 15, 977, 703, 10, + /* 350 */ 707, 645, 698, 319, 510, 450, 744, 743, 744, 743, + /* 360 */ 209, 208, 524, 533, 535, 746, 525, 534, 646, 703, + /* 370 */ 714, 609, 701, 52, 225, 61, 470, 45, 516, 620, + /* 380 */ 620, 744, 743, 645, 454, 717, 375, 369, 608, 633, + /* 390 */ 720, 703, 408, 470, 42, 43, 38, 456, 719, 718, + /* 400 */ 717, 44, 962, 746, 714, 702, 196, 358, 605, 3, + /* 410 */ 962, 512, 60, 116, 707, 713, 442, 962, 604, 717, + /* 420 */ 455, 470, 538, 801, 720, 742, 98, 713, 1082, 686, + /* 430 */ 740, 707, 719, 718, 717, 741, 962, 485, 328, 424, + /* 440 */ 409, 687, 582, 224, 1064, 1064, 320, 1171, 297, 962, + /* 450 */ 745, 962, 962, 300, 1171, 486, 360, 91, 12, 329, + /* 460 */ 962, 745, 962, 962, 628, 707, 745, 744, 743, 10, + /* 470 */ 707, 38, 698, 58, 59, 452, 308, 1064, 1064, 710, + /* 480 */ 710, 56, 56, 57, 57, 57, 57, 219, 55, 55, + /* 490 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 563, + /* 500 */ 563, 265, 387, 271, 478, 744, 743, 667, 324, 148, + /* 510 */ 581, 242, 414, 549, 803, 311, 377, 713, 245, 567, + /* 520 */ 73, 361, 690, 745, 1064, 1064, 58, 59, 452, 308, + /* 530 */ 119, 47, 710, 710, 56, 56, 57, 57, 57, 57, + /* 540 */ 406, 55, 55, 55, 55, 54, 54, 53, 53, 53, + /* 550 */ 52, 225, 657, 58, 59, 452, 308, 1064, 1064, 710, + /* 560 */ 710, 56, 56, 57, 57, 57, 57, 334, 55, 55, + /* 570 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 681, + /* 580 */ 687, 443, 224, 581, 1186, 162, 461, 2, 240, 239, + /* 590 */ 680, 285, 466, 73, 721, 41, 745, 722, 96, 58, + /* 600 */ 59, 452, 308, 1064, 1064, 710, 710, 56, 56, 57, + /* 610 */ 57, 57, 57, 96, 55, 55, 55, 55, 54, 54, + /* 620 */ 53, 53, 53, 52, 225, 49, 692, 691, 151, 1063, + /* 630 */ 1063, 602, 58, 59, 452, 308, 1064, 1064, 710, 710, + /* 640 */ 56, 56, 57, 57, 57, 57, 368, 55, 55, 55, + /* 650 */ 55, 54, 54, 53, 53, 53, 52, 225, 1063, 1063, + /* 660 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 670 */ 1063, 1063, 746, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 680 */ 1063, 1063, 1063, 1063, 1064, 1064, 452, 308, 692, 691, + /* 690 */ 710, 710, 56, 56, 57, 57, 57, 57, 34, 55, + /* 700 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 710 */ 713, 95, 709, 58, 59, 452, 308, 1064, 1064, 710, + /* 720 */ 710, 56, 56, 57, 57, 57, 57, 708, 55, 55, + /* 730 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 58, + /* 740 */ 59, 452, 308, 746, 218, 710, 710, 56, 56, 57, + /* 750 */ 57, 57, 57, 150, 55, 55, 55, 55, 54, 54, + /* 760 */ 53, 53, 53, 52, 225, 658, 984, 253, 672, 257, + /* 770 */ 512, 50, 706, 36, 744, 743, 58, 59, 452, 308, + /* 780 */ 746, 984, 710, 710, 56, 56, 57, 57, 57, 57, + /* 790 */ 161, 55, 55, 55, 55, 54, 54, 53, 53, 53, + /* 800 */ 52, 225, 6, 985, 148, 320, 1170, 217, 629, 648, + /* 810 */ 412, 259, 713, 1170, 58, 59, 452, 308, 985, 17, + /* 820 */ 710, 710, 56, 56, 57, 57, 57, 57, 984, 55, + /* 830 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 840 */ 498, 986, 299, 394, 16, 744, 743, 657, 1131, 438, + /* 850 */ 96, 58, 59, 452, 308, 745, 986, 710, 710, 56, + /* 860 */ 56, 57, 57, 57, 57, 985, 55, 55, 55, 55, + /* 870 */ 54, 54, 53, 53, 53, 52, 225, 554, 987, 255, + /* 880 */ 337, 211, 744, 743, 383, 498, 658, 354, 695, 694, + /* 890 */ 444, 695, 694, 987, 554, 746, 705, 745, 58, 59, + /* 900 */ 452, 308, 24, 986, 710, 710, 56, 56, 57, 57, + /* 910 */ 57, 57, 112, 55, 55, 55, 55, 54, 54, 53, + /* 920 */ 53, 53, 52, 225, 682, 1131, 58, 59, 452, 308, + /* 930 */ 647, 746, 710, 710, 56, 56, 57, 57, 57, 57, + /* 940 */ 987, 55, 55, 55, 55, 54, 54, 53, 53, 53, + /* 950 */ 52, 225, 457, 1145, 229, 690, 704, 441, 690, 20, + /* 960 */ 571, 598, 46, 445, 58, 59, 452, 308, 572, 139, + /* 970 */ 710, 710, 56, 56, 57, 57, 57, 57, 746, 55, + /* 980 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 990 */ 450, 98, 746, 37, 713, 696, 580, 744, 743, 393, + /* 1000 */ 97, 454, 298, 87, 454, 685, 662, 701, 240, 239, + /* 1010 */ 754, 581, 45, 428, 456, 745, 168, 456, 454, 745, + /* 1020 */ 727, 73, 702, 196, 745, 702, 99, 557, 281, 42, + /* 1030 */ 43, 456, 355, 744, 743, 357, 44, 482, 684, 702, + /* 1040 */ 196, 745, 703, 233, 3, 568, 692, 691, 746, 707, + /* 1050 */ 484, 442, 483, 167, 717, 455, 424, 425, 333, 720, + /* 1060 */ 532, 65, 87, 703, 287, 446, 707, 719, 718, 717, + /* 1070 */ 384, 340, 352, 424, 415, 517, 329, 149, 674, 671, + /* 1080 */ 744, 743, 1179, 1179, 297, 703, 72, 533, 535, 746, + /* 1090 */ 383, 534, 423, 329, 744, 743, 713, 745, 363, 752, + /* 1100 */ 707, 382, 440, 745, 10, 707, 714, 698, 149, 8, + /* 1110 */ 374, 745, 58, 59, 452, 308, 434, 376, 710, 710, + /* 1120 */ 56, 56, 57, 57, 57, 57, 98, 55, 55, 55, + /* 1130 */ 55, 54, 54, 53, 53, 53, 52, 225, 517, 166, + /* 1140 */ 714, 662, 681, 422, 324, 278, 454, 617, 273, 279, + /* 1150 */ 744, 743, 231, 680, 745, 437, 746, 673, 745, 456, + /* 1160 */ 228, 745, 651, 58, 59, 452, 308, 702, 204, 710, + /* 1170 */ 710, 56, 56, 57, 57, 57, 57, 650, 55, 55, + /* 1180 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 98, + /* 1190 */ 546, 744, 743, 58, 59, 452, 308, 149, 600, 710, + /* 1200 */ 710, 56, 56, 57, 57, 57, 57, 344, 55, 55, + /* 1210 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 14, + /* 1220 */ 746, 671, 433, 566, 40, 726, 659, 266, 284, 58, + /* 1230 */ 59, 452, 308, 586, 40, 710, 710, 56, 56, 57, + /* 1240 */ 57, 57, 57, 747, 55, 55, 55, 55, 54, 54, + /* 1250 */ 53, 53, 53, 52, 225, 9, 98, 98, 744, 743, + /* 1260 */ 38, 58, 59, 452, 308, 25, 94, 710, 710, 56, + /* 1270 */ 56, 57, 57, 57, 57, 653, 55, 55, 55, 55, + /* 1280 */ 54, 54, 53, 53, 53, 52, 225, 561, 1146, 262, + /* 1290 */ 713, 58, 59, 452, 308, 267, 40, 710, 710, 56, + /* 1300 */ 56, 57, 57, 57, 57, 147, 55, 55, 55, 55, + /* 1310 */ 54, 54, 53, 53, 53, 52, 225, 522, 1144, 746, + /* 1320 */ 614, 98, 744, 743, 58, 59, 452, 308, 723, 98, + /* 1330 */ 710, 710, 56, 56, 57, 57, 57, 57, 146, 55, + /* 1340 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 1350 */ 670, 58, 62, 452, 308, 357, 746, 710, 710, 56, + /* 1360 */ 56, 57, 57, 57, 57, 454, 55, 55, 55, 55, + /* 1370 */ 54, 54, 53, 53, 53, 52, 225, 457, 456, 611, + /* 1380 */ 746, 610, 522, 106, 148, 746, 702, 196, 445, 59, + /* 1390 */ 452, 308, 713, 746, 710, 710, 56, 56, 57, 57, + /* 1400 */ 57, 57, 219, 55, 55, 55, 55, 54, 54, 53, + /* 1410 */ 53, 53, 52, 225, 592, 450, 559, 514, 297, 752, + /* 1420 */ 429, 744, 743, 750, 321, 490, 145, 657, 460, 299, + /* 1430 */ 454, 745, 701, 144, 859, 402, 635, 45, 745, 557, + /* 1440 */ 329, 569, 745, 456, 87, 640, 591, 559, 746, 753, + /* 1450 */ 2, 702, 99, 479, 42, 43, 669, 418, 744, 743, + /* 1460 */ 457, 44, 748, 746, 353, 416, 746, 735, 746, 3, + /* 1470 */ 599, 445, 494, 65, 707, 745, 442, 746, 237, 717, + /* 1480 */ 455, 746, 744, 743, 720, 15, 924, 744, 743, 5, + /* 1490 */ 645, 707, 719, 718, 717, 744, 743, 338, 450, 493, + /* 1500 */ 492, 736, 746, 491, 746, 671, 299, 646, 219, 217, + /* 1510 */ 629, 675, 412, 634, 745, 701, 553, 479, 610, 745, + /* 1520 */ 45, 13, 645, 1179, 1179, 707, 463, 746, 347, 10, + /* 1530 */ 707, 746, 698, 716, 454, 746, 662, 42, 43, 381, + /* 1540 */ 632, 232, 627, 457, 44, 495, 1071, 456, 662, 745, + /* 1550 */ 744, 743, 3, 283, 445, 702, 191, 707, 625, 442, + /* 1560 */ 501, 745, 717, 455, 728, 744, 743, 720, 744, 743, + /* 1570 */ 744, 743, 115, 662, 707, 719, 718, 717, 624, 744, + /* 1580 */ 743, 450, 619, 744, 743, 746, 745, 734, 675, 235, + /* 1590 */ 746, 476, 501, 618, 286, 472, 590, 732, 701, 548, + /* 1600 */ 745, 540, 343, 45, 744, 743, 744, 743, 707, 671, + /* 1610 */ 745, 495, 10, 707, 342, 698, 548, 22, 540, 476, + /* 1620 */ 42, 43, 448, 472, 505, 457, 658, 44, 69, 744, + /* 1630 */ 743, 454, 464, 744, 743, 3, 445, 744, 743, 370, + /* 1640 */ 707, 505, 442, 87, 456, 717, 455, 242, 414, 464, + /* 1650 */ 720, 454, 702, 195, 454, 400, 68, 707, 719, 718, + /* 1660 */ 717, 454, 21, 450, 456, 299, 395, 456, 746, 67, + /* 1670 */ 236, 729, 702, 199, 456, 702, 197, 530, 745, 663, + /* 1680 */ 701, 725, 702, 205, 745, 45, 137, 744, 743, 391, + /* 1690 */ 292, 707, 744, 743, 745, 10, 707, 577, 698, 1072, + /* 1700 */ 346, 746, 42, 43, 570, 4, 671, 713, 457, 44, + /* 1710 */ 562, 746, 454, 164, 133, 31, 85, 3, 1074, 445, + /* 1720 */ 83, 30, 707, 29, 442, 456, 671, 717, 455, 671, + /* 1730 */ 28, 454, 720, 702, 203, 715, 671, 454, 746, 707, + /* 1740 */ 719, 718, 717, 454, 456, 341, 450, 675, 745, 746, + /* 1750 */ 456, 82, 702, 206, 454, 733, 456, 339, 702, 210, + /* 1760 */ 81, 454, 541, 701, 702, 244, 447, 456, 45, 542, + /* 1770 */ 744, 743, 372, 707, 456, 702, 309, 10, 707, 745, + /* 1780 */ 698, 664, 702, 202, 660, 42, 43, 671, 731, 270, + /* 1790 */ 457, 536, 44, 230, 745, 454, 529, 745, 531, 149, + /* 1800 */ 3, 445, 745, 744, 743, 707, 671, 442, 456, 713, + /* 1810 */ 717, 455, 671, 744, 743, 720, 702, 194, 671, 655, + /* 1820 */ 712, 454, 707, 719, 718, 717, 454, 89, 450, 671, + /* 1830 */ 523, 264, 745, 457, 456, 128, 671, 11, 261, 456, + /* 1840 */ 744, 743, 702, 180, 445, 701, 76, 702, 171, 160, + /* 1850 */ 45, 744, 743, 654, 169, 504, 707, 120, 481, 356, + /* 1860 */ 10, 707, 454, 698, 480, 103, 746, 42, 43, 462, + /* 1870 */ 671, 450, 596, 746, 44, 456, 216, 269, 642, 219, + /* 1880 */ 746, 268, 3, 702, 179, 234, 93, 707, 701, 442, + /* 1890 */ 745, 332, 744, 455, 212, 749, 671, 720, 331, 454, + /* 1900 */ 158, 671, 454, 739, 707, 719, 718, 717, 737, 258, + /* 1910 */ 42, 43, 456, 507, 256, 456, 738, 44, 503, 157, + /* 1920 */ 702, 193, 745, 702, 198, 3, 459, 745, 88, 713, + /* 1930 */ 707, 392, 442, 155, 18, 717, 455, 671, 707, 454, + /* 1940 */ 720, 454, 10, 707, 458, 698, 746, 707, 719, 718, + /* 1950 */ 717, 105, 456, 250, 456, 227, 746, 454, 142, 421, + /* 1960 */ 702, 327, 702, 326, 249, 153, 316, 730, 744, 743, + /* 1970 */ 456, 745, 745, 225, 671, 744, 743, 671, 702, 325, + /* 1980 */ 454, 707, 744, 743, 109, 10, 707, 313, 698, 243, + /* 1990 */ 454, 315, 156, 456, 622, 159, 454, 649, 87, 51, + /* 2000 */ 104, 702, 178, 456, 626, 35, 454, 700, 242, 456, + /* 2010 */ 745, 702, 100, 641, 671, 20, 671, 702, 177, 456, + /* 2020 */ 303, 299, 304, 454, 301, 454, 520, 702, 176, 430, + /* 2030 */ 454, 713, 671, 746, 745, 317, 456, 154, 456, 302, + /* 2040 */ 454, 39, 677, 456, 702, 174, 702, 173, 744, 743, + /* 2050 */ 432, 702, 192, 456, 454, 671, 345, 288, 744, 743, + /* 2060 */ 587, 702, 172, 746, 454, 671, 746, 456, 699, 454, + /* 2070 */ 745, 671, 746, 48, 330, 702, 200, 456, 439, 254, + /* 2080 */ 70, 671, 456, 499, 560, 702, 201, 238, 223, 252, + /* 2090 */ 702, 184, 745, 496, 597, 454, 746, 454, 671, 435, + /* 2100 */ 671, 454, 745, 675, 117, 671, 746, 745, 456, 118, + /* 2110 */ 456, 359, 454, 746, 456, 671, 702, 183, 702, 182, + /* 2120 */ 746, 417, 702, 181, 713, 456, 414, 454, 746, 671, + /* 2130 */ 454, 621, 454, 702, 185, 744, 743, 454, 746, 671, + /* 2140 */ 456, 746, 454, 456, 671, 456, 746, 141, 702, 188, + /* 2150 */ 456, 702, 101, 702, 187, 456, 746, 612, 702, 186, + /* 2160 */ 454, 746, 565, 702, 190, 744, 743, 454, 744, 743, + /* 2170 */ 671, 420, 671, 456, 744, 743, 671, 528, 746, 405, + /* 2180 */ 456, 702, 189, 746, 456, 607, 556, 671, 702, 175, + /* 2190 */ 578, 746, 702, 74, 746, 558, 746, 606, 744, 743, + /* 2200 */ 348, 282, 671, 745, 290, 671, 275, 671, 744, 743, + /* 2210 */ 552, 603, 671, 602, 745, 744, 743, 671, 601, 745, + /* 2220 */ 547, 576, 744, 743, 515, 246, 713, 518, 323, 335, + /* 2230 */ 744, 743, 366, 575, 506, 671, 583, 584, 745, 468, + /* 2240 */ 744, 743, 671, 744, 743, 745, 671, 574, 744, 743, + /* 2250 */ 136, 573, 745, 564, 86, 453, 295, 276, 744, 743, + /* 2260 */ 322, 135, 390, 744, 743, 385, 263, 502, 745, 745, + /* 2270 */ 745, 114, 134, 221, 467, 469, 260, 251, 745, 745, + /* 2280 */ 744, 743, 247, 500, 274, 744, 743, 672, 373, 745, + /* 2290 */ 745, 248, 388, 744, 743, 745, 744, 743, 744, 743, + /* 2300 */ 27, 132, 555, 113, 745, 84, 131, 130, 163, 497, + /* 2310 */ 90, 380, 379, 539, 545, 111, 129, 489, 367, 519, + /* 2320 */ 110, 127, 364, 80, 362, 126, 79, 125, 124, 78, + /* 2330 */ 77, 676, 123, 122, 26, 477, 336, 23, 475, 108, + /* 2340 */ 66, 107, 661, 471, 121, 465, 305, 170, 693, 689, + /* 2350 */ 679, 291, 451, 598, 399, 666, 207, 551, 656, 272, + /* 2360 */ 544, 386, 318, 711, 688, 7, 220, 33, 678, 585, + /* 2370 */ 306, 389, 449, 75, 595, 589, 588, 616, 615, 87, + /* 2380 */ 1187, 579, 1187, 513, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 4, 110, 111, 4, 81, 82, 83, 84, 85, 86, - /* 10 */ 87, 15, 72, 73, 74, 75, 76, 77, 78, 79, - /* 20 */ 80, 81, 82, 83, 84, 85, 86, 87, 4, 33, - /* 30 */ 34, 194, 195, 196, 72, 73, 74, 75, 42, 77, + /* 0 */ 4, 81, 82, 83, 84, 85, 86, 87, 51, 4, + /* 10 */ 53, 15, 72, 73, 74, 75, 76, 77, 78, 79, + /* 20 */ 80, 81, 82, 83, 84, 85, 86, 87, 193, 33, + /* 30 */ 34, 96, 4, 98, 72, 73, 74, 75, 42, 77, /* 40 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - /* 50 */ 89, 55, 124, 125, 126, 59, 33, 34, 62, 63, + /* 50 */ 97, 55, 95, 104, 4, 59, 107, 104, 62, 63, /* 60 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - /* 70 */ 74, 75, 104, 77, 78, 79, 80, 81, 82, 83, - /* 80 */ 84, 85, 86, 87, 88, 4, 185, 177, 4, 66, - /* 90 */ 67, 4, 96, 4, 97, 93, 15, 101, 261, 103, - /* 100 */ 190, 104, 106, 107, 105, 106, 107, 111, 109, 64, - /* 110 */ 142, 112, 113, 114, 118, 119, 120, 121, 5, 218, - /* 120 */ 219, 96, 4, 42, 83, 84, 85, 86, 87, 130, - /* 130 */ 106, 107, 87, 34, 138, 139, 51, 191, 53, 26, - /* 140 */ 59, 28, 118, 86, 87, 64, 245, 246, 152, 248, - /* 150 */ 154, 155, 123, 157, 109, 110, 111, 112, 113, 114, - /* 160 */ 115, 48, 81, 82, 83, 81, 82, 266, 267, 88, - /* 170 */ 89, 4, 143, 4, 129, 61, 152, 96, 97, 185, - /* 180 */ 95, 235, 101, 96, 103, 104, 276, 106, 107, 252, - /* 190 */ 106, 107, 111, 106, 110, 106, 107, 4, 252, 118, - /* 200 */ 119, 120, 121, 119, 120, 4, 269, 123, 177, 125, - /* 210 */ 96, 97, 218, 219, 4, 134, 15, 136, 137, 101, - /* 220 */ 0, 190, 123, 142, 106, 107, 195, 196, 147, 148, - /* 230 */ 149, 150, 151, 152, 97, 154, 155, 99, 157, 245, - /* 240 */ 246, 152, 248, 42, 4, 25, 161, 77, 78, 79, - /* 250 */ 80, 81, 82, 83, 84, 85, 86, 87, 205, 206, - /* 260 */ 59, 267, 19, 104, 106, 64, 213, 24, 101, 111, - /* 270 */ 101, 19, 29, 106, 107, 106, 107, 119, 120, 121, - /* 280 */ 162, 29, 81, 82, 117, 118, 23, 118, 61, 88, - /* 290 */ 89, 260, 261, 134, 101, 136, 137, 96, 97, 106, - /* 300 */ 107, 225, 101, 4, 103, 104, 96, 106, 107, 89, - /* 310 */ 234, 101, 111, 146, 45, 146, 106, 107, 55, 118, - /* 320 */ 119, 120, 121, 96, 97, 23, 177, 97, 118, 177, - /* 330 */ 99, 104, 33, 34, 104, 134, 96, 136, 137, 190, - /* 340 */ 99, 101, 190, 133, 195, 196, 106, 107, 147, 148, - /* 350 */ 149, 150, 89, 152, 135, 154, 155, 164, 157, 140, - /* 360 */ 4, 62, 63, 64, 65, 66, 67, 68, 69, 70, - /* 370 */ 71, 72, 73, 74, 75, 4, 77, 78, 79, 80, - /* 380 */ 81, 82, 83, 84, 85, 86, 87, 4, 50, 83, - /* 390 */ 4, 177, 54, 124, 125, 126, 182, 98, 15, 247, - /* 400 */ 186, 187, 177, 177, 190, 106, 99, 138, 139, 260, - /* 410 */ 261, 62, 63, 64, 65, 190, 190, 68, 69, 70, - /* 420 */ 71, 72, 73, 74, 75, 42, 77, 78, 79, 80, - /* 430 */ 81, 82, 83, 84, 85, 86, 87, 4, 89, 83, - /* 440 */ 141, 135, 59, 119, 120, 59, 140, 64, 177, 220, - /* 450 */ 221, 113, 223, 104, 109, 9, 7, 112, 113, 114, - /* 460 */ 11, 190, 106, 107, 81, 82, 20, 81, 82, 198, - /* 470 */ 199, 88, 89, 102, 118, 130, 4, 106, 107, 96, - /* 480 */ 97, 32, 96, 258, 101, 104, 103, 104, 107, 106, - /* 490 */ 107, 96, 106, 98, 111, 4, 111, 111, 58, 161, - /* 500 */ 151, 118, 119, 120, 121, 119, 120, 121, 152, 194, - /* 510 */ 195, 196, 172, 173, 33, 34, 97, 134, 96, 136, - /* 520 */ 137, 40, 251, 104, 253, 144, 145, 51, 177, 53, - /* 530 */ 147, 98, 149, 150, 104, 152, 185, 154, 155, 106, - /* 540 */ 157, 190, 104, 62, 63, 64, 65, 66, 67, 68, - /* 550 */ 69, 70, 71, 72, 73, 74, 75, 25, 77, 78, - /* 560 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 9, - /* 570 */ 219, 95, 100, 101, 141, 4, 261, 4, 106, 107, - /* 580 */ 20, 151, 4, 97, 4, 104, 97, 236, 237, 4, - /* 590 */ 104, 100, 101, 33, 34, 64, 65, 106, 107, 68, - /* 600 */ 69, 70, 71, 72, 73, 74, 75, 167, 77, 78, - /* 610 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 33, - /* 620 */ 34, 89, 62, 63, 64, 65, 66, 67, 68, 69, - /* 630 */ 70, 71, 72, 73, 74, 75, 96, 77, 78, 79, - /* 640 */ 80, 81, 82, 83, 84, 85, 86, 87, 62, 63, - /* 650 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - /* 660 */ 74, 75, 4, 77, 78, 79, 80, 81, 82, 83, - /* 670 */ 84, 85, 86, 87, 33, 34, 91, 106, 107, 106, - /* 680 */ 107, 101, 272, 273, 106, 107, 106, 107, 179, 116, - /* 690 */ 188, 106, 107, 191, 192, 193, 97, 158, 127, 160, - /* 700 */ 55, 43, 97, 62, 63, 64, 65, 66, 67, 68, - /* 710 */ 69, 70, 71, 72, 73, 74, 75, 12, 77, 78, - /* 720 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 62, - /* 730 */ 63, 64, 65, 97, 156, 68, 69, 70, 71, 72, - /* 740 */ 73, 74, 75, 163, 77, 78, 79, 80, 81, 82, - /* 750 */ 83, 84, 85, 86, 87, 110, 89, 97, 100, 170, - /* 760 */ 171, 172, 173, 61, 106, 107, 257, 62, 63, 64, - /* 770 */ 65, 104, 61, 68, 69, 70, 71, 72, 73, 74, - /* 780 */ 75, 96, 77, 78, 79, 80, 81, 82, 83, 84, - /* 790 */ 85, 86, 87, 97, 89, 38, 4, 111, 96, 97, - /* 800 */ 104, 4, 124, 125, 126, 191, 104, 96, 97, 197, - /* 810 */ 177, 4, 81, 82, 181, 129, 4, 205, 151, 62, - /* 820 */ 63, 64, 65, 190, 4, 68, 69, 70, 71, 72, - /* 830 */ 73, 74, 75, 97, 77, 78, 79, 80, 81, 82, - /* 840 */ 83, 84, 85, 86, 87, 4, 89, 55, 4, 235, - /* 850 */ 119, 120, 62, 63, 64, 65, 15, 104, 68, 69, - /* 860 */ 70, 71, 72, 73, 74, 75, 201, 77, 78, 79, - /* 870 */ 80, 81, 82, 83, 84, 85, 86, 87, 190, 104, - /* 880 */ 4, 138, 139, 42, 71, 4, 198, 98, 96, 97, - /* 890 */ 169, 220, 221, 101, 223, 174, 55, 122, 106, 107, - /* 900 */ 59, 97, 177, 106, 107, 64, 185, 100, 104, 96, - /* 910 */ 118, 186, 187, 106, 107, 190, 96, 252, 106, 107, - /* 920 */ 249, 101, 81, 82, 96, 133, 106, 107, 97, 88, - /* 930 */ 138, 139, 4, 177, 209, 5, 211, 96, 118, 218, - /* 940 */ 219, 177, 101, 146, 103, 101, 190, 106, 107, 159, - /* 950 */ 106, 107, 111, 133, 190, 185, 26, 30, 28, 118, - /* 960 */ 119, 120, 121, 177, 144, 145, 245, 246, 177, 248, - /* 970 */ 191, 55, 91, 177, 162, 45, 190, 101, 48, 138, - /* 980 */ 139, 190, 106, 107, 198, 199, 190, 106, 107, 219, - /* 990 */ 146, 64, 271, 152, 118, 154, 155, 97, 157, 98, - /* 1000 */ 62, 63, 64, 65, 104, 89, 68, 69, 70, 71, - /* 1010 */ 72, 73, 74, 75, 235, 77, 78, 79, 80, 81, - /* 1020 */ 82, 83, 84, 85, 86, 87, 4, 236, 237, 4, - /* 1030 */ 244, 191, 192, 193, 106, 107, 98, 251, 34, 243, - /* 1040 */ 276, 97, 62, 63, 64, 65, 118, 201, 68, 69, - /* 1050 */ 70, 71, 72, 73, 74, 75, 96, 77, 78, 79, - /* 1060 */ 80, 81, 82, 83, 84, 85, 86, 87, 64, 62, - /* 1070 */ 63, 64, 65, 13, 146, 68, 69, 70, 71, 72, - /* 1080 */ 73, 74, 75, 177, 77, 78, 79, 80, 81, 82, - /* 1090 */ 83, 84, 85, 86, 87, 104, 190, 13, 252, 62, - /* 1100 */ 63, 64, 65, 104, 97, 68, 69, 70, 71, 72, - /* 1110 */ 73, 74, 75, 91, 77, 78, 79, 80, 81, 82, - /* 1120 */ 83, 84, 85, 86, 87, 96, 13, 123, 106, 107, - /* 1130 */ 185, 106, 107, 129, 97, 62, 63, 64, 65, 159, - /* 1140 */ 30, 68, 69, 70, 71, 72, 73, 74, 75, 243, - /* 1150 */ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - /* 1160 */ 87, 185, 4, 97, 219, 62, 63, 64, 65, 144, - /* 1170 */ 97, 68, 69, 70, 71, 72, 73, 74, 75, 177, - /* 1180 */ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - /* 1190 */ 87, 97, 190, 185, 144, 219, 99, 62, 63, 64, - /* 1200 */ 65, 98, 83, 68, 69, 70, 71, 72, 73, 74, - /* 1210 */ 75, 99, 77, 78, 79, 80, 81, 82, 83, 84, - /* 1220 */ 85, 86, 87, 185, 89, 97, 4, 219, 62, 63, - /* 1230 */ 64, 65, 104, 104, 68, 69, 70, 71, 72, 73, - /* 1240 */ 74, 75, 96, 77, 78, 79, 80, 81, 82, 83, - /* 1250 */ 84, 85, 86, 87, 4, 89, 97, 219, 4, 101, - /* 1260 */ 62, 63, 64, 65, 106, 107, 68, 69, 70, 71, - /* 1270 */ 72, 73, 74, 75, 4, 77, 78, 79, 80, 81, - /* 1280 */ 82, 83, 84, 85, 86, 87, 4, 62, 63, 64, - /* 1290 */ 65, 133, 4, 68, 69, 70, 71, 72, 73, 74, - /* 1300 */ 75, 177, 77, 78, 79, 80, 81, 82, 83, 84, - /* 1310 */ 85, 86, 87, 4, 190, 97, 185, 135, 158, 96, - /* 1320 */ 17, 191, 104, 101, 15, 63, 64, 65, 106, 107, - /* 1330 */ 68, 69, 70, 71, 72, 73, 74, 75, 38, 77, + /* 70 */ 74, 75, 237, 77, 78, 79, 80, 81, 82, 83, + /* 80 */ 84, 85, 86, 87, 88, 4, 83, 84, 85, 86, + /* 90 */ 87, 4, 96, 144, 145, 106, 15, 101, 89, 103, + /* 100 */ 111, 96, 106, 107, 111, 179, 101, 111, 119, 120, + /* 110 */ 121, 106, 107, 187, 118, 119, 120, 121, 192, 4, + /* 120 */ 179, 97, 129, 42, 96, 179, 200, 201, 104, 101, + /* 130 */ 134, 135, 97, 192, 106, 107, 126, 179, 192, 104, + /* 140 */ 59, 200, 201, 197, 198, 64, 118, 221, 152, 23, + /* 150 */ 192, 101, 156, 157, 193, 159, 106, 107, 200, 201, + /* 160 */ 234, 133, 81, 82, 83, 155, 179, 117, 118, 88, + /* 170 */ 89, 137, 144, 145, 140, 234, 235, 96, 97, 192, + /* 180 */ 254, 55, 101, 4, 103, 104, 109, 106, 107, 112, + /* 190 */ 113, 114, 111, 106, 107, 254, 146, 4, 237, 118, + /* 200 */ 119, 120, 121, 116, 123, 179, 34, 130, 15, 263, + /* 210 */ 264, 96, 254, 64, 256, 89, 255, 136, 192, 138, + /* 220 */ 139, 106, 107, 142, 4, 227, 200, 201, 147, 148, + /* 230 */ 149, 150, 151, 152, 236, 42, 87, 156, 157, 93, + /* 240 */ 159, 77, 78, 79, 80, 81, 82, 83, 84, 85, + /* 250 */ 86, 87, 59, 30, 4, 179, 4, 64, 109, 110, + /* 260 */ 111, 112, 113, 114, 115, 97, 279, 152, 192, 124, + /* 270 */ 125, 126, 246, 104, 81, 82, 200, 201, 129, 4, + /* 280 */ 254, 88, 89, 4, 105, 106, 107, 64, 109, 96, + /* 290 */ 97, 112, 113, 114, 101, 123, 103, 104, 61, 106, + /* 300 */ 107, 110, 111, 187, 111, 136, 104, 138, 139, 130, + /* 310 */ 234, 118, 119, 120, 121, 50, 123, 4, 61, 54, + /* 320 */ 100, 101, 124, 125, 126, 4, 106, 107, 15, 136, + /* 330 */ 254, 138, 139, 96, 97, 83, 220, 221, 59, 96, + /* 340 */ 147, 148, 149, 150, 142, 152, 96, 154, 5, 156, + /* 350 */ 157, 101, 159, 96, 97, 42, 106, 107, 106, 107, + /* 360 */ 81, 82, 7, 247, 248, 4, 11, 251, 118, 26, + /* 370 */ 118, 28, 59, 86, 87, 96, 101, 64, 113, 33, + /* 380 */ 34, 106, 107, 133, 179, 106, 270, 32, 45, 97, + /* 390 */ 111, 48, 187, 118, 81, 82, 104, 192, 119, 120, + /* 400 */ 121, 88, 89, 4, 152, 200, 201, 58, 19, 96, + /* 410 */ 97, 61, 66, 67, 101, 4, 103, 104, 29, 106, + /* 420 */ 107, 146, 45, 99, 111, 19, 221, 106, 163, 108, + /* 430 */ 24, 118, 119, 120, 121, 29, 123, 179, 190, 234, + /* 440 */ 235, 193, 194, 195, 33, 34, 96, 97, 179, 136, + /* 450 */ 192, 138, 139, 179, 104, 197, 198, 96, 96, 254, + /* 460 */ 147, 192, 149, 150, 97, 152, 192, 106, 107, 156, + /* 470 */ 157, 104, 159, 62, 63, 64, 65, 66, 67, 68, + /* 480 */ 69, 70, 71, 72, 73, 74, 75, 255, 77, 78, + /* 490 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 100, + /* 500 */ 101, 124, 125, 126, 272, 106, 107, 238, 239, 98, + /* 510 */ 179, 134, 135, 152, 99, 184, 154, 106, 169, 188, + /* 520 */ 189, 263, 264, 192, 33, 34, 62, 63, 64, 65, + /* 530 */ 99, 40, 68, 69, 70, 71, 72, 73, 74, 75, + /* 540 */ 83, 77, 78, 79, 80, 81, 82, 83, 84, 85, + /* 550 */ 86, 87, 141, 62, 63, 64, 65, 66, 67, 68, + /* 560 */ 69, 70, 71, 72, 73, 74, 75, 181, 77, 78, + /* 570 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 9, + /* 580 */ 193, 194, 195, 179, 172, 173, 174, 175, 81, 82, + /* 590 */ 20, 97, 188, 189, 137, 104, 192, 140, 104, 62, + /* 600 */ 63, 64, 65, 33, 34, 68, 69, 70, 71, 72, + /* 610 */ 73, 74, 75, 104, 77, 78, 79, 80, 81, 82, + /* 620 */ 83, 84, 85, 86, 87, 161, 119, 120, 99, 33, + /* 630 */ 34, 122, 62, 63, 64, 65, 66, 67, 68, 69, + /* 640 */ 70, 71, 72, 73, 74, 75, 260, 77, 78, 79, + /* 650 */ 80, 81, 82, 83, 84, 85, 86, 87, 62, 63, + /* 660 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + /* 670 */ 74, 75, 4, 77, 78, 79, 80, 81, 82, 83, + /* 680 */ 84, 85, 86, 87, 33, 34, 64, 65, 119, 120, + /* 690 */ 68, 69, 70, 71, 72, 73, 74, 75, 161, 77, + /* 700 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 710 */ 4, 43, 111, 62, 63, 64, 65, 66, 67, 68, + /* 720 */ 69, 70, 71, 72, 73, 74, 75, 23, 77, 78, + /* 730 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 62, + /* 740 */ 63, 64, 65, 4, 96, 68, 69, 70, 71, 72, + /* 750 */ 73, 74, 75, 104, 77, 78, 79, 80, 81, 82, + /* 760 */ 83, 84, 85, 86, 87, 193, 89, 51, 100, 53, + /* 770 */ 61, 160, 97, 162, 106, 107, 62, 63, 64, 65, + /* 780 */ 4, 104, 68, 69, 70, 71, 72, 73, 74, 75, + /* 790 */ 104, 77, 78, 79, 80, 81, 82, 83, 84, 85, + /* 800 */ 86, 87, 96, 89, 98, 96, 97, 222, 223, 237, + /* 810 */ 225, 95, 106, 104, 62, 63, 64, 65, 104, 71, + /* 820 */ 68, 69, 70, 71, 72, 73, 74, 75, 151, 77, + /* 830 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 840 */ 101, 89, 179, 97, 96, 106, 107, 141, 12, 98, + /* 850 */ 104, 62, 63, 64, 65, 192, 104, 68, 69, 70, + /* 860 */ 71, 72, 73, 74, 75, 151, 77, 78, 79, 80, + /* 870 */ 81, 82, 83, 84, 85, 86, 87, 101, 89, 163, + /* 880 */ 275, 276, 106, 107, 179, 146, 193, 196, 197, 198, + /* 890 */ 196, 197, 198, 104, 118, 4, 97, 192, 62, 63, + /* 900 */ 64, 65, 38, 151, 68, 69, 70, 71, 72, 73, + /* 910 */ 74, 75, 104, 77, 78, 79, 80, 81, 82, 83, + /* 920 */ 84, 85, 86, 87, 261, 89, 62, 63, 64, 65, + /* 930 */ 237, 4, 68, 69, 70, 71, 72, 73, 74, 75, + /* 940 */ 151, 77, 78, 79, 80, 81, 82, 83, 84, 85, + /* 950 */ 86, 87, 4, 89, 249, 264, 97, 187, 264, 151, + /* 960 */ 207, 208, 96, 15, 62, 63, 64, 65, 215, 34, + /* 970 */ 68, 69, 70, 71, 72, 73, 74, 75, 4, 77, + /* 980 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 990 */ 42, 221, 4, 123, 4, 97, 105, 106, 107, 64, + /* 1000 */ 98, 179, 179, 55, 179, 97, 179, 59, 81, 82, + /* 1010 */ 0, 179, 64, 143, 192, 192, 96, 192, 179, 192, + /* 1020 */ 188, 189, 200, 201, 192, 200, 201, 187, 179, 81, + /* 1030 */ 82, 192, 183, 106, 107, 25, 88, 110, 97, 200, + /* 1040 */ 201, 192, 5, 211, 96, 213, 119, 120, 4, 101, + /* 1050 */ 123, 103, 125, 96, 106, 107, 234, 235, 123, 111, + /* 1060 */ 220, 221, 55, 26, 129, 28, 118, 119, 120, 121, + /* 1070 */ 97, 246, 245, 234, 235, 101, 254, 104, 97, 254, + /* 1080 */ 106, 107, 134, 135, 179, 48, 96, 247, 248, 4, + /* 1090 */ 179, 251, 187, 254, 106, 107, 106, 192, 179, 89, + /* 1100 */ 152, 97, 279, 192, 156, 157, 118, 159, 104, 269, + /* 1110 */ 270, 192, 62, 63, 64, 65, 98, 110, 68, 69, + /* 1120 */ 70, 71, 72, 73, 74, 75, 221, 77, 78, 79, + /* 1130 */ 80, 81, 82, 83, 84, 85, 86, 87, 164, 96, + /* 1140 */ 152, 179, 9, 238, 239, 179, 179, 97, 179, 183, + /* 1150 */ 106, 107, 183, 20, 192, 187, 4, 97, 192, 192, + /* 1160 */ 249, 192, 118, 62, 63, 64, 65, 200, 201, 68, + /* 1170 */ 69, 70, 71, 72, 73, 74, 75, 133, 77, 78, + /* 1180 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 221, + /* 1190 */ 97, 106, 107, 62, 63, 64, 65, 104, 97, 68, + /* 1200 */ 69, 70, 71, 72, 73, 74, 75, 245, 77, 78, + /* 1210 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 13, + /* 1220 */ 4, 254, 187, 187, 104, 199, 141, 97, 97, 62, + /* 1230 */ 63, 64, 65, 207, 104, 68, 69, 70, 71, 72, + /* 1240 */ 73, 74, 75, 91, 77, 78, 79, 80, 81, 82, + /* 1250 */ 83, 84, 85, 86, 87, 13, 221, 221, 106, 107, + /* 1260 */ 104, 62, 63, 64, 65, 98, 96, 68, 69, 70, + /* 1270 */ 71, 72, 73, 74, 75, 30, 77, 78, 79, 80, + /* 1280 */ 81, 82, 83, 84, 85, 86, 87, 187, 89, 97, + /* 1290 */ 4, 62, 63, 64, 65, 187, 104, 68, 69, 70, + /* 1300 */ 71, 72, 73, 74, 75, 13, 77, 78, 79, 80, + /* 1310 */ 81, 82, 83, 84, 85, 86, 87, 101, 89, 4, + /* 1320 */ 192, 221, 106, 107, 62, 63, 64, 65, 200, 221, + /* 1330 */ 68, 69, 70, 71, 72, 73, 74, 75, 97, 77, /* 1340 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - /* 1350 */ 219, 42, 4, 214, 132, 216, 106, 107, 177, 96, - /* 1360 */ 106, 107, 177, 4, 177, 235, 185, 243, 59, 6, - /* 1370 */ 185, 190, 118, 64, 97, 190, 106, 190, 108, 198, - /* 1380 */ 199, 104, 4, 198, 199, 198, 199, 133, 106, 101, - /* 1390 */ 81, 82, 97, 97, 106, 107, 4, 88, 177, 117, - /* 1400 */ 219, 97, 152, 97, 219, 96, 97, 15, 104, 97, - /* 1410 */ 101, 190, 103, 232, 233, 106, 107, 232, 177, 232, - /* 1420 */ 111, 214, 177, 216, 4, 96, 177, 118, 119, 120, - /* 1430 */ 121, 190, 251, 4, 42, 190, 251, 14, 251, 190, - /* 1440 */ 4, 97, 38, 198, 199, 96, 177, 198, 199, 177, - /* 1450 */ 97, 59, 96, 165, 106, 107, 64, 38, 35, 190, - /* 1460 */ 4, 152, 190, 154, 155, 106, 157, 198, 199, 46, - /* 1470 */ 198, 199, 4, 81, 82, 96, 117, 232, 233, 4, - /* 1480 */ 88, 232, 233, 115, 106, 107, 4, 129, 96, 97, - /* 1490 */ 15, 64, 144, 101, 177, 103, 251, 103, 106, 107, - /* 1500 */ 251, 232, 12, 111, 4, 177, 4, 190, 98, 177, - /* 1510 */ 118, 119, 120, 121, 186, 187, 244, 42, 190, 141, - /* 1520 */ 251, 4, 190, 251, 123, 142, 106, 107, 177, 71, - /* 1530 */ 71, 128, 139, 153, 59, 106, 107, 101, 118, 64, - /* 1540 */ 4, 190, 106, 107, 152, 116, 154, 155, 4, 157, - /* 1550 */ 89, 128, 177, 89, 118, 22, 81, 82, 47, 91, - /* 1560 */ 39, 4, 106, 88, 177, 190, 146, 177, 181, 237, - /* 1570 */ 104, 96, 15, 117, 106, 107, 101, 190, 103, 177, - /* 1580 */ 190, 106, 107, 101, 177, 177, 111, 4, 106, 107, - /* 1590 */ 39, 177, 190, 118, 119, 120, 121, 190, 190, 42, - /* 1600 */ 118, 101, 212, 101, 190, 161, 106, 107, 106, 107, - /* 1610 */ 123, 103, 198, 199, 95, 177, 59, 4, 118, 181, - /* 1620 */ 118, 64, 4, 106, 107, 96, 143, 152, 190, 154, - /* 1630 */ 155, 96, 157, 158, 177, 118, 97, 97, 81, 82, - /* 1640 */ 95, 93, 106, 107, 4, 88, 177, 190, 258, 177, - /* 1650 */ 106, 107, 37, 96, 97, 15, 36, 252, 101, 190, - /* 1660 */ 103, 273, 190, 106, 107, 251, 177, 189, 111, 212, - /* 1670 */ 198, 199, 177, 4, 204, 118, 119, 120, 121, 190, - /* 1680 */ 4, 177, 42, 238, 204, 190, 4, 198, 199, 106, - /* 1690 */ 107, 275, 177, 177, 190, 177, 152, 181, 176, 59, - /* 1700 */ 164, 118, 198, 199, 64, 190, 190, 275, 190, 152, - /* 1710 */ 176, 154, 155, 4, 157, 258, 198, 199, 100, 106, - /* 1720 */ 107, 81, 82, 251, 106, 107, 4, 90, 88, 177, - /* 1730 */ 176, 118, 177, 4, 178, 177, 96, 15, 49, 177, - /* 1740 */ 251, 101, 190, 103, 176, 190, 106, 107, 190, 177, - /* 1750 */ 177, 111, 190, 198, 199, 251, 198, 199, 118, 119, - /* 1760 */ 120, 121, 190, 190, 42, 177, 177, 177, 60, 251, - /* 1770 */ 181, 198, 199, 178, 212, 106, 107, 177, 190, 190, - /* 1780 */ 190, 59, 106, 107, 212, 180, 64, 183, 106, 107, - /* 1790 */ 190, 104, 152, 184, 154, 155, 64, 157, 198, 199, - /* 1800 */ 118, 132, 56, 81, 82, 87, 251, 254, 4, 251, - /* 1810 */ 88, 252, 221, 177, 158, 106, 107, 181, 96, 15, - /* 1820 */ 258, 177, 146, 101, 251, 103, 190, 118, 106, 107, - /* 1830 */ 258, 177, 177, 111, 190, 106, 107, 177, 138, 227, - /* 1840 */ 118, 119, 120, 121, 190, 190, 42, 118, 177, 151, - /* 1850 */ 190, 251, 181, 198, 199, 8, 228, 10, 177, 12, - /* 1860 */ 177, 190, 181, 59, 4, 177, 149, 148, 21, 181, - /* 1870 */ 23, 190, 229, 190, 152, 230, 154, 155, 190, 157, - /* 1880 */ 177, 198, 199, 231, 181, 81, 82, 203, 41, 150, - /* 1890 */ 4, 44, 88, 190, 147, 48, 49, 96, 259, 52, - /* 1900 */ 96, 87, 55, 177, 57, 101, 251, 103, 203, 241, - /* 1910 */ 106, 107, 4, 177, 177, 111, 190, 177, 99, 177, - /* 1920 */ 223, 139, 118, 119, 120, 121, 190, 190, 200, 177, - /* 1930 */ 190, 177, 190, 177, 251, 198, 199, 241, 99, 92, - /* 1940 */ 4, 94, 190, 123, 190, 200, 190, 177, 200, 177, - /* 1950 */ 198, 199, 198, 199, 198, 199, 152, 208, 154, 155, - /* 1960 */ 190, 157, 190, 31, 177, 202, 106, 107, 198, 199, - /* 1970 */ 198, 199, 4, 122, 4, 200, 177, 190, 131, 203, - /* 1980 */ 200, 208, 177, 200, 200, 198, 199, 177, 251, 190, - /* 1990 */ 200, 203, 106, 107, 241, 190, 99, 198, 199, 177, - /* 2000 */ 190, 180, 99, 251, 118, 251, 177, 251, 198, 199, - /* 2010 */ 203, 177, 190, 166, 106, 107, 4, 180, 177, 190, - /* 2020 */ 241, 251, 264, 251, 190, 165, 118, 198, 199, 99, - /* 2030 */ 4, 190, 198, 199, 27, 177, 177, 158, 251, 198, - /* 2040 */ 199, 177, 106, 107, 99, 227, 177, 177, 190, 190, - /* 2050 */ 251, 177, 177, 215, 190, 62, 198, 199, 177, 190, - /* 2060 */ 190, 251, 198, 199, 190, 190, 177, 198, 199, 177, - /* 2070 */ 96, 190, 198, 199, 106, 107, 106, 107, 4, 190, - /* 2080 */ 251, 4, 190, 177, 99, 251, 118, 198, 199, 177, - /* 2090 */ 198, 199, 251, 177, 177, 265, 190, 4, 99, 163, - /* 2100 */ 177, 4, 190, 133, 198, 199, 190, 190, 4, 251, - /* 2110 */ 198, 199, 100, 190, 177, 251, 250, 177, 106, 107, - /* 2120 */ 251, 198, 199, 4, 177, 251, 215, 190, 177, 177, - /* 2130 */ 190, 177, 106, 107, 177, 198, 199, 190, 198, 199, - /* 2140 */ 251, 190, 190, 251, 190, 198, 199, 190, 177, 198, - /* 2150 */ 199, 241, 198, 199, 177, 198, 199, 251, 180, 99, - /* 2160 */ 227, 190, 180, 251, 177, 241, 99, 190, 60, 198, - /* 2170 */ 199, 99, 217, 217, 251, 198, 199, 190, 152, 99, - /* 2180 */ 106, 107, 217, 106, 107, 198, 199, 99, 251, 217, - /* 2190 */ 99, 251, 118, 100, 241, 99, 177, 268, 251, 106, - /* 2200 */ 107, 18, 251, 106, 107, 251, 268, 241, 251, 190, - /* 2210 */ 106, 107, 99, 99, 241, 99, 270, 198, 199, 16, - /* 2220 */ 224, 226, 251, 261, 105, 106, 107, 206, 251, 152, - /* 2230 */ 255, 201, 240, 242, 201, 210, 202, 261, 251, 242, - /* 2240 */ 242, 227, 224, 175, 191, 191, 191, 191, 262, 152, - /* 2250 */ 256, 263, 216, 222, 239, 207, 207, 207, 274, 198, - /* 2260 */ 198, 55, 211, 277, 277, 277, 277, 277, 277, 277, - /* 2270 */ 251, + /* 1350 */ 203, 62, 63, 64, 65, 25, 4, 68, 69, 70, + /* 1360 */ 71, 72, 73, 74, 75, 179, 77, 78, 79, 80, + /* 1370 */ 81, 82, 83, 84, 85, 86, 87, 4, 192, 216, + /* 1380 */ 4, 218, 166, 99, 98, 4, 200, 201, 15, 63, + /* 1390 */ 64, 65, 106, 4, 68, 69, 70, 71, 72, 73, + /* 1400 */ 74, 75, 255, 77, 78, 79, 80, 81, 82, 83, + /* 1410 */ 84, 85, 86, 87, 14, 42, 101, 97, 179, 89, + /* 1420 */ 234, 106, 107, 171, 104, 179, 97, 141, 176, 179, + /* 1430 */ 179, 192, 59, 97, 97, 35, 83, 64, 192, 187, + /* 1440 */ 254, 104, 192, 192, 55, 144, 46, 132, 4, 174, + /* 1450 */ 175, 200, 201, 101, 81, 82, 203, 99, 106, 107, + /* 1460 */ 4, 88, 179, 4, 214, 104, 4, 91, 4, 96, + /* 1470 */ 97, 15, 220, 221, 101, 192, 103, 4, 239, 106, + /* 1480 */ 107, 4, 106, 107, 111, 96, 97, 106, 107, 96, + /* 1490 */ 101, 118, 119, 120, 121, 106, 107, 246, 42, 247, + /* 1500 */ 248, 179, 4, 251, 4, 254, 179, 118, 255, 222, + /* 1510 */ 223, 261, 225, 97, 192, 59, 216, 165, 218, 192, + /* 1520 */ 64, 96, 133, 134, 135, 152, 274, 4, 128, 156, + /* 1530 */ 157, 4, 159, 152, 179, 4, 179, 81, 82, 252, + /* 1540 */ 137, 214, 97, 4, 88, 101, 160, 192, 179, 192, + /* 1550 */ 106, 107, 96, 97, 15, 200, 201, 101, 97, 103, + /* 1560 */ 101, 192, 106, 107, 102, 106, 107, 111, 106, 107, + /* 1570 */ 106, 107, 17, 179, 118, 119, 120, 121, 97, 106, + /* 1580 */ 107, 42, 97, 106, 107, 4, 192, 179, 261, 38, + /* 1590 */ 4, 118, 133, 97, 97, 118, 6, 179, 59, 101, + /* 1600 */ 192, 101, 245, 64, 106, 107, 106, 107, 152, 254, + /* 1610 */ 192, 167, 156, 157, 245, 159, 118, 96, 118, 146, + /* 1620 */ 81, 82, 158, 146, 101, 4, 193, 88, 96, 106, + /* 1630 */ 107, 179, 101, 106, 107, 96, 15, 106, 107, 245, + /* 1640 */ 101, 118, 103, 55, 192, 106, 107, 134, 135, 118, + /* 1650 */ 111, 179, 200, 201, 179, 38, 96, 118, 119, 120, + /* 1660 */ 121, 179, 96, 42, 192, 179, 38, 192, 4, 96, + /* 1670 */ 237, 179, 200, 201, 192, 200, 201, 89, 192, 152, + /* 1680 */ 59, 179, 200, 201, 192, 64, 115, 106, 107, 64, + /* 1690 */ 129, 152, 106, 107, 192, 156, 157, 116, 159, 160, + /* 1700 */ 214, 4, 81, 82, 118, 12, 254, 4, 4, 88, + /* 1710 */ 103, 4, 179, 98, 123, 71, 142, 96, 97, 15, + /* 1720 */ 128, 71, 101, 71, 103, 192, 254, 106, 107, 254, + /* 1730 */ 71, 179, 111, 200, 201, 179, 254, 179, 4, 118, + /* 1740 */ 119, 120, 121, 179, 192, 17, 42, 261, 192, 4, + /* 1750 */ 192, 153, 200, 201, 179, 91, 192, 154, 200, 201, + /* 1760 */ 128, 179, 135, 59, 200, 201, 179, 192, 64, 155, + /* 1770 */ 106, 107, 22, 152, 192, 200, 201, 156, 157, 192, + /* 1780 */ 159, 179, 200, 201, 179, 81, 82, 254, 91, 179, + /* 1790 */ 4, 89, 88, 183, 192, 179, 47, 192, 89, 104, + /* 1800 */ 96, 15, 192, 106, 107, 101, 254, 103, 192, 106, + /* 1810 */ 106, 107, 254, 106, 107, 111, 200, 201, 254, 179, + /* 1820 */ 117, 179, 118, 119, 120, 121, 179, 39, 42, 254, + /* 1830 */ 39, 163, 192, 4, 192, 123, 254, 96, 95, 192, + /* 1840 */ 106, 107, 200, 201, 15, 59, 95, 200, 201, 143, + /* 1850 */ 64, 106, 107, 146, 96, 103, 152, 93, 97, 37, + /* 1860 */ 156, 157, 179, 159, 97, 191, 4, 81, 82, 36, + /* 1870 */ 254, 42, 127, 4, 88, 192, 240, 179, 144, 255, + /* 1880 */ 4, 183, 96, 200, 201, 206, 206, 101, 59, 103, + /* 1890 */ 192, 278, 106, 107, 276, 178, 254, 111, 278, 179, + /* 1900 */ 90, 254, 179, 178, 118, 119, 120, 121, 49, 179, + /* 1910 */ 81, 82, 192, 183, 179, 192, 178, 88, 183, 180, + /* 1920 */ 200, 201, 192, 200, 201, 96, 178, 192, 182, 4, + /* 1930 */ 101, 60, 103, 180, 104, 106, 107, 254, 152, 179, + /* 1940 */ 111, 179, 156, 157, 185, 159, 4, 118, 119, 120, + /* 1950 */ 121, 8, 192, 10, 192, 12, 4, 179, 179, 179, + /* 1960 */ 200, 201, 200, 201, 21, 56, 23, 186, 106, 107, + /* 1970 */ 192, 192, 192, 87, 254, 106, 107, 254, 200, 201, + /* 1980 */ 179, 152, 106, 107, 41, 156, 157, 44, 159, 257, + /* 1990 */ 179, 48, 49, 192, 118, 52, 179, 179, 55, 255, + /* 2000 */ 57, 200, 201, 192, 64, 160, 179, 223, 134, 192, + /* 2010 */ 192, 200, 201, 144, 254, 151, 254, 200, 201, 192, + /* 2020 */ 230, 179, 229, 179, 232, 179, 164, 200, 201, 148, + /* 2030 */ 179, 106, 254, 4, 192, 92, 192, 94, 192, 231, + /* 2040 */ 179, 149, 117, 192, 200, 201, 200, 201, 106, 107, + /* 2050 */ 147, 200, 201, 192, 179, 254, 214, 179, 106, 107, + /* 2060 */ 118, 200, 201, 4, 179, 254, 4, 192, 233, 179, + /* 2070 */ 192, 254, 4, 150, 131, 200, 201, 192, 205, 179, + /* 2080 */ 96, 254, 192, 183, 132, 200, 201, 262, 87, 179, + /* 2090 */ 200, 201, 192, 183, 179, 179, 4, 179, 254, 205, + /* 2100 */ 254, 179, 192, 261, 99, 254, 4, 192, 192, 243, + /* 2110 */ 192, 168, 179, 4, 192, 254, 200, 201, 200, 201, + /* 2120 */ 4, 225, 200, 201, 4, 192, 135, 179, 4, 254, + /* 2130 */ 179, 243, 179, 200, 201, 106, 107, 179, 4, 254, + /* 2140 */ 192, 4, 179, 192, 254, 192, 4, 99, 200, 201, + /* 2150 */ 192, 200, 201, 200, 201, 192, 4, 202, 200, 201, + /* 2160 */ 179, 4, 100, 200, 201, 106, 107, 179, 106, 107, + /* 2170 */ 254, 179, 254, 192, 106, 107, 254, 118, 4, 123, + /* 2180 */ 192, 200, 201, 4, 192, 202, 118, 254, 200, 201, + /* 2190 */ 179, 4, 200, 201, 4, 166, 4, 210, 106, 107, + /* 2200 */ 31, 179, 254, 192, 202, 254, 179, 254, 106, 107, + /* 2210 */ 118, 204, 254, 122, 192, 106, 107, 254, 202, 192, + /* 2220 */ 118, 202, 106, 107, 100, 179, 106, 118, 205, 183, + /* 2230 */ 106, 107, 179, 202, 118, 254, 210, 117, 192, 179, + /* 2240 */ 106, 107, 254, 106, 107, 192, 254, 202, 106, 107, + /* 2250 */ 99, 202, 192, 243, 182, 179, 179, 179, 106, 107, + /* 2260 */ 205, 99, 205, 106, 107, 179, 179, 133, 192, 192, + /* 2270 */ 192, 182, 99, 243, 100, 118, 179, 179, 192, 192, + /* 2280 */ 106, 107, 179, 146, 267, 106, 107, 100, 27, 192, + /* 2290 */ 192, 179, 268, 106, 107, 192, 106, 107, 106, 107, + /* 2300 */ 160, 99, 229, 62, 192, 217, 99, 99, 250, 167, + /* 2310 */ 96, 123, 229, 217, 253, 182, 99, 165, 243, 229, + /* 2320 */ 182, 99, 243, 219, 60, 99, 219, 99, 99, 219, + /* 2330 */ 219, 152, 99, 99, 271, 18, 243, 271, 243, 99, + /* 2340 */ 273, 99, 152, 243, 99, 16, 228, 226, 264, 264, + /* 2350 */ 203, 203, 258, 208, 204, 242, 212, 229, 244, 244, + /* 2360 */ 229, 244, 177, 193, 193, 226, 265, 259, 193, 193, + /* 2370 */ 224, 266, 218, 241, 209, 209, 209, 200, 200, 55, + /* 2380 */ 280, 213, 280, 277, }; -#define YY_SHIFT_USE_DFLT (-110) -#define YY_SHIFT_COUNT (435) -#define YY_SHIFT_MIN (-109) -#define YY_SHIFT_MAX (2206) +#define YY_SHIFT_USE_DFLT (-81) +#define YY_SHIFT_COUNT (460) +#define YY_SHIFT_MIN (-80) +#define YY_SHIFT_MAX (2329) static const short yy_shift_ofst[] = { - /* 0 */ 532, -4, 1847, 841, 916, 1557, 1557, 263, 383, 1475, - /* 10 */ 1722, 1640, 1640, 792, 84, 84, -1, 81, 201, 1392, - /* 20 */ 1309, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, - /* 30 */ 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, - /* 40 */ 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, - /* 50 */ 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1804, 2119, - /* 60 */ 820, 269, 2119, 2026, 2026, 2026, 2026, 731, 731, 1270, - /* 70 */ 299, 210, 1502, 1288, 844, 1158, 1500, 1482, 1436, 876, - /* 80 */ 1222, 658, 491, 2077, 2077, 2097, 1004, 2077, 2093, 2026, - /* 90 */ 1270, 743, 560, 560, 757, 386, 45, 167, 169, 356, - /* 100 */ 1420, 928, 580, 472, 118, 930, 193, 930, 240, 1254, - /* 110 */ 24, 2012, 1968, 1936, 1860, 1676, 1970, 2074, 1618, 1908, - /* 120 */ 812, 1886, 1544, 1729, 1709, 1682, 1536, 1669, 807, 1613, - /* 130 */ 1429, 571, 1583, 1517, 1348, 1025, 433, 433, 797, 1378, - /* 140 */ 433, 1250, 578, 89, 573, 371, 338, 1468, 1022, 881, - /* 150 */ 585, 2104, 2104, 2104, 220, 645, 2206, 2206, 2206, 2206, - /* 160 */ 2206, -110, -110, 481, 641, 641, 641, 641, 641, 641, - /* 170 */ 641, 641, 641, 667, 349, 705, 1166, 1135, 1103, 1073, - /* 180 */ 1037, 1007, 980, 938, 790, 1225, 1198, 1262, 531, 531, - /* 190 */ -60, -38, -38, -38, -38, 170, -77, 345, 158, 158, - /* 200 */ 41, 702, 227, 1423, 1423, 1423, 381, 159, 113, 23, - /* 210 */ 678, 449, 1456, 1359, 87, 1282, 306, 243, 430, 927, - /* 220 */ 927, 775, 1304, 99, 446, 927, 29, 446, 324, 324, - /* 230 */ -32, 219, 539, 57, 2203, 2116, 2114, 2113, 2183, 2183, - /* 240 */ 2096, 2091, 2108, 2088, 2108, 2080, 2108, 2072, 2108, 2067, - /* 250 */ 1708, 1698, 2060, 1708, 1993, 1974, 1999, 1985, 1993, 1698, - /* 260 */ 1945, 1879, 2007, 1930, 1708, 1903, 1801, 1708, 1897, 1801, - /* 270 */ 1820, 1820, 1820, 1820, 1932, 1801, 1820, 1851, 1820, 1932, - /* 280 */ 1820, 1820, 1839, 1782, 1819, 1801, 1814, 1801, 1739, 1747, - /* 290 */ 1717, 1719, 1698, 1700, 1656, 1732, 1718, 1746, 1687, 1708, - /* 300 */ 1689, 1689, 1637, 1637, 1637, 1637, -110, -110, -110, -110, - /* 310 */ -110, -110, -110, -110, -110, -110, 586, 85, 711, 114, - /* 320 */ -72, 476, 440, 813, 1277, 1218, 1128, 900, 804, -109, - /* 330 */ 252, 686, 696, 486, 419, 230, -3, 395, 1620, 1615, - /* 340 */ 1548, 1545, 1540, 1539, 1508, 1535, 1483, 1519, 1529, 1487, - /* 350 */ 1444, 1551, 1466, 1521, 1511, 1533, 1464, 1461, 1393, 1380, - /* 360 */ 1459, 1458, 1403, 1383, 1490, 1401, 1410, 1394, 1427, 1358, - /* 370 */ 1368, 1379, 1419, 1356, 1349, 1353, 1329, 1404, 1363, 1263, - /* 380 */ 1300, 1303, 1344, 1312, 1306, 1296, 1160, 1295, 1129, 1182, - /* 390 */ 1223, 999, 1159, 1146, 1129, 1119, 1112, 1097, 1050, 1094, - /* 400 */ 1066, 1110, 1113, 1029, 999, 1084, 991, 1060, 944, 960, - /* 410 */ 901, 753, 831, 828, 789, 753, 736, 685, 660, 636, - /* 420 */ 540, 605, 599, 489, 438, 422, 302, 385, 307, 241, - /* 430 */ 231, 138, 25, 137, 2, -39, + /* 0 */ 1330, -4, 1943, 948, 1588, 1621, 1621, 1621, 126, 313, + /* 10 */ 1539, 1704, 1704, 1704, 1704, 1389, 927, 927, 179, 81, + /* 20 */ 193, 1456, 1373, 1704, 1704, 1704, 1704, 1704, 1704, 1704, + /* 30 */ 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, + /* 40 */ 1786, 1704, 1704, 1704, 1704, 1786, 1704, 1704, 1704, 1704, + /* 50 */ 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, + /* 60 */ 1704, 1704, 1829, 891, 28, 377, 891, 2179, 2179, 2179, + /* 70 */ 2179, 507, 507, 321, 411, 250, 1531, 1444, 739, 1459, + /* 80 */ 1523, 361, 1500, 361, 1498, 776, 1315, 668, 399, 2190, + /* 90 */ 2190, 2190, 2190, 935, 2190, 2187, 2179, 321, 1513, 570, + /* 100 */ 570, 864, 279, 149, 50, 275, 252, 1477, 1473, 1352, + /* 110 */ 220, 974, 115, 343, 1216, 343, 5, 1044, 706, 988, + /* 120 */ 2174, 2157, 2152, 2142, 2137, 2134, 2116, 2124, 2109, 1862, + /* 130 */ 2102, 2092, 2068, 2059, 2029, 1952, 2062, 1586, 1581, 1745, + /* 140 */ 1942, 1876, 1869, 1734, 1286, 1286, 1286, 1707, 1085, 1527, + /* 150 */ 1464, 1381, 87, 1462, 265, 1697, 1664, 1376, 1152, 2192, + /* 160 */ 2192, 2192, 1010, 1007, 2324, 2324, 2324, 2324, 2324, -81, + /* 170 */ -81, 491, 651, 651, 651, 651, 651, 651, 651, 651, + /* 180 */ 651, 789, 752, 714, 677, 836, 1229, 1199, 1167, 1131, + /* 190 */ 1101, 1050, 537, 902, 464, 1289, 1262, 1326, 622, 622, + /* 200 */ -60, -38, -38, -38, -38, 164, -80, 77, -11, -11, + /* 210 */ 3, 709, 350, 1400, 1400, 1400, -51, 169, 1037, 346, + /* 220 */ 198, 355, 2120, 1925, 990, 1703, 457, 406, 808, 808, + /* 230 */ 223, 223, 509, 1337, 172, 1133, 223, 870, 1133, 569, + /* 240 */ 569, 202, 34, 611, 287, 2329, 2245, 2242, 2240, 2317, + /* 250 */ 2317, 2234, 2233, 2264, 2229, 2264, 2228, 2264, 2226, 2264, + /* 260 */ 2222, 1871, 1864, 2217, 1871, 2241, 1864, 2188, 2214, 2208, + /* 270 */ 2207, 2241, 1864, 2202, 2140, 2261, 2173, 1871, 2162, 1984, + /* 280 */ 1871, 2151, 1984, 2056, 2056, 2056, 2056, 2169, 1984, 2056, + /* 290 */ 2091, 2056, 2169, 2056, 2056, 2048, 1991, 2005, 1984, 2001, + /* 300 */ 1984, 1923, 1903, 1892, 1881, 1864, 1874, 1845, 1940, 1886, + /* 310 */ 1909, 1830, 1871, 1859, 1859, 1810, 1810, 1810, 1810, -81, + /* 320 */ -81, -81, -81, -81, -81, -81, -81, -81, -81, 596, + /* 330 */ 716, 257, 237, 145, -43, 349, 748, 1320, 1192, 10, + /* 340 */ 1130, 362, 1093, 1004, 973, 746, 494, 191, 389, -7, + /* 350 */ 367, 292, 35, 24, -47, -65, 1833, 1822, 1764, 1751, + /* 360 */ 1767, 1761, 1752, 1758, 1706, 1743, 1741, 1712, 1668, 1791, + /* 370 */ 1695, 1788, 1749, 1750, 1709, 1702, 1627, 1614, 1632, 1603, + /* 380 */ 1728, 1598, 1659, 1652, 1650, 1644, 1592, 1574, 1693, 1591, + /* 390 */ 1615, 1607, 1625, 1561, 1571, 1573, 1628, 1566, 1560, 1497, + /* 400 */ 1532, 1617, 1590, 1521, 1551, 1555, 1496, 1485, 1481, 1461, + /* 410 */ 1386, 1445, 1361, 1403, 1425, 1416, 1393, 1361, 1353, 1358, + /* 420 */ 1284, 1301, 1336, 1329, 1156, 1241, 1245, 1292, 1170, 1156, + /* 430 */ 1242, 1120, 1206, 1060, 1043, 1018, 686, 981, 957, 751, + /* 440 */ 686, 941, 920, 908, 898, 866, 859, 799, 675, 649, + /* 450 */ 648, 704, 601, 529, 431, 415, 324, 243, 168, 146, + /* 460 */ 9, }; -#define YY_REDUCE_USE_DFLT (-164) -#define YY_REDUCE_COUNT (315) -#define YY_REDUCE_MIN (-163) -#define YY_REDUCE_MAX (2068) +#define YY_REDUCE_USE_DFLT (-166) +#define YY_REDUCE_COUNT (328) +#define YY_REDUCE_MIN (-165) +#define YY_REDUCE_MAX (2185) static const short yy_reduce_ofst[] = { - /* 0 */ 589, 1181, 721, 1185, -99, 1249, 1245, -6, 1269, 271, - /* 10 */ 1272, 1187, 786, 351, 149, 31, 725, 2019, 1987, 1977, - /* 20 */ 1971, 1957, 1954, 1951, 1947, 1940, 1937, 1923, 1912, 1906, - /* 30 */ 1892, 1889, 1874, 1869, 1864, 1858, 1841, 1834, 1829, 1810, - /* 40 */ 1799, 1787, 1772, 1770, 1756, 1754, 1752, 1737, 1683, 1655, - /* 50 */ 1600, 1573, 1558, 1555, 1518, 1504, 1489, 1472, 1414, 214, - /* 60 */ 791, 671, 1328, 1572, 1562, 1457, 1390, 315, -163, 502, - /* 70 */ -54, 1332, 1703, 1688, 1681, 1671, 1636, 1589, 1516, 1438, - /* 80 */ 1387, 764, 633, 1124, 906, 152, 53, 796, -90, 225, - /* 90 */ 840, 229, 846, 665, -63, 688, 612, 1952, 1917, 1822, - /* 100 */ 1590, 1590, 1916, 1881, 1875, 1207, 1870, 1139, 1859, 1590, - /* 110 */ 1822, 1805, 1590, 1590, 1590, 1590, 1590, 1590, 1590, 1742, - /* 120 */ 1590, 1590, 1740, 1590, 1590, 1736, 1590, 1590, 1590, 1726, - /* 130 */ 1660, 1654, 1644, 1590, 1588, 1552, 1130, 779, 1515, 1495, - /* 140 */ 614, 1469, 1408, 1407, 1402, 1375, 509, 1351, 1317, 1241, - /* 150 */ 1221, 1002, 756, 226, 340, 1131, 1038, 1008, 976, 945, - /* 160 */ 770, 410, 76, 1405, 1405, 1405, 1405, 1405, 1405, 1405, - /* 170 */ 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, - /* 180 */ 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, - /* 190 */ 1405, 1405, 1405, 1405, 1405, 1405, 1405, 2051, 2062, 2061, - /* 200 */ 1405, 1984, 1984, 2050, 2049, 2048, 2015, 2031, 2036, 1994, - /* 210 */ 1988, 1986, 2056, 2055, 2054, 2053, 2018, 2068, 2014, 1998, - /* 220 */ 1997, 2034, 2025, 2021, 2033, 1991, 1992, 2030, 1976, 1962, - /* 230 */ 1995, 1996, 1975, 1405, 1946, 1753, 1973, 1966, 1938, 1929, - /* 240 */ 1953, 1753, 1972, 1753, 1965, 1753, 1956, 1753, 1955, 1924, - /* 250 */ 1982, 1933, 1910, 1978, 1911, 1866, 1753, 1753, 1838, 1818, - /* 260 */ 1753, 1830, 1758, 1779, 1837, 1753, 1807, 1821, 1753, 1788, - /* 270 */ 1790, 1784, 1783, 1780, 1773, 1776, 1775, 1763, 1748, 1749, - /* 280 */ 1745, 1728, 1696, 1697, 1668, 1705, 1639, 1684, 1652, 1645, - /* 290 */ 1643, 1628, 1612, 1591, 1553, 1559, 1405, 1609, 1604, 1605, - /* 300 */ 1595, 1556, 1568, 1554, 1534, 1522, 1432, 1416, 1388, 1480, - /* 310 */ 1470, 1445, 1405, 1405, 1405, 1478, + /* 0 */ 412, 205, 1252, -74, 840, 839, 822, -59, 116, 1186, + /* 10 */ -42, 1251, 825, 76, 26, 905, 258, -54, 832, 1992, + /* 20 */ 1988, 1981, 1963, 1958, 1953, 1951, 1948, 1933, 1922, 1918, + /* 30 */ 1916, 1890, 1885, 1875, 1861, 1851, 1846, 1844, 1827, 1817, + /* 40 */ 1811, 1801, 1778, 1762, 1760, 1723, 1720, 1683, 1647, 1642, + /* 50 */ 1616, 1582, 1575, 1564, 1558, 1552, 1533, 1482, 1475, 1472, + /* 60 */ 1452, 1355, 967, 331, 269, 1287, 404, 1842, 1486, 1327, + /* 70 */ 1250, 694, 691, 248, -39, 1239, 2046, 1910, 1900, 1735, + /* 80 */ 1730, 911, 1698, 705, 1610, 969, 966, 823, 849, 1394, + /* 90 */ 1369, 1357, 962, 753, 827, -13, 663, 387, 585, 1253, + /* 100 */ 1147, 232, 1128, 1026, 2112, 2103, 2076, 1818, 1818, 2098, + /* 110 */ 2097, 2087, 2086, 1300, 2078, 1163, 2077, 1818, 1433, 2076, + /* 120 */ 2060, 1818, 1818, 1818, 1818, 1818, 1818, 1818, 2053, 1818, + /* 130 */ 1818, 1818, 1818, 2027, 1818, 1818, 1818, 2022, 2011, 1915, + /* 140 */ 1878, 1818, 1780, 1779, 693, 572, -165, 1640, 1605, 1602, + /* 150 */ 1587, 1556, 1502, 1492, 386, 1418, 1408, 1322, 1283, 1246, + /* 160 */ 919, 274, 1275, 1108, 1100, 1036, 1035, 968, 770, 605, + /* 170 */ -2, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, + /* 180 */ 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, + /* 190 */ 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, + /* 200 */ 1624, 1624, 1624, 1624, 1624, 1624, 1624, 2168, 2178, 2177, + /* 210 */ 1624, 2106, 2106, 2167, 2166, 2165, 2132, 2146, 2154, 2108, + /* 220 */ 2105, 2101, 2176, 2175, 2171, 2170, 2139, 2185, 2131, 2128, + /* 230 */ 2117, 2115, 2150, 2144, 2145, 2148, 2114, 2113, 2147, 2085, + /* 240 */ 2084, 2118, 2121, 2094, 1624, 2067, 2010, 2100, 2095, 2066, + /* 250 */ 2063, 2093, 2010, 2111, 2010, 2110, 2010, 2107, 2010, 2104, + /* 260 */ 2079, 2138, 2090, 2075, 2133, 2096, 2083, 2061, 2058, 2010, + /* 270 */ 2010, 2088, 2073, 2010, 2024, 2017, 2030, 2089, 2010, 2057, + /* 280 */ 2072, 2010, 2055, 2049, 2045, 2031, 2019, 2026, 2023, 2016, + /* 290 */ 2007, 2002, 1987, 1983, 1955, 1888, 1896, 1866, 1894, 1825, + /* 300 */ 1873, 1835, 1792, 1808, 1790, 1793, 1784, 1732, 1744, 1624, + /* 310 */ 1781, 1759, 1746, 1753, 1739, 1748, 1738, 1725, 1717, 1620, + /* 320 */ 1613, 1618, 1680, 1679, 1636, 1624, 1624, 1624, 1674, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 730, 1038, 1143, 1026, 1143, 1026, 1026, 1143, 1026, 1026, - /* 10 */ 1026, 1026, 1026, 901, 1149, 1149, 1149, 1026, 1026, 1026, - /* 20 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, - /* 30 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, - /* 40 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, - /* 50 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 978, 1149, - /* 60 */ 895, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 775, - /* 70 */ 891, 901, 1149, 1149, 1149, 1149, 1149, 963, 950, 941, - /* 80 */ 1149, 1149, 1149, 973, 973, 956, 843, 973, 1149, 1149, - /* 90 */ 1149, 1149, 929, 929, 1028, 1149, 767, 1113, 1118, 976, - /* 100 */ 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 902, - /* 110 */ 976, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, - /* 120 */ 1149, 964, 957, 951, 942, 1149, 1149, 1149, 1149, 1149, - /* 130 */ 1149, 1149, 1149, 1149, 1149, 1149, 891, 891, 1149, 1149, - /* 140 */ 891, 1149, 1149, 977, 1149, 1149, 764, 1149, 1149, 1149, - /* 150 */ 736, 1059, 1149, 1149, 730, 1143, 1143, 1143, 1143, 1143, - /* 160 */ 1143, 1136, 881, 936, 1032, 1033, 907, 946, 1039, 934, - /* 170 */ 938, 937, 1031, 1028, 1028, 1028, 1028, 1028, 1028, 1028, - /* 180 */ 1028, 1028, 1028, 1028, 1028, 1028, 1028, 1001, 1013, 1000, - /* 190 */ 1008, 1009, 1012, 1003, 1017, 1002, 1004, 1149, 1149, 1149, - /* 200 */ 1005, 1149, 1149, 1149, 1149, 1149, 894, 865, 1149, 1149, - /* 210 */ 1149, 1087, 1149, 1149, 777, 1149, 879, 739, 945, 919, - /* 220 */ 919, 810, 834, 799, 929, 919, 909, 929, 1149, 1149, - /* 230 */ 892, 879, 1034, 1006, 1127, 910, 910, 910, 1112, 1112, - /* 240 */ 910, 910, 856, 910, 856, 910, 856, 910, 856, 910, - /* 250 */ 761, 945, 910, 761, 847, 969, 910, 910, 847, 945, - /* 260 */ 910, 1094, 1092, 910, 761, 910, 1047, 761, 910, 1047, - /* 270 */ 845, 845, 845, 845, 826, 1047, 845, 810, 845, 826, - /* 280 */ 845, 845, 910, 1149, 910, 1047, 1053, 1047, 935, 923, - /* 290 */ 933, 930, 945, 1149, 1149, 1028, 1007, 758, 829, 761, - /* 300 */ 747, 747, 735, 735, 735, 735, 1140, 1140, 1136, 812, - /* 310 */ 812, 897, 1016, 1015, 1014, 786, 1040, 1149, 1149, 1149, - /* 320 */ 1149, 1149, 1149, 1061, 1149, 1149, 1149, 1149, 1149, 1149, - /* 330 */ 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 731, - /* 340 */ 1149, 1149, 1149, 1149, 1149, 1130, 1149, 1149, 1149, 1149, - /* 350 */ 1149, 1149, 1091, 1090, 1149, 1149, 1149, 1149, 1149, 1149, - /* 360 */ 1149, 1149, 1149, 1149, 1079, 1149, 1149, 1149, 1149, 1149, - /* 370 */ 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, - /* 380 */ 1149, 1149, 1149, 1149, 1149, 980, 1027, 1149, 868, 870, - /* 390 */ 1149, 1037, 1149, 1149, 869, 1149, 1149, 1149, 1149, 1149, - /* 400 */ 1149, 1149, 1149, 1149, 931, 1149, 924, 1149, 1149, 1149, - /* 410 */ 1149, 1145, 1149, 1149, 1149, 1144, 1149, 1149, 1149, 1149, - /* 420 */ 1149, 1149, 1149, 1149, 1149, 1149, 979, 1029, 993, 1149, - /* 430 */ 992, 991, 770, 1149, 745, 1149, 727, 732, 1129, 1126, - /* 440 */ 1128, 1123, 1124, 1122, 1125, 1121, 1119, 1120, 1117, 1115, - /* 450 */ 1114, 1116, 1111, 1107, 1067, 1065, 1063, 1072, 1071, 1070, - /* 460 */ 1069, 1068, 1064, 1062, 1066, 1060, 960, 948, 939, 863, - /* 470 */ 1106, 1104, 1105, 1058, 1056, 1057, 862, 861, 860, 855, - /* 480 */ 854, 853, 852, 1133, 1142, 1141, 1139, 1138, 1137, 1131, - /* 490 */ 1132, 1045, 1044, 1042, 1041, 1043, 763, 1083, 1086, 1085, - /* 500 */ 1084, 1089, 1088, 1081, 1093, 1098, 1097, 1102, 1101, 1100, - /* 510 */ 1099, 1096, 1078, 968, 967, 965, 970, 962, 961, 966, - /* 520 */ 953, 959, 958, 949, 952, 848, 944, 940, 943, 864, - /* 530 */ 1082, 859, 858, 857, 762, 757, 912, 756, 755, 766, - /* 540 */ 832, 833, 841, 844, 839, 842, 838, 837, 836, 840, - /* 550 */ 835, 831, 769, 768, 776, 825, 803, 801, 800, 804, - /* 560 */ 817, 816, 823, 822, 821, 820, 819, 815, 818, 814, - /* 570 */ 813, 805, 798, 797, 811, 796, 828, 827, 824, 795, - /* 580 */ 851, 850, 849, 846, 794, 793, 792, 791, 790, 789, - /* 590 */ 999, 998, 1030, 1021, 982, 981, 1020, 1018, 1029, 1019, - /* 600 */ 990, 866, 873, 872, 871, 875, 876, 886, 884, 883, - /* 610 */ 882, 918, 917, 916, 915, 914, 913, 906, 904, 900, - /* 620 */ 899, 911, 905, 903, 921, 922, 920, 898, 890, 888, - /* 630 */ 889, 887, 975, 972, 974, 971, 908, 896, 893, 880, - /* 640 */ 926, 925, 1027, 1148, 1146, 1147, 1050, 1052, 1055, 1054, - /* 650 */ 1051, 928, 927, 1049, 1048, 1022, 997, 782, 780, 781, - /* 660 */ 1075, 1074, 1077, 1076, 1073, 784, 783, 779, 778, 995, - /* 670 */ 874, 867, 989, 988, 1103, 1024, 1025, 987, 983, 1023, - /* 680 */ 1011, 1010, 996, 986, 771, 984, 994, 985, 809, 808, - /* 690 */ 807, 806, 878, 877, 788, 802, 787, 785, 765, 760, - /* 700 */ 759, 754, 752, 749, 751, 748, 753, 750, 746, 744, - /* 710 */ 743, 742, 741, 740, 774, 773, 772, 770, 738, 737, - /* 720 */ 734, 733, 729, 728, 726, + /* 0 */ 759, 1074, 1179, 1062, 1179, 1062, 1062, 1062, 1179, 1062, + /* 10 */ 1062, 1062, 1062, 1062, 1062, 931, 1185, 1185, 1185, 1062, + /* 20 */ 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 30 */ 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 40 */ 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 50 */ 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 60 */ 1062, 1062, 1014, 1185, 924, 1185, 1185, 1185, 1185, 1185, + /* 70 */ 1185, 1185, 1185, 804, 920, 931, 1185, 1185, 1185, 1185, + /* 80 */ 1185, 988, 1002, 988, 980, 971, 1185, 1185, 1185, 996, + /* 90 */ 996, 996, 996, 872, 996, 1185, 1185, 1185, 1185, 959, + /* 100 */ 959, 1064, 1185, 796, 1149, 1154, 1012, 1185, 1185, 1185, + /* 110 */ 1185, 1185, 989, 1185, 1185, 1185, 1185, 932, 920, 1012, + /* 120 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 130 */ 1003, 981, 972, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 140 */ 1185, 1185, 1185, 1185, 920, 920, 920, 1185, 1185, 1185, + /* 150 */ 1185, 1013, 1185, 1185, 793, 1185, 1185, 1185, 765, 1095, + /* 160 */ 1185, 1185, 759, 1179, 1179, 1179, 1179, 1179, 1179, 1172, + /* 170 */ 910, 966, 1068, 1069, 937, 976, 1075, 964, 968, 967, + /* 180 */ 1067, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, + /* 190 */ 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1037, 1049, 1036, + /* 200 */ 1044, 1045, 1048, 1039, 1053, 1038, 1040, 1185, 1185, 1185, + /* 210 */ 1041, 1185, 1185, 1185, 1185, 1185, 923, 894, 1185, 1185, + /* 220 */ 1185, 1123, 1185, 1185, 806, 1185, 908, 768, 975, 975, + /* 230 */ 949, 949, 839, 863, 828, 959, 949, 939, 959, 1185, + /* 240 */ 1185, 921, 908, 1070, 1042, 1163, 940, 940, 940, 1148, + /* 250 */ 1148, 940, 940, 885, 940, 885, 940, 885, 940, 885, + /* 260 */ 940, 790, 975, 940, 790, 876, 975, 1008, 992, 940, + /* 270 */ 940, 876, 975, 940, 1130, 1128, 940, 790, 940, 1083, + /* 280 */ 790, 940, 1083, 874, 874, 874, 874, 855, 1083, 874, + /* 290 */ 839, 874, 855, 874, 874, 940, 1185, 940, 1083, 1089, + /* 300 */ 1083, 965, 953, 963, 960, 975, 1185, 1185, 1064, 1043, + /* 310 */ 787, 858, 790, 776, 776, 764, 764, 764, 764, 1176, + /* 320 */ 1176, 1172, 841, 841, 926, 1052, 1051, 1050, 815, 1076, + /* 330 */ 1185, 1185, 1185, 1185, 1185, 1185, 1097, 1185, 1185, 1185, + /* 340 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 350 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 760, 1185, 1185, + /* 360 */ 1185, 1185, 1185, 1166, 1185, 1185, 1185, 1185, 1185, 1185, + /* 370 */ 1127, 1126, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 380 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1115, 1185, + /* 390 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 400 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1016, + /* 410 */ 1063, 1185, 897, 902, 1185, 1185, 1185, 898, 1185, 1185, + /* 420 */ 1185, 1185, 1185, 1185, 1073, 1185, 1185, 1185, 1185, 961, + /* 430 */ 1185, 954, 1185, 1185, 1185, 1185, 1181, 1185, 1185, 1185, + /* 440 */ 1180, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 450 */ 1185, 1015, 1065, 1029, 1185, 1028, 1027, 799, 1185, 774, + /* 460 */ 1185, 756, 761, 1165, 1162, 1164, 1159, 1160, 1158, 1161, + /* 470 */ 1157, 1155, 1156, 1153, 1151, 1150, 1152, 1147, 1143, 1103, + /* 480 */ 1101, 1099, 1108, 1107, 1106, 1105, 1104, 1100, 1098, 1102, + /* 490 */ 1096, 999, 978, 969, 892, 1142, 1140, 1141, 1094, 1092, + /* 500 */ 1093, 891, 890, 889, 884, 883, 882, 881, 1169, 1178, + /* 510 */ 1177, 1175, 1174, 1173, 1167, 1168, 1081, 1080, 1078, 1077, + /* 520 */ 1079, 792, 1119, 1122, 1121, 1120, 1125, 1124, 1117, 1129, + /* 530 */ 1134, 1133, 1138, 1137, 1136, 1135, 1132, 1114, 1007, 1006, + /* 540 */ 1004, 1001, 1011, 1010, 1009, 1000, 993, 1005, 983, 991, + /* 550 */ 990, 979, 982, 877, 974, 970, 973, 893, 1118, 888, + /* 560 */ 887, 886, 791, 786, 942, 785, 784, 795, 861, 862, + /* 570 */ 870, 873, 868, 871, 867, 866, 865, 869, 864, 860, + /* 580 */ 798, 797, 805, 854, 832, 830, 829, 833, 846, 845, + /* 590 */ 852, 851, 850, 849, 848, 844, 847, 843, 842, 834, + /* 600 */ 827, 826, 840, 825, 857, 856, 853, 824, 880, 879, + /* 610 */ 878, 875, 823, 822, 821, 820, 819, 818, 1035, 1034, + /* 620 */ 1066, 1057, 1018, 1017, 1056, 1054, 1065, 1055, 1026, 895, + /* 630 */ 905, 904, 903, 900, 901, 915, 913, 912, 911, 948, + /* 640 */ 947, 946, 945, 944, 943, 936, 934, 929, 928, 941, + /* 650 */ 935, 933, 930, 951, 952, 950, 927, 919, 917, 918, + /* 660 */ 916, 998, 995, 997, 994, 938, 925, 922, 909, 956, + /* 670 */ 955, 1063, 1184, 1182, 1183, 1086, 1088, 1091, 1090, 1087, + /* 680 */ 958, 957, 1085, 1084, 1058, 1033, 811, 809, 810, 1111, + /* 690 */ 1110, 1113, 1112, 1109, 813, 812, 808, 807, 1031, 899, + /* 700 */ 896, 1025, 1024, 1139, 1060, 1061, 1023, 1019, 1059, 1047, + /* 710 */ 1046, 1032, 1022, 800, 1020, 1030, 1021, 838, 837, 836, + /* 720 */ 835, 907, 906, 817, 831, 816, 814, 794, 789, 788, + /* 730 */ 783, 781, 778, 780, 777, 782, 779, 775, 773, 772, + /* 740 */ 771, 770, 769, 803, 802, 801, 799, 767, 766, 763, + /* 750 */ 762, 758, 757, 755, }; /* The next table maps tokens into fallback tokens. If a construct @@ -1123,43 +1154,43 @@ static const char *const yyTokenName[] = { "FLOAT", "BLOB", "AUTOINCR", "ON", "INSERT", "DELETE", "UPDATE", "ID_FK_MATCH", "SET", "DEFERRABLE", "FOREIGN", "DROP", - "ID_VIEW_NEW", "ID_VIEW", "UNION", "ALL", - "EXCEPT", "INTERSECT", "SELECT", "VALUES", + "ID_VIEW_NEW", "ID_VIEW", "SELECT", "VALUES", + "UNION", "ALL", "EXCEPT", "INTERSECT", "DISTINCT", "ID_ALIAS", "FROM", "USING", "JOIN", "ID_JOIN_OPTS", "ID_IDX", "ORDER", "GROUP", "HAVING", "LIMIT", "WHERE", - "ID_COL", "INTO", "CASE", "ID_FN", - "ID_ERR_MSG", "VARIABLE", "WHEN", "THEN", - "ELSE", "INDEX", "ID_IDX_NEW", "ID_PRAGMA", - "ID_TRIG_NEW", "ID_TRIG", "ALTER", "ADD", - "error", "cmd", "input", "cmdlist", - "ecmd", "explain", "cmdx", "transtype", - "trans_opt", "nm", "savepoint_opt", "temp", - "ifnotexists", "fullname", "columnlist", "conslist_opt", - "table_options", "select", "column", "columnid", - "type", "carglist", "id", "ids", - "typetoken", "typename", "signed", "plus_num", - "minus_num", "ccons", "term", "expr", - "onconf", "sortorder", "autoinc", "idxlist_opt", - "refargs", "defer_subclause", "refarg", "refact", - "init_deferred_pred_opt", "conslist", "tconscomma", "tcons", - "idxlist", "defer_subclause_opt", "resolvetype", "orconf", - "raisetype", "ifexists", "select_stmt", "with", - "selectnowith", "oneselect", "multiselect_op", "values", - "distinct", "selcollist", "from", "where_opt", - "groupby_opt", "having_opt", "orderby_opt", "limit_opt", - "nexprlist", "exprlist", "sclp", "as", - "joinsrc", "singlesrc", "seltablist", "joinop", - "joinconstr_opt", "dbnm", "indexed_opt", "inscollist", - "sortlist", "delete_stmt", "update_stmt", "setlist", - "insert_stmt", "insert_cmd", "inscollist_opt", "exprx", - "not_opt", "case_operand", "case_exprlist", "case_else", - "likeop", "uniqueflag", "idxlist_single", "collate", - "nmnum", "number", "trigger_time", "trigger_event", - "foreach_clause", "when_clause", "trigger_cmd_list", "trigger_cmd", - "database_kw_opt", "key_opt", "kwcolumn_opt", "create_vtab", - "vtabarglist", "vtabarg", "vtabargtoken", "anylist", - "wqlist", + "ID_COL", "INTO", "DO", "NOTHING", + "CASE", "ID_FN", "ID_ERR_MSG", "VARIABLE", + "WHEN", "THEN", "ELSE", "INDEX", + "ID_IDX_NEW", "ID_PRAGMA", "ID_TRIG_NEW", "ID_TRIG", + "ALTER", "ADD", "error", "cmd", + "input", "cmdlist", "ecmd", "explain", + "cmdx", "transtype", "trans_opt", "nm", + "savepoint_opt", "temp", "ifnotexists", "fullname", + "columnlist", "conslist_opt", "table_options", "select", + "column", "columnid", "type", "carglist", + "id", "ids", "typetoken", "typename", + "signed", "plus_num", "minus_num", "ccons", + "term", "expr", "onconf", "sortorder", + "autoinc", "idxlist_opt", "refargs", "defer_subclause", + "refarg", "refact", "init_deferred_pred_opt", "conslist", + "tconscomma", "tcons", "idxlist", "defer_subclause_opt", + "resolvetype", "orconf", "raisetype", "ifexists", + "select_stmt", "with", "selectnowith", "oneselect", + "multiselect_op", "values", "distinct", "selcollist", + "from", "where_opt", "groupby_opt", "having_opt", + "orderby_opt", "limit_opt", "nexprlist", "exprlist", + "sclp", "as", "joinsrc", "singlesrc", + "seltablist", "joinop", "joinconstr_opt", "dbnm", + "indexed_opt", "idlist", "sortlist", "delete_stmt", + "update_stmt", "setlist", "idlist_opt", "insert_stmt", + "insert_cmd", "upsert", "exprx", "not_opt", + "case_operand", "case_exprlist", "case_else", "likeop", + "uniqueflag", "idxlist_single", "collate", "nmnum", + "number", "trigger_time", "trigger_event", "foreach_clause", + "when_clause", "trigger_cmd_list", "trigger_cmd", "database_kw_opt", + "key_opt", "kwcolumn_opt", "create_vtab", "vtabarglist", + "vtabarg", "vtabargtoken", "anylist", "wqlist", }; #endif /* NDEBUG */ @@ -1312,13 +1343,13 @@ static const char *const yyRuleName[] = { /* 142 */ "selectnowith ::= selectnowith multiselect_op oneselect", /* 143 */ "selectnowith ::= values", /* 144 */ "selectnowith ::= selectnowith COMMA values", - /* 145 */ "multiselect_op ::= UNION", - /* 146 */ "multiselect_op ::= UNION ALL", - /* 147 */ "multiselect_op ::= EXCEPT", - /* 148 */ "multiselect_op ::= INTERSECT", - /* 149 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 150 */ "values ::= VALUES LP nexprlist RP", - /* 151 */ "values ::= values COMMA LP exprlist RP", + /* 145 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 146 */ "values ::= VALUES LP nexprlist RP", + /* 147 */ "values ::= values COMMA LP exprlist RP", + /* 148 */ "multiselect_op ::= UNION", + /* 149 */ "multiselect_op ::= UNION ALL", + /* 150 */ "multiselect_op ::= EXCEPT", + /* 151 */ "multiselect_op ::= INTERSECT", /* 152 */ "distinct ::= DISTINCT", /* 153 */ "distinct ::= ALL", /* 154 */ "distinct ::=", @@ -1343,254 +1374,261 @@ static const char *const yyRuleName[] = { /* 173 */ "singlesrc ::= nm dbnm as indexed_opt", /* 174 */ "singlesrc ::= LP select RP as", /* 175 */ "singlesrc ::= LP joinsrc RP as", - /* 176 */ "singlesrc ::=", - /* 177 */ "singlesrc ::= nm DOT", - /* 178 */ "singlesrc ::= nm DOT ID_TAB", - /* 179 */ "singlesrc ::= ID_DB|ID_TAB", - /* 180 */ "singlesrc ::= nm DOT ID_VIEW", - /* 181 */ "singlesrc ::= ID_DB|ID_VIEW", - /* 182 */ "joinconstr_opt ::= ON expr", - /* 183 */ "joinconstr_opt ::= USING LP inscollist RP", - /* 184 */ "joinconstr_opt ::=", - /* 185 */ "dbnm ::=", - /* 186 */ "dbnm ::= DOT nm", - /* 187 */ "fullname ::= nm dbnm", - /* 188 */ "joinop ::= COMMA", - /* 189 */ "joinop ::= JOIN", - /* 190 */ "joinop ::= JOIN_KW JOIN", - /* 191 */ "joinop ::= JOIN_KW nm JOIN", - /* 192 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 193 */ "joinop ::= ID_JOIN_OPTS", - /* 194 */ "indexed_opt ::=", - /* 195 */ "indexed_opt ::= INDEXED BY nm", - /* 196 */ "indexed_opt ::= NOT INDEXED", - /* 197 */ "indexed_opt ::= INDEXED BY ID_IDX", - /* 198 */ "orderby_opt ::=", - /* 199 */ "orderby_opt ::= ORDER BY sortlist", - /* 200 */ "sortlist ::= sortlist COMMA expr sortorder", - /* 201 */ "sortlist ::= expr sortorder", - /* 202 */ "sortorder ::= ASC", - /* 203 */ "sortorder ::= DESC", - /* 204 */ "sortorder ::=", - /* 205 */ "groupby_opt ::=", - /* 206 */ "groupby_opt ::= GROUP BY nexprlist", - /* 207 */ "groupby_opt ::= GROUP BY", - /* 208 */ "having_opt ::=", - /* 209 */ "having_opt ::= HAVING expr", - /* 210 */ "limit_opt ::=", - /* 211 */ "limit_opt ::= LIMIT expr", - /* 212 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 213 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 214 */ "cmd ::= delete_stmt", - /* 215 */ "delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt", - /* 216 */ "delete_stmt ::= with DELETE FROM", - /* 217 */ "delete_stmt ::= with DELETE FROM nm DOT", - /* 218 */ "delete_stmt ::= with DELETE FROM nm DOT ID_TAB", - /* 219 */ "delete_stmt ::= with DELETE FROM ID_DB|ID_TAB", - /* 220 */ "where_opt ::=", - /* 221 */ "where_opt ::= WHERE expr", - /* 222 */ "where_opt ::= WHERE", - /* 223 */ "cmd ::= update_stmt", - /* 224 */ "update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", - /* 225 */ "update_stmt ::= with UPDATE orconf", - /* 226 */ "update_stmt ::= with UPDATE orconf nm DOT", - /* 227 */ "update_stmt ::= with UPDATE orconf nm DOT ID_TAB", - /* 228 */ "update_stmt ::= with UPDATE orconf ID_DB|ID_TAB", - /* 229 */ "setlist ::= setlist COMMA nm EQ expr", - /* 230 */ "setlist ::= nm EQ expr", - /* 231 */ "setlist ::=", - /* 232 */ "setlist ::= setlist COMMA", - /* 233 */ "setlist ::= setlist COMMA ID_COL", - /* 234 */ "setlist ::= ID_COL", - /* 235 */ "cmd ::= insert_stmt", - /* 236 */ "insert_stmt ::= with insert_cmd INTO fullname inscollist_opt select", - /* 237 */ "insert_stmt ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES", - /* 238 */ "insert_stmt ::= with insert_cmd INTO", - /* 239 */ "insert_stmt ::= with insert_cmd INTO nm DOT", - /* 240 */ "insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB", - /* 241 */ "insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB", - /* 242 */ "insert_cmd ::= INSERT orconf", - /* 243 */ "insert_cmd ::= REPLACE", - /* 244 */ "inscollist_opt ::=", - /* 245 */ "inscollist_opt ::= LP inscollist RP", - /* 246 */ "inscollist ::= inscollist COMMA nm", - /* 247 */ "inscollist ::= nm", - /* 248 */ "inscollist ::=", - /* 249 */ "inscollist ::= inscollist COMMA ID_COL", - /* 250 */ "inscollist ::= ID_COL", - /* 251 */ "exprx ::= nm DOT", - /* 252 */ "exprx ::= nm DOT nm DOT", - /* 253 */ "exprx ::= expr not_opt BETWEEN expr AND", - /* 254 */ "exprx ::= CASE case_operand case_exprlist case_else", - /* 255 */ "exprx ::= expr not_opt IN LP exprlist", - /* 256 */ "exprx ::= expr not_opt IN ID_DB", - /* 257 */ "exprx ::= expr not_opt IN nm DOT ID_TAB", - /* 258 */ "exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN", - /* 259 */ "exprx ::= nm DOT ID_TAB|ID_COL", - /* 260 */ "exprx ::= nm DOT nm DOT ID_COL", - /* 261 */ "exprx ::= expr COLLATE ID_COLLATE", - /* 262 */ "exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP", - /* 263 */ "exprx ::= term", - /* 264 */ "exprx ::= CTIME_KW", - /* 265 */ "exprx ::= LP nexprlist RP", - /* 266 */ "exprx ::= id", - /* 267 */ "exprx ::= JOIN_KW", - /* 268 */ "exprx ::= nm DOT nm", - /* 269 */ "exprx ::= nm DOT nm DOT nm", - /* 270 */ "exprx ::= VARIABLE", - /* 271 */ "exprx ::= expr COLLATE ids", - /* 272 */ "exprx ::= CAST LP expr AS typetoken RP", - /* 273 */ "exprx ::= ID LP distinct exprlist RP", - /* 274 */ "exprx ::= ID LP STAR RP", - /* 275 */ "exprx ::= expr AND expr", - /* 276 */ "exprx ::= expr OR expr", - /* 277 */ "exprx ::= expr LT|GT|GE|LE expr", - /* 278 */ "exprx ::= expr EQ|NE expr", - /* 279 */ "exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 280 */ "exprx ::= expr PLUS|MINUS expr", - /* 281 */ "exprx ::= expr STAR|SLASH|REM expr", - /* 282 */ "exprx ::= expr CONCAT expr", - /* 283 */ "exprx ::= expr not_opt likeop expr", - /* 284 */ "exprx ::= expr not_opt likeop expr ESCAPE expr", - /* 285 */ "exprx ::= expr ISNULL|NOTNULL", - /* 286 */ "exprx ::= expr NOT NULL", - /* 287 */ "exprx ::= expr IS not_opt expr", - /* 288 */ "exprx ::= NOT expr", - /* 289 */ "exprx ::= BITNOT expr", - /* 290 */ "exprx ::= MINUS expr", - /* 291 */ "exprx ::= PLUS expr", - /* 292 */ "exprx ::= expr not_opt BETWEEN expr AND expr", - /* 293 */ "exprx ::= expr not_opt IN LP exprlist RP", - /* 294 */ "exprx ::= LP select RP", - /* 295 */ "exprx ::= expr not_opt IN LP select RP", - /* 296 */ "exprx ::= expr not_opt IN nm dbnm", - /* 297 */ "exprx ::= EXISTS LP select RP", - /* 298 */ "exprx ::= CASE case_operand case_exprlist case_else END", - /* 299 */ "exprx ::= RAISE LP IGNORE RP", - /* 300 */ "exprx ::= RAISE LP raisetype COMMA nm RP", - /* 301 */ "expr ::=", - /* 302 */ "expr ::= exprx", - /* 303 */ "not_opt ::=", - /* 304 */ "not_opt ::= NOT", - /* 305 */ "likeop ::= LIKE_KW|MATCH", - /* 306 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 307 */ "case_exprlist ::= WHEN expr THEN expr", - /* 308 */ "case_else ::= ELSE expr", - /* 309 */ "case_else ::=", - /* 310 */ "case_operand ::= exprx", - /* 311 */ "case_operand ::=", - /* 312 */ "exprlist ::= nexprlist", - /* 313 */ "exprlist ::=", - /* 314 */ "nexprlist ::= nexprlist COMMA expr", - /* 315 */ "nexprlist ::= exprx", - /* 316 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 317 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB", - /* 318 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW", - /* 319 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW", - /* 320 */ "uniqueflag ::= UNIQUE", - /* 321 */ "uniqueflag ::=", - /* 322 */ "idxlist_opt ::=", - /* 323 */ "idxlist_opt ::= LP idxlist RP", - /* 324 */ "idxlist ::= idxlist COMMA idxlist_single", - /* 325 */ "idxlist ::= idxlist_single", - /* 326 */ "idxlist_single ::= nm collate sortorder", - /* 327 */ "idxlist_single ::= ID_COL", - /* 328 */ "collate ::=", - /* 329 */ "collate ::= COLLATE ids", - /* 330 */ "collate ::= COLLATE ID_COLLATE", - /* 331 */ "cmd ::= DROP INDEX ifexists fullname", - /* 332 */ "cmd ::= DROP INDEX ifexists nm DOT ID_IDX", - /* 333 */ "cmd ::= DROP INDEX ifexists ID_DB|ID_IDX", - /* 334 */ "cmd ::= VACUUM", - /* 335 */ "cmd ::= VACUUM nm", - /* 336 */ "cmd ::= PRAGMA nm dbnm", - /* 337 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 338 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 339 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 340 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 341 */ "cmd ::= PRAGMA nm DOT ID_PRAGMA", - /* 342 */ "cmd ::= PRAGMA ID_DB|ID_PRAGMA", - /* 343 */ "nmnum ::= plus_num", - /* 344 */ "nmnum ::= nm", - /* 345 */ "nmnum ::= ON", - /* 346 */ "nmnum ::= DELETE", - /* 347 */ "nmnum ::= DEFAULT", - /* 348 */ "plus_num ::= PLUS number", - /* 349 */ "plus_num ::= number", - /* 350 */ "minus_num ::= MINUS number", - /* 351 */ "number ::= INTEGER", - /* 352 */ "number ::= FLOAT", - /* 353 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END", - /* 354 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause", - /* 355 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list", - /* 356 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB", - /* 357 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW", - /* 358 */ "cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW", - /* 359 */ "trigger_time ::= BEFORE", - /* 360 */ "trigger_time ::= AFTER", - /* 361 */ "trigger_time ::= INSTEAD OF", - /* 362 */ "trigger_time ::=", - /* 363 */ "trigger_event ::= DELETE", - /* 364 */ "trigger_event ::= INSERT", - /* 365 */ "trigger_event ::= UPDATE", - /* 366 */ "trigger_event ::= UPDATE OF inscollist", - /* 367 */ "foreach_clause ::=", - /* 368 */ "foreach_clause ::= FOR EACH ROW", - /* 369 */ "when_clause ::=", - /* 370 */ "when_clause ::= WHEN expr", - /* 371 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 372 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 373 */ "trigger_cmd_list ::= SEMI", - /* 374 */ "trigger_cmd ::= update_stmt", - /* 375 */ "trigger_cmd ::= insert_stmt", - /* 376 */ "trigger_cmd ::= delete_stmt", - /* 377 */ "trigger_cmd ::= select_stmt", - /* 378 */ "raisetype ::= ROLLBACK|ABORT|FAIL", - /* 379 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 380 */ "cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG", - /* 381 */ "cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG", - /* 382 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 383 */ "cmd ::= DETACH database_kw_opt expr", - /* 384 */ "key_opt ::=", - /* 385 */ "key_opt ::= KEY expr", - /* 386 */ "database_kw_opt ::= DATABASE", - /* 387 */ "database_kw_opt ::=", - /* 388 */ "cmd ::= REINDEX", - /* 389 */ "cmd ::= REINDEX nm dbnm", - /* 390 */ "cmd ::= REINDEX ID_COLLATE", - /* 391 */ "cmd ::= REINDEX nm DOT ID_TAB|ID_IDX", - /* 392 */ "cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB", - /* 393 */ "cmd ::= ANALYZE", - /* 394 */ "cmd ::= ANALYZE nm dbnm", - /* 395 */ "cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX", - /* 396 */ "cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB", - /* 397 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 398 */ "cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column", - /* 399 */ "cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW", - /* 400 */ "cmd ::= ALTER TABLE nm DOT ID_TAB", - /* 401 */ "cmd ::= ALTER TABLE ID_DB|ID_TAB", - /* 402 */ "kwcolumn_opt ::=", - /* 403 */ "kwcolumn_opt ::= COLUMNKW", - /* 404 */ "cmd ::= create_vtab", - /* 405 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 406 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP", - /* 407 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW", - /* 408 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW", - /* 409 */ "vtabarglist ::= vtabarg", - /* 410 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 411 */ "vtabarg ::=", - /* 412 */ "vtabarg ::= vtabarg vtabargtoken", - /* 413 */ "vtabargtoken ::= ANY", - /* 414 */ "vtabargtoken ::= LP anylist RP", - /* 415 */ "anylist ::=", - /* 416 */ "anylist ::= anylist LP anylist RP", - /* 417 */ "anylist ::= anylist ANY", - /* 418 */ "with ::=", - /* 419 */ "with ::= WITH wqlist", - /* 420 */ "with ::= WITH RECURSIVE wqlist", - /* 421 */ "wqlist ::= nm idxlist_opt AS LP select RP", - /* 422 */ "wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP", - /* 423 */ "wqlist ::= ID_TAB_NEW", + /* 176 */ "singlesrc ::= nm dbnm LP exprlist RP as", + /* 177 */ "singlesrc ::=", + /* 178 */ "singlesrc ::= nm DOT", + /* 179 */ "singlesrc ::= nm DOT ID_TAB", + /* 180 */ "singlesrc ::= ID_DB|ID_TAB", + /* 181 */ "singlesrc ::= nm DOT ID_VIEW", + /* 182 */ "singlesrc ::= ID_DB|ID_VIEW", + /* 183 */ "joinconstr_opt ::= ON expr", + /* 184 */ "joinconstr_opt ::= USING LP idlist RP", + /* 185 */ "joinconstr_opt ::=", + /* 186 */ "dbnm ::=", + /* 187 */ "dbnm ::= DOT nm", + /* 188 */ "fullname ::= nm dbnm", + /* 189 */ "joinop ::= COMMA", + /* 190 */ "joinop ::= JOIN", + /* 191 */ "joinop ::= JOIN_KW JOIN", + /* 192 */ "joinop ::= JOIN_KW nm JOIN", + /* 193 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 194 */ "joinop ::= ID_JOIN_OPTS", + /* 195 */ "indexed_opt ::=", + /* 196 */ "indexed_opt ::= INDEXED BY nm", + /* 197 */ "indexed_opt ::= NOT INDEXED", + /* 198 */ "indexed_opt ::= INDEXED BY ID_IDX", + /* 199 */ "orderby_opt ::=", + /* 200 */ "orderby_opt ::= ORDER BY sortlist", + /* 201 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 202 */ "sortlist ::= expr sortorder", + /* 203 */ "sortorder ::= ASC", + /* 204 */ "sortorder ::= DESC", + /* 205 */ "sortorder ::=", + /* 206 */ "groupby_opt ::=", + /* 207 */ "groupby_opt ::= GROUP BY nexprlist", + /* 208 */ "groupby_opt ::= GROUP BY", + /* 209 */ "having_opt ::=", + /* 210 */ "having_opt ::= HAVING expr", + /* 211 */ "limit_opt ::=", + /* 212 */ "limit_opt ::= LIMIT expr", + /* 213 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 214 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 215 */ "cmd ::= delete_stmt", + /* 216 */ "delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt", + /* 217 */ "delete_stmt ::= with DELETE FROM", + /* 218 */ "delete_stmt ::= with DELETE FROM nm DOT", + /* 219 */ "delete_stmt ::= with DELETE FROM nm DOT ID_TAB", + /* 220 */ "delete_stmt ::= with DELETE FROM ID_DB|ID_TAB", + /* 221 */ "where_opt ::=", + /* 222 */ "where_opt ::= WHERE expr", + /* 223 */ "where_opt ::= WHERE", + /* 224 */ "cmd ::= update_stmt", + /* 225 */ "update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", + /* 226 */ "update_stmt ::= with UPDATE orconf", + /* 227 */ "update_stmt ::= with UPDATE orconf nm DOT", + /* 228 */ "update_stmt ::= with UPDATE orconf nm DOT ID_TAB", + /* 229 */ "update_stmt ::= with UPDATE orconf ID_DB|ID_TAB", + /* 230 */ "setlist ::= setlist COMMA nm EQ expr", + /* 231 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 232 */ "setlist ::= nm EQ expr", + /* 233 */ "setlist ::= LP idlist RP EQ expr", + /* 234 */ "setlist ::=", + /* 235 */ "setlist ::= setlist COMMA", + /* 236 */ "setlist ::= setlist COMMA ID_COL", + /* 237 */ "setlist ::= ID_COL", + /* 238 */ "idlist_opt ::=", + /* 239 */ "idlist_opt ::= LP idlist RP", + /* 240 */ "idlist ::= idlist COMMA nm", + /* 241 */ "idlist ::= nm", + /* 242 */ "idlist ::=", + /* 243 */ "idlist ::= idlist COMMA ID_COL", + /* 244 */ "idlist ::= ID_COL", + /* 245 */ "cmd ::= insert_stmt", + /* 246 */ "insert_stmt ::= with insert_cmd INTO fullname idlist_opt select upsert", + /* 247 */ "insert_stmt ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", + /* 248 */ "insert_stmt ::= with insert_cmd INTO", + /* 249 */ "insert_stmt ::= with insert_cmd INTO nm DOT", + /* 250 */ "insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB", + /* 251 */ "insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB", + /* 252 */ "insert_cmd ::= INSERT orconf", + /* 253 */ "insert_cmd ::= REPLACE", + /* 254 */ "upsert ::=", + /* 255 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt", + /* 256 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING", + /* 257 */ "upsert ::= ON CONFLICT DO NOTHING", + /* 258 */ "exprx ::= nm DOT", + /* 259 */ "exprx ::= nm DOT nm DOT", + /* 260 */ "exprx ::= expr not_opt BETWEEN expr AND", + /* 261 */ "exprx ::= CASE case_operand case_exprlist case_else", + /* 262 */ "exprx ::= expr not_opt IN LP exprlist", + /* 263 */ "exprx ::= expr not_opt IN ID_DB", + /* 264 */ "exprx ::= expr not_opt IN nm DOT ID_TAB", + /* 265 */ "exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN", + /* 266 */ "exprx ::= nm DOT ID_TAB|ID_COL", + /* 267 */ "exprx ::= nm DOT nm DOT ID_COL", + /* 268 */ "exprx ::= expr COLLATE ID_COLLATE", + /* 269 */ "exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP", + /* 270 */ "exprx ::= term", + /* 271 */ "exprx ::= CTIME_KW", + /* 272 */ "exprx ::= LP nexprlist RP", + /* 273 */ "exprx ::= id", + /* 274 */ "exprx ::= JOIN_KW", + /* 275 */ "exprx ::= nm DOT nm", + /* 276 */ "exprx ::= nm DOT nm DOT nm", + /* 277 */ "exprx ::= VARIABLE", + /* 278 */ "exprx ::= expr COLLATE ids", + /* 279 */ "exprx ::= CAST LP expr AS typetoken RP", + /* 280 */ "exprx ::= ID LP distinct exprlist RP", + /* 281 */ "exprx ::= ID LP STAR RP", + /* 282 */ "exprx ::= expr AND expr", + /* 283 */ "exprx ::= expr OR expr", + /* 284 */ "exprx ::= expr LT|GT|GE|LE expr", + /* 285 */ "exprx ::= expr EQ|NE expr", + /* 286 */ "exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 287 */ "exprx ::= expr PLUS|MINUS expr", + /* 288 */ "exprx ::= expr STAR|SLASH|REM expr", + /* 289 */ "exprx ::= expr CONCAT expr", + /* 290 */ "exprx ::= expr not_opt likeop expr", + /* 291 */ "exprx ::= expr not_opt likeop expr ESCAPE expr", + /* 292 */ "exprx ::= expr ISNULL|NOTNULL", + /* 293 */ "exprx ::= expr NOT NULL", + /* 294 */ "exprx ::= expr IS not_opt expr", + /* 295 */ "exprx ::= NOT expr", + /* 296 */ "exprx ::= BITNOT expr", + /* 297 */ "exprx ::= MINUS expr", + /* 298 */ "exprx ::= PLUS expr", + /* 299 */ "exprx ::= expr not_opt BETWEEN expr AND expr", + /* 300 */ "exprx ::= expr not_opt IN LP exprlist RP", + /* 301 */ "exprx ::= LP select RP", + /* 302 */ "exprx ::= expr not_opt IN LP select RP", + /* 303 */ "exprx ::= expr not_opt IN nm dbnm", + /* 304 */ "exprx ::= EXISTS LP select RP", + /* 305 */ "exprx ::= CASE case_operand case_exprlist case_else END", + /* 306 */ "exprx ::= RAISE LP IGNORE RP", + /* 307 */ "exprx ::= RAISE LP raisetype COMMA nm RP", + /* 308 */ "expr ::=", + /* 309 */ "expr ::= exprx", + /* 310 */ "not_opt ::=", + /* 311 */ "not_opt ::= NOT", + /* 312 */ "likeop ::= LIKE_KW|MATCH", + /* 313 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 314 */ "case_exprlist ::= WHEN expr THEN expr", + /* 315 */ "case_else ::= ELSE expr", + /* 316 */ "case_else ::=", + /* 317 */ "case_operand ::= exprx", + /* 318 */ "case_operand ::=", + /* 319 */ "exprlist ::= nexprlist", + /* 320 */ "exprlist ::=", + /* 321 */ "nexprlist ::= nexprlist COMMA expr", + /* 322 */ "nexprlist ::= exprx", + /* 323 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 324 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB", + /* 325 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW", + /* 326 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW", + /* 327 */ "uniqueflag ::= UNIQUE", + /* 328 */ "uniqueflag ::=", + /* 329 */ "idxlist_opt ::=", + /* 330 */ "idxlist_opt ::= LP idxlist RP", + /* 331 */ "idxlist ::= idxlist COMMA idxlist_single", + /* 332 */ "idxlist ::= idxlist_single", + /* 333 */ "idxlist_single ::= nm collate sortorder", + /* 334 */ "idxlist_single ::= ID_COL", + /* 335 */ "collate ::=", + /* 336 */ "collate ::= COLLATE ids", + /* 337 */ "collate ::= COLLATE ID_COLLATE", + /* 338 */ "cmd ::= DROP INDEX ifexists fullname", + /* 339 */ "cmd ::= DROP INDEX ifexists nm DOT ID_IDX", + /* 340 */ "cmd ::= DROP INDEX ifexists ID_DB|ID_IDX", + /* 341 */ "cmd ::= VACUUM", + /* 342 */ "cmd ::= VACUUM nm", + /* 343 */ "cmd ::= PRAGMA nm dbnm", + /* 344 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 345 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 346 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 347 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 348 */ "cmd ::= PRAGMA nm DOT ID_PRAGMA", + /* 349 */ "cmd ::= PRAGMA ID_DB|ID_PRAGMA", + /* 350 */ "nmnum ::= plus_num", + /* 351 */ "nmnum ::= nm", + /* 352 */ "nmnum ::= ON", + /* 353 */ "nmnum ::= DELETE", + /* 354 */ "nmnum ::= DEFAULT", + /* 355 */ "plus_num ::= PLUS number", + /* 356 */ "plus_num ::= number", + /* 357 */ "minus_num ::= MINUS number", + /* 358 */ "number ::= INTEGER", + /* 359 */ "number ::= FLOAT", + /* 360 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END", + /* 361 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause", + /* 362 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list", + /* 363 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB", + /* 364 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW", + /* 365 */ "cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW", + /* 366 */ "trigger_time ::= BEFORE", + /* 367 */ "trigger_time ::= AFTER", + /* 368 */ "trigger_time ::= INSTEAD OF", + /* 369 */ "trigger_time ::=", + /* 370 */ "trigger_event ::= DELETE", + /* 371 */ "trigger_event ::= INSERT", + /* 372 */ "trigger_event ::= UPDATE", + /* 373 */ "trigger_event ::= UPDATE OF idlist", + /* 374 */ "foreach_clause ::=", + /* 375 */ "foreach_clause ::= FOR EACH ROW", + /* 376 */ "when_clause ::=", + /* 377 */ "when_clause ::= WHEN expr", + /* 378 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 379 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 380 */ "trigger_cmd_list ::= SEMI", + /* 381 */ "trigger_cmd ::= update_stmt", + /* 382 */ "trigger_cmd ::= insert_stmt", + /* 383 */ "trigger_cmd ::= delete_stmt", + /* 384 */ "trigger_cmd ::= select_stmt", + /* 385 */ "raisetype ::= ROLLBACK|ABORT|FAIL", + /* 386 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 387 */ "cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG", + /* 388 */ "cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG", + /* 389 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 390 */ "cmd ::= DETACH database_kw_opt expr", + /* 391 */ "key_opt ::=", + /* 392 */ "key_opt ::= KEY expr", + /* 393 */ "database_kw_opt ::= DATABASE", + /* 394 */ "database_kw_opt ::=", + /* 395 */ "cmd ::= REINDEX", + /* 396 */ "cmd ::= REINDEX nm dbnm", + /* 397 */ "cmd ::= REINDEX ID_COLLATE", + /* 398 */ "cmd ::= REINDEX nm DOT ID_TAB|ID_IDX", + /* 399 */ "cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB", + /* 400 */ "cmd ::= ANALYZE", + /* 401 */ "cmd ::= ANALYZE nm dbnm", + /* 402 */ "cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX", + /* 403 */ "cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB", + /* 404 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 405 */ "cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column", + /* 406 */ "cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW", + /* 407 */ "cmd ::= ALTER TABLE nm DOT ID_TAB", + /* 408 */ "cmd ::= ALTER TABLE ID_DB|ID_TAB", + /* 409 */ "kwcolumn_opt ::=", + /* 410 */ "kwcolumn_opt ::= COLUMNKW", + /* 411 */ "cmd ::= create_vtab", + /* 412 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 413 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP", + /* 414 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW", + /* 415 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW", + /* 416 */ "vtabarglist ::= vtabarg", + /* 417 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 418 */ "vtabarg ::=", + /* 419 */ "vtabarg ::= vtabarg vtabargtoken", + /* 420 */ "vtabargtoken ::= ANY", + /* 421 */ "vtabargtoken ::= LP anylist RP", + /* 422 */ "anylist ::=", + /* 423 */ "anylist ::= anylist LP anylist RP", + /* 424 */ "anylist ::= anylist ANY", + /* 425 */ "with ::=", + /* 426 */ "with ::= WITH wqlist", + /* 427 */ "with ::= WITH RECURSIVE wqlist", + /* 428 */ "wqlist ::= nm idxlist_opt AS LP select RP", + /* 429 */ "wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP", + /* 430 */ "wqlist ::= ID_TAB_NEW", }; #endif /* NDEBUG */ @@ -1671,309 +1709,314 @@ static void yy_destructor( ** which appear on the RHS of the rule, but which are not used ** inside the C code. */ - case 169: /* cmd */ - case 172: /* ecmd */ - case 174: /* cmdx */ - case 218: /* select_stmt */ - case 245: /* delete_stmt */ - case 246: /* update_stmt */ - case 248: /* insert_stmt */ - case 267: /* trigger_cmd */ - case 271: /* create_vtab */ -{ -delete (yypminor->yy399); + case 171: /* cmd */ + case 174: /* ecmd */ + case 176: /* cmdx */ + case 220: /* select_stmt */ + case 247: /* delete_stmt */ + case 248: /* update_stmt */ + case 251: /* insert_stmt */ + case 270: /* trigger_cmd */ + case 274: /* create_vtab */ +{ +delete (yypminor->yy283); } break; - case 173: /* explain */ + case 175: /* explain */ { -delete (yypminor->yy225); +delete (yypminor->yy411); } break; - case 175: /* transtype */ - case 176: /* trans_opt */ + case 177: /* transtype */ + case 178: /* trans_opt */ { -delete (yypminor->yy300); +delete (yypminor->yy404); } break; - case 177: /* nm */ - case 184: /* table_options */ - case 187: /* columnid */ - case 190: /* id */ - case 191: /* ids */ - case 193: /* typename */ - case 241: /* dbnm */ - case 259: /* collate */ - case 273: /* vtabarg */ - case 274: /* vtabargtoken */ - case 275: /* anylist */ -{ -delete (yypminor->yy211); + case 179: /* nm */ + case 186: /* table_options */ + case 189: /* columnid */ + case 192: /* id */ + case 193: /* ids */ + case 195: /* typename */ + case 243: /* dbnm */ + case 262: /* collate */ + case 276: /* vtabarg */ + case 277: /* vtabargtoken */ + case 278: /* anylist */ +{ +delete (yypminor->yy399); } break; - case 178: /* savepoint_opt */ - case 180: /* ifnotexists */ - case 202: /* autoinc */ - case 210: /* tconscomma */ - case 217: /* ifexists */ - case 252: /* not_opt */ - case 257: /* uniqueflag */ - case 268: /* database_kw_opt */ - case 270: /* kwcolumn_opt */ -{ -delete (yypminor->yy237); + case 180: /* savepoint_opt */ + case 182: /* ifnotexists */ + case 204: /* autoinc */ + case 212: /* tconscomma */ + case 219: /* ifexists */ + case 255: /* not_opt */ + case 260: /* uniqueflag */ + case 271: /* database_kw_opt */ + case 273: /* kwcolumn_opt */ +{ +delete (yypminor->yy451); } break; - case 179: /* temp */ - case 224: /* distinct */ + case 181: /* temp */ + case 226: /* distinct */ { -delete (yypminor->yy376); +delete (yypminor->yy146); } break; - case 181: /* fullname */ + case 183: /* fullname */ { -delete (yypminor->yy66); +delete (yypminor->yy360); } break; - case 182: /* columnlist */ + case 184: /* columnlist */ { -delete (yypminor->yy118); +delete (yypminor->yy202); } break; - case 183: /* conslist_opt */ - case 209: /* conslist */ + case 185: /* conslist_opt */ + case 211: /* conslist */ { -delete (yypminor->yy87); +delete (yypminor->yy333); } break; - case 185: /* select */ - case 220: /* selectnowith */ + case 187: /* select */ + case 222: /* selectnowith */ { -delete (yypminor->yy123); +delete (yypminor->yy473); } break; - case 186: /* column */ + case 188: /* column */ { -delete (yypminor->yy425); +delete (yypminor->yy227); } break; - case 188: /* type */ - case 192: /* typetoken */ + case 190: /* type */ + case 194: /* typetoken */ { -delete (yypminor->yy299); +delete (yypminor->yy537); } break; - case 189: /* carglist */ + case 191: /* carglist */ { -delete (yypminor->yy449); +delete (yypminor->yy51); } break; - case 194: /* signed */ - case 195: /* plus_num */ - case 196: /* minus_num */ - case 198: /* term */ - case 260: /* nmnum */ - case 261: /* number */ -{ -delete (yypminor->yy21); + case 196: /* signed */ + case 197: /* plus_num */ + case 198: /* minus_num */ + case 200: /* term */ + case 263: /* nmnum */ + case 264: /* number */ +{ +delete (yypminor->yy469); } break; - case 197: /* ccons */ + case 199: /* ccons */ { -delete (yypminor->yy4); +delete (yypminor->yy304); } break; - case 199: /* expr */ - case 227: /* where_opt */ - case 229: /* having_opt */ - case 251: /* exprx */ - case 253: /* case_operand */ - case 255: /* case_else */ -{ -delete (yypminor->yy490); + case 201: /* expr */ + case 229: /* where_opt */ + case 231: /* having_opt */ + case 254: /* exprx */ + case 256: /* case_operand */ + case 258: /* case_else */ +{ +delete (yypminor->yy352); } break; - case 200: /* onconf */ - case 214: /* resolvetype */ - case 215: /* orconf */ + case 202: /* onconf */ + case 216: /* resolvetype */ + case 217: /* orconf */ { -delete (yypminor->yy30); +delete (yypminor->yy338); } break; - case 201: /* sortorder */ + case 203: /* sortorder */ { -delete (yypminor->yy226); +delete (yypminor->yy309); } break; - case 203: /* idxlist_opt */ - case 212: /* idxlist */ + case 205: /* idxlist_opt */ + case 214: /* idxlist */ { -delete (yypminor->yy139); +delete (yypminor->yy223); } break; - case 204: /* refargs */ + case 206: /* refargs */ { -delete (yypminor->yy108); +delete (yypminor->yy184); } break; - case 205: /* defer_subclause */ - case 213: /* defer_subclause_opt */ + case 207: /* defer_subclause */ + case 215: /* defer_subclause_opt */ { -delete (yypminor->yy131); +delete (yypminor->yy329); } break; - case 206: /* refarg */ + case 208: /* refarg */ { -delete (yypminor->yy271); +delete (yypminor->yy347); } break; - case 207: /* refact */ + case 209: /* refact */ { -delete (yypminor->yy312); +delete (yypminor->yy104); } break; - case 208: /* init_deferred_pred_opt */ + case 210: /* init_deferred_pred_opt */ { -delete (yypminor->yy498); +delete (yypminor->yy392); } break; - case 211: /* tcons */ + case 213: /* tcons */ { -delete (yypminor->yy8); +delete (yypminor->yy406); } break; - case 219: /* with */ - case 276: /* wqlist */ + case 221: /* with */ + case 279: /* wqlist */ { -delete (yypminor->yy367); +delete (yypminor->yy321); } break; - case 221: /* oneselect */ + case 223: /* oneselect */ { -delete (yypminor->yy468); +delete (yypminor->yy310); } break; - case 222: /* multiselect_op */ + case 224: /* multiselect_op */ { -delete (yypminor->yy168); +delete (yypminor->yy462); } break; - case 223: /* values */ + case 225: /* values */ { -delete (yypminor->yy416); +delete (yypminor->yy166); } break; - case 225: /* selcollist */ - case 234: /* sclp */ + case 227: /* selcollist */ + case 236: /* sclp */ { -delete (yypminor->yy263); +delete (yypminor->yy373); } break; - case 226: /* from */ - case 236: /* joinsrc */ + case 228: /* from */ + case 238: /* joinsrc */ { -delete (yypminor->yy373); +delete (yypminor->yy511); } break; - case 228: /* groupby_opt */ - case 232: /* nexprlist */ - case 233: /* exprlist */ - case 254: /* case_exprlist */ + case 230: /* groupby_opt */ + case 234: /* nexprlist */ + case 235: /* exprlist */ + case 257: /* case_exprlist */ { -delete (yypminor->yy13); +delete (yypminor->yy551); } break; - case 230: /* orderby_opt */ - case 244: /* sortlist */ + case 232: /* orderby_opt */ + case 246: /* sortlist */ { -delete (yypminor->yy495); +delete (yypminor->yy163); } break; - case 231: /* limit_opt */ + case 233: /* limit_opt */ { -delete (yypminor->yy128); +delete (yypminor->yy484); } break; - case 235: /* as */ + case 237: /* as */ { -delete (yypminor->yy28); +delete (yypminor->yy200); } break; - case 237: /* singlesrc */ + case 239: /* singlesrc */ { -delete (yypminor->yy173); +delete (yypminor->yy201); } break; - case 238: /* seltablist */ + case 240: /* seltablist */ { -delete (yypminor->yy359); +delete (yypminor->yy131); } break; - case 239: /* joinop */ + case 241: /* joinop */ { -delete (yypminor->yy473); +delete (yypminor->yy301); } break; - case 240: /* joinconstr_opt */ + case 242: /* joinconstr_opt */ { -delete (yypminor->yy117); +delete (yypminor->yy295); } break; - case 242: /* indexed_opt */ + case 244: /* indexed_opt */ { -delete (yypminor->yy472); +delete (yypminor->yy192); } break; - case 243: /* inscollist */ - case 250: /* inscollist_opt */ - case 272: /* vtabarglist */ + case 245: /* idlist */ + case 250: /* idlist_opt */ + case 275: /* vtabarglist */ { -delete (yypminor->yy445); +delete (yypminor->yy95); } break; - case 247: /* setlist */ + case 249: /* setlist */ { -delete (yypminor->yy381); +delete (yypminor->yy521); } break; - case 249: /* insert_cmd */ + case 252: /* insert_cmd */ { -delete (yypminor->yy250); +delete (yypminor->yy105); } break; - case 256: /* likeop */ + case 253: /* upsert */ { -delete (yypminor->yy374); +delete (yypminor->yy560); } break; - case 258: /* idxlist_single */ + case 259: /* likeop */ { -delete (yypminor->yy90); +delete (yypminor->yy520); } break; - case 262: /* trigger_time */ + case 261: /* idxlist_single */ { -delete (yypminor->yy152); +delete (yypminor->yy108); } break; - case 263: /* trigger_event */ + case 265: /* trigger_time */ { -delete (yypminor->yy309); +delete (yypminor->yy132); +} + break; + case 266: /* trigger_event */ +{ +delete (yypminor->yy552); } break; - case 264: /* foreach_clause */ + case 267: /* foreach_clause */ { -delete (yypminor->yy409); +delete (yypminor->yy3); } break; - case 265: /* when_clause */ - case 269: /* key_opt */ + case 268: /* when_clause */ + case 272: /* key_opt */ { -if ((yypminor->yy490)) delete (yypminor->yy490); +if ((yypminor->yy352)) delete (yypminor->yy352); } break; - case 266: /* trigger_cmd_list */ + case 269: /* trigger_cmd_list */ { -delete (yypminor->yy214); +delete (yypminor->yy430); } break; default: break; /* If no destructor action specified: do nothing */ @@ -2224,430 +2267,437 @@ static const struct { YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ unsigned char nrhs; /* Number of right-hand side symbols in the rule */ } yyRuleInfo[] = { - { 170, 1 }, - { 171, 2 }, - { 171, 1 }, { 172, 1 }, - { 172, 3 }, - { 173, 0 }, + { 173, 2 }, { 173, 1 }, - { 173, 3 }, { 174, 1 }, - { 169, 3 }, - { 176, 0 }, - { 176, 1 }, - { 176, 2 }, - { 176, 2 }, + { 174, 3 }, { 175, 0 }, { 175, 1 }, - { 175, 1 }, - { 175, 1 }, - { 169, 2 }, - { 169, 2 }, - { 169, 2 }, - { 178, 1 }, + { 175, 3 }, + { 176, 1 }, + { 171, 3 }, { 178, 0 }, - { 169, 2 }, - { 169, 3 }, - { 169, 5 }, - { 169, 2 }, - { 169, 3 }, - { 169, 5 }, - { 169, 10 }, - { 169, 7 }, - { 169, 7 }, - { 169, 5 }, - { 184, 0 }, - { 184, 2 }, - { 184, 2 }, - { 180, 0 }, - { 180, 3 }, - { 179, 1 }, - { 179, 0 }, - { 182, 3 }, - { 182, 1 }, - { 186, 3 }, - { 187, 1 }, - { 187, 1 }, - { 190, 1 }, - { 191, 1 }, + { 178, 1 }, + { 178, 2 }, + { 178, 2 }, + { 177, 0 }, { 177, 1 }, { 177, 1 }, { 177, 1 }, - { 188, 0 }, - { 188, 1 }, + { 171, 2 }, + { 171, 2 }, + { 171, 2 }, + { 180, 1 }, + { 180, 0 }, + { 171, 2 }, + { 171, 3 }, + { 171, 5 }, + { 171, 2 }, + { 171, 3 }, + { 171, 5 }, + { 171, 10 }, + { 171, 7 }, + { 171, 7 }, + { 171, 5 }, + { 186, 0 }, + { 186, 2 }, + { 186, 2 }, + { 182, 0 }, + { 182, 3 }, + { 181, 1 }, + { 181, 0 }, + { 184, 3 }, + { 184, 1 }, + { 188, 3 }, + { 189, 1 }, + { 189, 1 }, { 192, 1 }, - { 192, 4 }, - { 192, 6 }, - { 193, 1 }, - { 193, 2 }, { 193, 1 }, + { 179, 1 }, + { 179, 1 }, + { 179, 1 }, + { 190, 0 }, + { 190, 1 }, { 194, 1 }, - { 194, 1 }, - { 189, 2 }, - { 189, 0 }, - { 197, 2 }, - { 197, 2 }, - { 197, 4 }, - { 197, 3 }, - { 197, 3 }, - { 197, 2 }, - { 197, 2 }, - { 197, 2 }, - { 197, 3 }, - { 197, 5 }, - { 197, 2 }, - { 197, 4 }, - { 197, 4 }, - { 197, 1 }, - { 197, 2 }, - { 197, 2 }, - { 197, 2 }, - { 197, 2 }, - { 197, 3 }, - { 198, 1 }, - { 198, 1 }, - { 198, 1 }, - { 198, 1 }, - { 202, 0 }, - { 202, 1 }, + { 194, 4 }, + { 194, 6 }, + { 195, 1 }, + { 195, 2 }, + { 195, 1 }, + { 196, 1 }, + { 196, 1 }, + { 191, 2 }, + { 191, 0 }, + { 199, 2 }, + { 199, 2 }, + { 199, 4 }, + { 199, 3 }, + { 199, 3 }, + { 199, 2 }, + { 199, 2 }, + { 199, 2 }, + { 199, 3 }, + { 199, 5 }, + { 199, 2 }, + { 199, 4 }, + { 199, 4 }, + { 199, 1 }, + { 199, 2 }, + { 199, 2 }, + { 199, 2 }, + { 199, 2 }, + { 199, 3 }, + { 200, 1 }, + { 200, 1 }, + { 200, 1 }, + { 200, 1 }, { 204, 0 }, - { 204, 2 }, + { 204, 1 }, + { 206, 0 }, { 206, 2 }, - { 206, 3 }, - { 206, 3 }, - { 206, 3 }, - { 206, 2 }, - { 207, 2 }, - { 207, 2 }, - { 207, 1 }, - { 207, 1 }, - { 207, 2 }, - { 205, 3 }, - { 205, 2 }, - { 208, 0 }, { 208, 2 }, + { 208, 3 }, + { 208, 3 }, + { 208, 3 }, { 208, 2 }, - { 183, 0 }, - { 183, 2 }, - { 209, 3 }, + { 209, 2 }, + { 209, 2 }, + { 209, 1 }, { 209, 1 }, - { 210, 1 }, + { 209, 2 }, + { 207, 3 }, + { 207, 2 }, { 210, 0 }, - { 211, 2 }, - { 211, 7 }, - { 211, 5 }, - { 211, 5 }, - { 211, 10 }, - { 211, 2 }, - { 211, 7 }, - { 211, 4 }, - { 213, 0 }, - { 213, 1 }, - { 200, 0 }, - { 200, 3 }, + { 210, 2 }, + { 210, 2 }, + { 185, 0 }, + { 185, 2 }, + { 211, 3 }, + { 211, 1 }, + { 212, 1 }, + { 212, 0 }, + { 213, 2 }, + { 213, 7 }, + { 213, 5 }, + { 213, 5 }, + { 213, 10 }, + { 213, 2 }, + { 213, 7 }, + { 213, 4 }, { 215, 0 }, - { 215, 2 }, - { 214, 1 }, - { 214, 1 }, - { 214, 1 }, - { 169, 4 }, - { 169, 6 }, - { 169, 4 }, - { 217, 2 }, + { 215, 1 }, + { 202, 0 }, + { 202, 3 }, { 217, 0 }, - { 169, 8 }, - { 169, 7 }, - { 169, 5 }, - { 169, 4 }, - { 169, 6 }, - { 169, 4 }, - { 169, 1 }, - { 218, 1 }, - { 185, 2 }, - { 220, 1 }, - { 220, 3 }, + { 217, 2 }, + { 216, 1 }, + { 216, 1 }, + { 216, 1 }, + { 171, 4 }, + { 171, 6 }, + { 171, 4 }, + { 219, 2 }, + { 219, 0 }, + { 171, 8 }, + { 171, 7 }, + { 171, 5 }, + { 171, 4 }, + { 171, 6 }, + { 171, 4 }, + { 171, 1 }, { 220, 1 }, - { 220, 3 }, - { 222, 1 }, - { 222, 2 }, + { 187, 2 }, { 222, 1 }, + { 222, 3 }, { 222, 1 }, - { 221, 9 }, - { 223, 4 }, - { 223, 5 }, + { 222, 3 }, + { 223, 9 }, + { 225, 4 }, + { 225, 5 }, { 224, 1 }, + { 224, 2 }, { 224, 1 }, - { 224, 0 }, - { 234, 2 }, - { 234, 0 }, - { 225, 3 }, - { 225, 2 }, - { 225, 4 }, - { 225, 1 }, - { 225, 4 }, - { 235, 2 }, - { 235, 1 }, - { 235, 2 }, - { 235, 1 }, - { 235, 0 }, + { 224, 1 }, + { 226, 1 }, + { 226, 1 }, { 226, 0 }, - { 226, 2 }, { 236, 2 }, { 236, 0 }, - { 238, 4 }, - { 238, 0 }, - { 237, 4 }, - { 237, 4 }, - { 237, 4 }, - { 237, 0 }, + { 227, 3 }, + { 227, 2 }, + { 227, 4 }, + { 227, 1 }, + { 227, 4 }, { 237, 2 }, - { 237, 3 }, { 237, 1 }, - { 237, 3 }, + { 237, 2 }, { 237, 1 }, - { 240, 2 }, + { 237, 0 }, + { 228, 0 }, + { 228, 2 }, + { 238, 2 }, + { 238, 0 }, { 240, 4 }, { 240, 0 }, - { 241, 0 }, - { 241, 2 }, - { 181, 2 }, - { 239, 1 }, - { 239, 1 }, + { 239, 4 }, + { 239, 4 }, + { 239, 4 }, + { 239, 6 }, + { 239, 0 }, { 239, 2 }, { 239, 3 }, - { 239, 4 }, { 239, 1 }, - { 242, 0 }, - { 242, 3 }, + { 239, 3 }, + { 239, 1 }, { 242, 2 }, - { 242, 3 }, + { 242, 4 }, + { 242, 0 }, + { 243, 0 }, + { 243, 2 }, + { 183, 2 }, + { 241, 1 }, + { 241, 1 }, + { 241, 2 }, + { 241, 3 }, + { 241, 4 }, + { 241, 1 }, + { 244, 0 }, + { 244, 3 }, + { 244, 2 }, + { 244, 3 }, + { 232, 0 }, + { 232, 3 }, + { 246, 4 }, + { 246, 2 }, + { 203, 1 }, + { 203, 1 }, + { 203, 0 }, { 230, 0 }, { 230, 3 }, - { 244, 4 }, - { 244, 2 }, - { 201, 1 }, - { 201, 1 }, - { 201, 0 }, - { 228, 0 }, - { 228, 3 }, - { 228, 2 }, - { 229, 0 }, - { 229, 2 }, + { 230, 2 }, { 231, 0 }, { 231, 2 }, - { 231, 4 }, - { 231, 4 }, - { 169, 1 }, - { 245, 6 }, - { 245, 3 }, - { 245, 5 }, - { 245, 6 }, - { 245, 4 }, - { 227, 0 }, - { 227, 2 }, - { 227, 1 }, - { 169, 1 }, - { 246, 8 }, - { 246, 3 }, - { 246, 5 }, - { 246, 6 }, - { 246, 4 }, - { 247, 5 }, - { 247, 3 }, - { 247, 0 }, - { 247, 2 }, + { 233, 0 }, + { 233, 2 }, + { 233, 4 }, + { 233, 4 }, + { 171, 1 }, + { 247, 6 }, { 247, 3 }, - { 247, 1 }, - { 169, 1 }, - { 248, 6 }, - { 248, 7 }, + { 247, 5 }, + { 247, 6 }, + { 247, 4 }, + { 229, 0 }, + { 229, 2 }, + { 229, 1 }, + { 171, 1 }, + { 248, 8 }, { 248, 3 }, { 248, 5 }, - { 248, 4 }, { 248, 6 }, + { 248, 4 }, + { 249, 5 }, + { 249, 7 }, + { 249, 3 }, + { 249, 5 }, + { 249, 0 }, { 249, 2 }, + { 249, 3 }, { 249, 1 }, { 250, 0 }, { 250, 3 }, - { 243, 3 }, - { 243, 1 }, - { 243, 0 }, - { 243, 3 }, - { 243, 1 }, - { 251, 2 }, - { 251, 4 }, - { 251, 5 }, - { 251, 4 }, - { 251, 5 }, - { 251, 4 }, - { 251, 6 }, - { 251, 1 }, - { 251, 3 }, - { 251, 5 }, - { 251, 3 }, - { 251, 6 }, - { 251, 1 }, - { 251, 1 }, - { 251, 3 }, - { 251, 1 }, - { 251, 1 }, - { 251, 3 }, - { 251, 5 }, - { 251, 1 }, - { 251, 3 }, - { 251, 6 }, - { 251, 5 }, - { 251, 4 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 4 }, - { 251, 6 }, - { 251, 2 }, - { 251, 3 }, - { 251, 4 }, - { 251, 2 }, - { 251, 2 }, - { 251, 2 }, - { 251, 2 }, - { 251, 6 }, - { 251, 6 }, + { 245, 3 }, + { 245, 1 }, + { 245, 0 }, + { 245, 3 }, + { 245, 1 }, + { 171, 1 }, + { 251, 7 }, + { 251, 7 }, { 251, 3 }, - { 251, 6 }, - { 251, 5 }, - { 251, 4 }, { 251, 5 }, { 251, 4 }, { 251, 6 }, - { 199, 0 }, - { 199, 1 }, - { 252, 0 }, + { 252, 2 }, { 252, 1 }, - { 256, 1 }, + { 253, 0 }, + { 253, 11 }, + { 253, 8 }, + { 253, 4 }, + { 254, 2 }, + { 254, 4 }, + { 254, 5 }, + { 254, 4 }, + { 254, 5 }, + { 254, 4 }, + { 254, 6 }, + { 254, 1 }, + { 254, 3 }, + { 254, 5 }, + { 254, 3 }, + { 254, 6 }, + { 254, 1 }, + { 254, 1 }, + { 254, 3 }, + { 254, 1 }, + { 254, 1 }, + { 254, 3 }, + { 254, 5 }, + { 254, 1 }, + { 254, 3 }, + { 254, 6 }, + { 254, 5 }, + { 254, 4 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 4 }, + { 254, 6 }, + { 254, 2 }, + { 254, 3 }, + { 254, 4 }, + { 254, 2 }, + { 254, 2 }, + { 254, 2 }, + { 254, 2 }, + { 254, 6 }, + { 254, 6 }, + { 254, 3 }, + { 254, 6 }, { 254, 5 }, { 254, 4 }, - { 255, 2 }, + { 254, 5 }, + { 254, 4 }, + { 254, 6 }, + { 201, 0 }, + { 201, 1 }, { 255, 0 }, - { 253, 1 }, - { 253, 0 }, - { 233, 1 }, - { 233, 0 }, - { 232, 3 }, - { 232, 1 }, - { 169, 12 }, - { 169, 8 }, - { 169, 7 }, - { 169, 5 }, - { 257, 1 }, - { 257, 0 }, - { 203, 0 }, - { 203, 3 }, - { 212, 3 }, - { 212, 1 }, - { 258, 3 }, - { 258, 1 }, - { 259, 0 }, - { 259, 2 }, - { 259, 2 }, - { 169, 4 }, - { 169, 6 }, - { 169, 4 }, - { 169, 1 }, - { 169, 2 }, - { 169, 3 }, - { 169, 5 }, - { 169, 6 }, - { 169, 5 }, - { 169, 6 }, - { 169, 4 }, - { 169, 2 }, - { 260, 1 }, - { 260, 1 }, - { 260, 1 }, - { 260, 1 }, + { 255, 1 }, + { 259, 1 }, + { 257, 5 }, + { 257, 4 }, + { 258, 2 }, + { 258, 0 }, + { 256, 1 }, + { 256, 0 }, + { 235, 1 }, + { 235, 0 }, + { 234, 3 }, + { 234, 1 }, + { 171, 12 }, + { 171, 8 }, + { 171, 7 }, + { 171, 5 }, { 260, 1 }, - { 195, 2 }, - { 195, 1 }, - { 196, 2 }, - { 261, 1 }, + { 260, 0 }, + { 205, 0 }, + { 205, 3 }, + { 214, 3 }, + { 214, 1 }, + { 261, 3 }, { 261, 1 }, - { 169, 15 }, - { 169, 12 }, - { 169, 14 }, - { 169, 10 }, - { 169, 7 }, - { 169, 5 }, - { 262, 1 }, - { 262, 1 }, - { 262, 2 }, { 262, 0 }, + { 262, 2 }, + { 262, 2 }, + { 171, 4 }, + { 171, 6 }, + { 171, 4 }, + { 171, 1 }, + { 171, 2 }, + { 171, 3 }, + { 171, 5 }, + { 171, 6 }, + { 171, 5 }, + { 171, 6 }, + { 171, 4 }, + { 171, 2 }, { 263, 1 }, { 263, 1 }, { 263, 1 }, - { 263, 3 }, - { 264, 0 }, - { 264, 3 }, - { 265, 0 }, + { 263, 1 }, + { 263, 1 }, + { 197, 2 }, + { 197, 1 }, + { 198, 2 }, + { 264, 1 }, + { 264, 1 }, + { 171, 15 }, + { 171, 12 }, + { 171, 14 }, + { 171, 10 }, + { 171, 7 }, + { 171, 5 }, + { 265, 1 }, + { 265, 1 }, { 265, 2 }, - { 266, 3 }, - { 266, 2 }, + { 265, 0 }, { 266, 1 }, - { 267, 1 }, - { 267, 1 }, - { 267, 1 }, - { 267, 1 }, - { 216, 1 }, - { 169, 4 }, - { 169, 6 }, - { 169, 4 }, - { 169, 6 }, - { 169, 3 }, - { 269, 0 }, - { 269, 2 }, - { 268, 1 }, + { 266, 1 }, + { 266, 1 }, + { 266, 3 }, + { 267, 0 }, + { 267, 3 }, { 268, 0 }, - { 169, 1 }, - { 169, 3 }, - { 169, 2 }, - { 169, 4 }, - { 169, 2 }, - { 169, 1 }, - { 169, 3 }, - { 169, 4 }, - { 169, 2 }, - { 169, 6 }, - { 169, 6 }, - { 169, 6 }, - { 169, 5 }, - { 169, 3 }, - { 270, 0 }, + { 268, 2 }, + { 269, 3 }, + { 269, 2 }, + { 269, 1 }, + { 270, 1 }, + { 270, 1 }, + { 270, 1 }, { 270, 1 }, - { 169, 1 }, - { 271, 8 }, - { 271, 11 }, - { 271, 7 }, - { 271, 5 }, - { 272, 1 }, - { 272, 3 }, + { 218, 1 }, + { 171, 4 }, + { 171, 6 }, + { 171, 4 }, + { 171, 6 }, + { 171, 3 }, + { 272, 0 }, + { 272, 2 }, + { 271, 1 }, + { 271, 0 }, + { 171, 1 }, + { 171, 3 }, + { 171, 2 }, + { 171, 4 }, + { 171, 2 }, + { 171, 1 }, + { 171, 3 }, + { 171, 4 }, + { 171, 2 }, + { 171, 6 }, + { 171, 6 }, + { 171, 6 }, + { 171, 5 }, + { 171, 3 }, { 273, 0 }, - { 273, 2 }, - { 274, 1 }, - { 274, 3 }, - { 275, 0 }, - { 275, 4 }, - { 275, 2 }, - { 219, 0 }, - { 219, 2 }, - { 219, 3 }, - { 276, 6 }, - { 276, 8 }, - { 276, 1 }, + { 273, 1 }, + { 171, 1 }, + { 274, 8 }, + { 274, 11 }, + { 274, 7 }, + { 274, 5 }, + { 275, 1 }, + { 275, 3 }, + { 276, 0 }, + { 276, 2 }, + { 277, 1 }, + { 277, 3 }, + { 278, 0 }, + { 278, 4 }, + { 278, 2 }, + { 221, 0 }, + { 221, 2 }, + { 221, 3 }, + { 279, 6 }, + { 279, 8 }, + { 279, 1 }, }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -2707,119 +2757,119 @@ static void yy_reduce( ** break; */ case 1: /* cmdlist ::= cmdlist ecmd */ -{parserContext->addQuery(yymsp[0].minor.yy399); DONT_INHERIT_TOKENS("cmdlist");} +{parserContext->addQuery(yymsp[0].minor.yy283); DONT_INHERIT_TOKENS("cmdlist");} break; case 2: /* cmdlist ::= ecmd */ -{parserContext->addQuery(yymsp[0].minor.yy399);} +{parserContext->addQuery(yymsp[0].minor.yy283);} break; case 3: /* ecmd ::= SEMI */ -{yygotominor.yy399 = new SqliteEmptyQuery();} +{yygotominor.yy283 = new SqliteEmptyQuery();} break; case 4: /* ecmd ::= explain cmdx SEMI */ { - yygotominor.yy399 = yymsp[-1].minor.yy399; - yygotominor.yy399->explain = yymsp[-2].minor.yy225->explain; - yygotominor.yy399->queryPlan = yymsp[-2].minor.yy225->queryPlan; - delete yymsp[-2].minor.yy225; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = yymsp[-1].minor.yy283; + yygotominor.yy283->explain = yymsp[-2].minor.yy411->explain; + yygotominor.yy283->queryPlan = yymsp[-2].minor.yy411->queryPlan; + delete yymsp[-2].minor.yy411; + objectForTokens = yygotominor.yy283; } break; case 5: /* explain ::= */ -{yygotominor.yy225 = new ParserStubExplain(false, false);} +{yygotominor.yy411 = new ParserStubExplain(false, false);} break; case 6: /* explain ::= EXPLAIN */ -{yygotominor.yy225 = new ParserStubExplain(true, false);} +{yygotominor.yy411 = new ParserStubExplain(true, false);} break; case 7: /* explain ::= EXPLAIN QUERY PLAN */ -{yygotominor.yy225 = new ParserStubExplain(true, true);} +{yygotominor.yy411 = new ParserStubExplain(true, true);} break; case 8: /* cmdx ::= cmd */ - case 374: /* trigger_cmd ::= update_stmt */ yytestcase(yyruleno==374); - case 375: /* trigger_cmd ::= insert_stmt */ yytestcase(yyruleno==375); - case 376: /* trigger_cmd ::= delete_stmt */ yytestcase(yyruleno==376); - case 377: /* trigger_cmd ::= select_stmt */ yytestcase(yyruleno==377); - case 404: /* cmd ::= create_vtab */ yytestcase(yyruleno==404); -{yygotominor.yy399 = yymsp[0].minor.yy399;} + case 381: /* trigger_cmd ::= update_stmt */ yytestcase(yyruleno==381); + case 382: /* trigger_cmd ::= insert_stmt */ yytestcase(yyruleno==382); + case 383: /* trigger_cmd ::= delete_stmt */ yytestcase(yyruleno==383); + case 384: /* trigger_cmd ::= select_stmt */ yytestcase(yyruleno==384); + case 411: /* cmd ::= create_vtab */ yytestcase(yyruleno==411); +{yygotominor.yy283 = yymsp[0].minor.yy283;} break; case 9: /* cmd ::= BEGIN transtype trans_opt */ { - yygotominor.yy399 = new SqliteBeginTrans( - yymsp[-1].minor.yy300->type, - yymsp[0].minor.yy300->transactionKw, - yymsp[0].minor.yy300->name + yygotominor.yy283 = new SqliteBeginTrans( + yymsp[-1].minor.yy404->type, + yymsp[0].minor.yy404->transactionKw, + yymsp[0].minor.yy404->name ); - delete yymsp[0].minor.yy300; - delete yymsp[-1].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy404; + delete yymsp[-1].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 10: /* trans_opt ::= */ case 14: /* transtype ::= */ yytestcase(yyruleno==14); -{yygotominor.yy300 = new ParserStubTransDetails();} +{yygotominor.yy404 = new ParserStubTransDetails();} break; case 11: /* trans_opt ::= TRANSACTION */ { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->transactionKw = true; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->transactionKw = true; } break; case 12: /* trans_opt ::= TRANSACTION nm */ case 13: /* trans_opt ::= TRANSACTION ID_TRANS */ yytestcase(yyruleno==13); { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->transactionKw = true; - yygotominor.yy300->name = *(yymsp[0].minor.yy211); - delete yymsp[0].minor.yy211; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->transactionKw = true; + yygotominor.yy404->name = *(yymsp[0].minor.yy399); + delete yymsp[0].minor.yy399; } break; case 15: /* transtype ::= DEFERRED */ { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->type = SqliteBeginTrans::Type::DEFERRED; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->type = SqliteBeginTrans::Type::DEFERRED; } break; case 16: /* transtype ::= IMMEDIATE */ { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->type = SqliteBeginTrans::Type::IMMEDIATE; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->type = SqliteBeginTrans::Type::IMMEDIATE; } break; case 17: /* transtype ::= EXCLUSIVE */ { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->type = SqliteBeginTrans::Type::EXCLUSIVE; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->type = SqliteBeginTrans::Type::EXCLUSIVE; } break; case 18: /* cmd ::= COMMIT trans_opt */ { - yygotominor.yy399 = new SqliteCommitTrans( - yymsp[0].minor.yy300->transactionKw, - yymsp[0].minor.yy300->name, + yygotominor.yy283 = new SqliteCommitTrans( + yymsp[0].minor.yy404->transactionKw, + yymsp[0].minor.yy404->name, false ); - delete yymsp[0].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 19: /* cmd ::= END trans_opt */ { - yygotominor.yy399 = new SqliteCommitTrans( - yymsp[0].minor.yy300->transactionKw, - yymsp[0].minor.yy300->name, + yygotominor.yy283 = new SqliteCommitTrans( + yymsp[0].minor.yy404->transactionKw, + yymsp[0].minor.yy404->name, true ); - delete yymsp[0].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 20: /* cmd ::= ROLLBACK trans_opt */ { - yygotominor.yy399 = new SqliteRollback( - yymsp[0].minor.yy300->transactionKw, - yymsp[0].minor.yy300->name + yygotominor.yy283 = new SqliteRollback( + yymsp[0].minor.yy404->transactionKw, + yymsp[0].minor.yy404->name ); - delete yymsp[0].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 21: /* savepoint_opt ::= SAVEPOINT */ @@ -2827,159 +2877,159 @@ static void yy_reduce( case 86: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==86); case 108: /* tconscomma ::= COMMA */ yytestcase(yyruleno==108); case 130: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==130); - case 304: /* not_opt ::= NOT */ yytestcase(yyruleno==304); - case 320: /* uniqueflag ::= UNIQUE */ yytestcase(yyruleno==320); - case 386: /* database_kw_opt ::= DATABASE */ yytestcase(yyruleno==386); - case 402: /* kwcolumn_opt ::= */ yytestcase(yyruleno==402); -{yygotominor.yy237 = new bool(true);} + case 311: /* not_opt ::= NOT */ yytestcase(yyruleno==311); + case 327: /* uniqueflag ::= UNIQUE */ yytestcase(yyruleno==327); + case 393: /* database_kw_opt ::= DATABASE */ yytestcase(yyruleno==393); + case 409: /* kwcolumn_opt ::= */ yytestcase(yyruleno==409); +{yygotominor.yy451 = new bool(true);} break; case 22: /* savepoint_opt ::= */ case 36: /* ifnotexists ::= */ yytestcase(yyruleno==36); case 85: /* autoinc ::= */ yytestcase(yyruleno==85); case 109: /* tconscomma ::= */ yytestcase(yyruleno==109); case 131: /* ifexists ::= */ yytestcase(yyruleno==131); - case 303: /* not_opt ::= */ yytestcase(yyruleno==303); - case 321: /* uniqueflag ::= */ yytestcase(yyruleno==321); - case 387: /* database_kw_opt ::= */ yytestcase(yyruleno==387); - case 403: /* kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==403); -{yygotominor.yy237 = new bool(false);} + case 310: /* not_opt ::= */ yytestcase(yyruleno==310); + case 328: /* uniqueflag ::= */ yytestcase(yyruleno==328); + case 394: /* database_kw_opt ::= */ yytestcase(yyruleno==394); + case 410: /* kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==410); +{yygotominor.yy451 = new bool(false);} break; case 23: /* cmd ::= SAVEPOINT nm */ { - yygotominor.yy399 = new SqliteSavepoint(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteSavepoint(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; case 24: /* cmd ::= RELEASE savepoint_opt nm */ { - yygotominor.yy399 = new SqliteRelease(*(yymsp[-1].minor.yy237), *(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteRelease(*(yymsp[-1].minor.yy451), *(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; case 25: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ case 26: /* cmd ::= SAVEPOINT ID_TRANS */ yytestcase(yyruleno==26); { - yygotominor.yy399 = new SqliteRollback( - yymsp[-3].minor.yy300->transactionKw, - *(yymsp[-1].minor.yy237), - *(yymsp[0].minor.yy211) + yygotominor.yy283 = new SqliteRollback( + yymsp[-3].minor.yy404->transactionKw, + *(yymsp[-1].minor.yy451), + *(yymsp[0].minor.yy399) ); - delete yymsp[-1].minor.yy237; - delete yymsp[-3].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[-1].minor.yy451; + delete yymsp[-3].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 27: /* cmd ::= RELEASE savepoint_opt ID_TRANS */ case 28: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt ID_TRANS */ yytestcase(yyruleno==28); -{ yy_destructor(yypParser,178,&yymsp[-1].minor); +{ yy_destructor(yypParser,180,&yymsp[-1].minor); } break; case 29: /* cmd ::= CREATE temp TABLE ifnotexists fullname LP columnlist conslist_opt RP table_options */ { - yygotominor.yy399 = new SqliteCreateTable( - *(yymsp[-6].minor.yy237), - *(yymsp[-8].minor.yy376), - yymsp[-5].minor.yy66->name1, - yymsp[-5].minor.yy66->name2, - *(yymsp[-3].minor.yy118), - *(yymsp[-2].minor.yy87), - *(yymsp[0].minor.yy211) + yygotominor.yy283 = new SqliteCreateTable( + *(yymsp[-6].minor.yy451), + *(yymsp[-8].minor.yy146), + yymsp[-5].minor.yy360->name1, + yymsp[-5].minor.yy360->name2, + *(yymsp[-3].minor.yy202), + *(yymsp[-2].minor.yy333), + *(yymsp[0].minor.yy399) ); - delete yymsp[-6].minor.yy237; - delete yymsp[-8].minor.yy376; - delete yymsp[-3].minor.yy118; - delete yymsp[-2].minor.yy87; - delete yymsp[-5].minor.yy66; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + delete yymsp[-6].minor.yy451; + delete yymsp[-8].minor.yy146; + delete yymsp[-3].minor.yy202; + delete yymsp[-2].minor.yy333; + delete yymsp[-5].minor.yy360; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; case 30: /* cmd ::= CREATE temp TABLE ifnotexists fullname AS select */ { - yygotominor.yy399 = new SqliteCreateTable( - *(yymsp[-3].minor.yy237), - *(yymsp[-5].minor.yy376), - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, - yymsp[0].minor.yy123 + yygotominor.yy283 = new SqliteCreateTable( + *(yymsp[-3].minor.yy451), + *(yymsp[-5].minor.yy146), + yymsp[-2].minor.yy360->name1, + yymsp[-2].minor.yy360->name2, + yymsp[0].minor.yy473 ); - delete yymsp[-3].minor.yy237; - delete yymsp[-5].minor.yy376; - delete yymsp[-2].minor.yy66; - objectForTokens = yygotominor.yy399; + delete yymsp[-3].minor.yy451; + delete yymsp[-5].minor.yy146; + delete yymsp[-2].minor.yy360; + objectForTokens = yygotominor.yy283; } break; case 31: /* cmd ::= CREATE temp TABLE ifnotexists nm DOT ID_TAB_NEW */ case 133: /* cmd ::= CREATE temp VIEW ifnotexists nm DOT ID_VIEW_NEW */ yytestcase(yyruleno==133); - case 357: /* cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW */ yytestcase(yyruleno==357); -{ yy_destructor(yypParser,179,&yymsp[-5].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 364: /* cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW */ yytestcase(yyruleno==364); +{ yy_destructor(yypParser,181,&yymsp[-5].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; case 32: /* cmd ::= CREATE temp TABLE ifnotexists ID_DB|ID_TAB_NEW */ case 134: /* cmd ::= CREATE temp VIEW ifnotexists ID_DB|ID_VIEW_NEW */ yytestcase(yyruleno==134); - case 358: /* cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW */ yytestcase(yyruleno==358); -{ yy_destructor(yypParser,179,&yymsp[-3].minor); + case 365: /* cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW */ yytestcase(yyruleno==365); +{ yy_destructor(yypParser,181,&yymsp[-3].minor); } break; case 33: /* table_options ::= */ - case 185: /* dbnm ::= */ yytestcase(yyruleno==185); - case 328: /* collate ::= */ yytestcase(yyruleno==328); - case 411: /* vtabarg ::= */ yytestcase(yyruleno==411); - case 415: /* anylist ::= */ yytestcase(yyruleno==415); -{yygotominor.yy211 = new QString();} + case 186: /* dbnm ::= */ yytestcase(yyruleno==186); + case 335: /* collate ::= */ yytestcase(yyruleno==335); + case 418: /* vtabarg ::= */ yytestcase(yyruleno==418); + case 422: /* anylist ::= */ yytestcase(yyruleno==422); +{yygotominor.yy399 = new QString();} break; case 34: /* table_options ::= WITHOUT nm */ case 35: /* table_options ::= WITHOUT CTX_ROWID_KW */ yytestcase(yyruleno==35); { - if (yymsp[0].minor.yy211->toLower() != "rowid") - parserContext->errorAtToken(QString("Invalid table option: %1").arg(*(yymsp[0].minor.yy211))); + if (yymsp[0].minor.yy399->toLower() != "rowid") + parserContext->errorAtToken(QString("Invalid table option: %1").arg(*(yymsp[0].minor.yy399))); - yygotominor.yy211 = yymsp[0].minor.yy211; + yygotominor.yy399 = yymsp[0].minor.yy399; } break; case 38: /* temp ::= TEMP */ -{yygotominor.yy376 = new int( (yymsp[0].minor.yy0->value.length() > 4) ? 2 : 1 );} +{yygotominor.yy146 = new int( (yymsp[0].minor.yy0->value.length() > 4) ? 2 : 1 );} break; case 39: /* temp ::= */ case 154: /* distinct ::= */ yytestcase(yyruleno==154); -{yygotominor.yy376 = new int(0);} +{yygotominor.yy146 = new int(0);} break; case 40: /* columnlist ::= columnlist COMMA column */ { - yymsp[-2].minor.yy118->append(yymsp[0].minor.yy425); - yygotominor.yy118 = yymsp[-2].minor.yy118; + yymsp[-2].minor.yy202->append(yymsp[0].minor.yy227); + yygotominor.yy202 = yymsp[-2].minor.yy202; DONT_INHERIT_TOKENS("columnlist"); } break; case 41: /* columnlist ::= column */ { - yygotominor.yy118 = new ParserCreateTableColumnList(); - yygotominor.yy118->append(yymsp[0].minor.yy425); + yygotominor.yy202 = new ParserCreateTableColumnList(); + yygotominor.yy202->append(yymsp[0].minor.yy227); } break; case 42: /* column ::= columnid type carglist */ { - yygotominor.yy425 = new SqliteCreateTable::Column(*(yymsp[-2].minor.yy211), yymsp[-1].minor.yy299, *(yymsp[0].minor.yy449)); - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy449; - objectForTokens = yygotominor.yy425; + yygotominor.yy227 = new SqliteCreateTable::Column(*(yymsp[-2].minor.yy399), yymsp[-1].minor.yy537, *(yymsp[0].minor.yy51)); + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy51; + objectForTokens = yygotominor.yy227; } break; case 43: /* columnid ::= nm */ case 44: /* columnid ::= ID_COL_NEW */ yytestcase(yyruleno==44); case 47: /* nm ::= id */ yytestcase(yyruleno==47); case 55: /* typename ::= ids */ yytestcase(yyruleno==55); - case 186: /* dbnm ::= DOT nm */ yytestcase(yyruleno==186); - case 329: /* collate ::= COLLATE ids */ yytestcase(yyruleno==329); - case 330: /* collate ::= COLLATE ID_COLLATE */ yytestcase(yyruleno==330); -{yygotominor.yy211 = yymsp[0].minor.yy211;} + case 187: /* dbnm ::= DOT nm */ yytestcase(yyruleno==187); + case 336: /* collate ::= COLLATE ids */ yytestcase(yyruleno==336); + case 337: /* collate ::= COLLATE ID_COLLATE */ yytestcase(yyruleno==337); +{yygotominor.yy399 = yymsp[0].minor.yy399;} break; case 45: /* id ::= ID */ { - yygotominor.yy211 = new QString( + yygotominor.yy399 = new QString( stripObjName( yymsp[0].minor.yy0->value, parserContext->dialect @@ -2989,177 +3039,177 @@ static void yy_reduce( break; case 46: /* ids ::= ID|STRING */ case 49: /* nm ::= JOIN_KW */ yytestcase(yyruleno==49); -{yygotominor.yy211 = new QString(yymsp[0].minor.yy0->value);} +{yygotominor.yy399 = new QString(yymsp[0].minor.yy0->value);} break; case 48: /* nm ::= STRING */ -{yygotominor.yy211 = new QString(stripString(yymsp[0].minor.yy0->value));} +{yygotominor.yy399 = new QString(stripString(yymsp[0].minor.yy0->value));} break; case 50: /* type ::= */ -{yygotominor.yy299 = nullptr;} +{yygotominor.yy537 = nullptr;} break; case 51: /* type ::= typetoken */ -{yygotominor.yy299 = yymsp[0].minor.yy299;} +{yygotominor.yy537 = yymsp[0].minor.yy537;} break; case 52: /* typetoken ::= typename */ { - yygotominor.yy299 = new SqliteColumnType(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy299; + yygotominor.yy537 = new SqliteColumnType(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy537; } break; case 53: /* typetoken ::= typename LP signed RP */ { - yygotominor.yy299 = new SqliteColumnType(*(yymsp[-3].minor.yy211), *(yymsp[-1].minor.yy21)); - delete yymsp[-3].minor.yy211; - delete yymsp[-1].minor.yy21; - objectForTokens = yygotominor.yy299; + yygotominor.yy537 = new SqliteColumnType(*(yymsp[-3].minor.yy399), *(yymsp[-1].minor.yy469)); + delete yymsp[-3].minor.yy399; + delete yymsp[-1].minor.yy469; + objectForTokens = yygotominor.yy537; } break; case 54: /* typetoken ::= typename LP signed COMMA signed RP */ { - yygotominor.yy299 = new SqliteColumnType(*(yymsp[-5].minor.yy211), *(yymsp[-3].minor.yy21), *(yymsp[-1].minor.yy21)); - delete yymsp[-5].minor.yy211; - delete yymsp[-3].minor.yy21; - delete yymsp[-1].minor.yy21; - objectForTokens = yygotominor.yy299; + yygotominor.yy537 = new SqliteColumnType(*(yymsp[-5].minor.yy399), *(yymsp[-3].minor.yy469), *(yymsp[-1].minor.yy469)); + delete yymsp[-5].minor.yy399; + delete yymsp[-3].minor.yy469; + delete yymsp[-1].minor.yy469; + objectForTokens = yygotominor.yy537; } break; case 56: /* typename ::= typename ids */ case 57: /* typename ::= ID_COL_TYPE */ yytestcase(yyruleno==57); { - yymsp[-1].minor.yy211->append(" " + *(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - yygotominor.yy211 = yymsp[-1].minor.yy211; + yymsp[-1].minor.yy399->append(" " + *(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + yygotominor.yy399 = yymsp[-1].minor.yy399; } break; case 58: /* signed ::= plus_num */ case 59: /* signed ::= minus_num */ yytestcase(yyruleno==59); - case 343: /* nmnum ::= plus_num */ yytestcase(yyruleno==343); - case 348: /* plus_num ::= PLUS number */ yytestcase(yyruleno==348); - case 349: /* plus_num ::= number */ yytestcase(yyruleno==349); -{yygotominor.yy21 = yymsp[0].minor.yy21;} + case 350: /* nmnum ::= plus_num */ yytestcase(yyruleno==350); + case 355: /* plus_num ::= PLUS number */ yytestcase(yyruleno==355); + case 356: /* plus_num ::= number */ yytestcase(yyruleno==356); +{yygotominor.yy469 = yymsp[0].minor.yy469;} break; case 60: /* carglist ::= carglist ccons */ { - yymsp[-1].minor.yy449->append(yymsp[0].minor.yy4); - yygotominor.yy449 = yymsp[-1].minor.yy449; + yymsp[-1].minor.yy51->append(yymsp[0].minor.yy304); + yygotominor.yy51 = yymsp[-1].minor.yy51; DONT_INHERIT_TOKENS("carglist"); } break; case 61: /* carglist ::= */ -{yygotominor.yy449 = new ParserCreateTableColumnConstraintList();} +{yygotominor.yy51 = new ParserCreateTableColumnConstraintList();} break; case 62: /* ccons ::= CONSTRAINT nm */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefNameOnly(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefNameOnly(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy304; } break; case 63: /* ccons ::= DEFAULT term */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefTerm(*(yymsp[0].minor.yy21)); - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefTerm(*(yymsp[0].minor.yy469)); + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy304; } break; case 64: /* ccons ::= DEFAULT LP expr RP */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefExpr(yymsp[-1].minor.yy490); - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefExpr(yymsp[-1].minor.yy352); + objectForTokens = yygotominor.yy304; } break; case 65: /* ccons ::= DEFAULT PLUS term */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefTerm(*(yymsp[0].minor.yy21), false); - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefTerm(*(yymsp[0].minor.yy469), false); + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy304; } break; case 66: /* ccons ::= DEFAULT MINUS term */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefTerm(*(yymsp[0].minor.yy21), true); - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefTerm(*(yymsp[0].minor.yy469), true); + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy304; } break; case 67: /* ccons ::= DEFAULT id */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefId(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefId(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy304; } break; case 68: /* ccons ::= DEFAULT CTIME_KW */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefCTime(yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefCTime(yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy304; } break; case 69: /* ccons ::= NULL onconf */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initNull(*(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initNull(*(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; + objectForTokens = yygotominor.yy304; } break; case 70: /* ccons ::= NOT NULL onconf */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initNotNull(*(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initNotNull(*(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; + objectForTokens = yygotominor.yy304; } break; case 71: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initPk(*(yymsp[-2].minor.yy226), *(yymsp[-1].minor.yy30), *(yymsp[0].minor.yy237)); - delete yymsp[-2].minor.yy226; - delete yymsp[0].minor.yy237; - delete yymsp[-1].minor.yy30; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initPk(*(yymsp[-2].minor.yy309), *(yymsp[-1].minor.yy338), *(yymsp[0].minor.yy451)); + delete yymsp[-2].minor.yy309; + delete yymsp[0].minor.yy451; + delete yymsp[-1].minor.yy338; + objectForTokens = yygotominor.yy304; } break; case 72: /* ccons ::= UNIQUE onconf */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initUnique(*(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initUnique(*(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; + objectForTokens = yygotominor.yy304; } break; case 73: /* ccons ::= CHECK LP expr RP */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initCheck(yymsp[-1].minor.yy490); - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initCheck(yymsp[-1].minor.yy352); + objectForTokens = yygotominor.yy304; } break; case 74: /* ccons ::= REFERENCES nm idxlist_opt refargs */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initFk(*(yymsp[-2].minor.yy211), *(yymsp[-1].minor.yy139), *(yymsp[0].minor.yy108)); - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy108; - delete yymsp[-1].minor.yy139; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initFk(*(yymsp[-2].minor.yy399), *(yymsp[-1].minor.yy223), *(yymsp[0].minor.yy184)); + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy184; + delete yymsp[-1].minor.yy223; + objectForTokens = yygotominor.yy304; } break; case 75: /* ccons ::= defer_subclause */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefer(yymsp[0].minor.yy131->initially, yymsp[0].minor.yy131->deferrable); - delete yymsp[0].minor.yy131; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefer(yymsp[0].minor.yy329->initially, yymsp[0].minor.yy329->deferrable); + delete yymsp[0].minor.yy329; + objectForTokens = yygotominor.yy304; } break; case 76: /* ccons ::= COLLATE ids */ @@ -3167,377 +3217,377 @@ static void yy_reduce( case 78: /* ccons ::= COLLATE ID_COLLATE */ yytestcase(yyruleno==78); case 79: /* ccons ::= REFERENCES ID_TAB */ yytestcase(yyruleno==79); { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initColl(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initColl(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy304; } break; case 80: /* ccons ::= CHECK LP RP */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initCheck(); - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initCheck(); + objectForTokens = yygotominor.yy304; parserContext->minorErrorAfterLastToken("Syntax error"); } break; case 81: /* term ::= NULL */ -{yygotominor.yy21 = new QVariant();} +{yygotominor.yy469 = new QVariant();} break; case 82: /* term ::= INTEGER */ - case 351: /* number ::= INTEGER */ yytestcase(yyruleno==351); -{yygotominor.yy21 = parserContext->handleNumberToken(yymsp[0].minor.yy0->value);} + case 358: /* number ::= INTEGER */ yytestcase(yyruleno==358); +{yygotominor.yy469 = parserContext->handleNumberToken(yymsp[0].minor.yy0->value);} break; case 83: /* term ::= FLOAT */ - case 352: /* number ::= FLOAT */ yytestcase(yyruleno==352); -{yygotominor.yy21 = new QVariant(QVariant(yymsp[0].minor.yy0->value).toDouble());} + case 359: /* number ::= FLOAT */ yytestcase(yyruleno==359); +{yygotominor.yy469 = new QVariant(QVariant(yymsp[0].minor.yy0->value).toDouble());} break; case 84: /* term ::= STRING|BLOB */ - case 345: /* nmnum ::= ON */ yytestcase(yyruleno==345); - case 346: /* nmnum ::= DELETE */ yytestcase(yyruleno==346); - case 347: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==347); -{yygotominor.yy21 = new QVariant(yymsp[0].minor.yy0->value);} + case 352: /* nmnum ::= ON */ yytestcase(yyruleno==352); + case 353: /* nmnum ::= DELETE */ yytestcase(yyruleno==353); + case 354: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==354); +{yygotominor.yy469 = new QVariant(yymsp[0].minor.yy0->value);} break; case 87: /* refargs ::= */ -{yygotominor.yy108 = new ParserFkConditionList();} +{yygotominor.yy184 = new ParserFkConditionList();} break; case 88: /* refargs ::= refargs refarg */ { - yymsp[-1].minor.yy108->append(yymsp[0].minor.yy271); - yygotominor.yy108 = yymsp[-1].minor.yy108; + yymsp[-1].minor.yy184->append(yymsp[0].minor.yy347); + yygotominor.yy184 = yymsp[-1].minor.yy184; DONT_INHERIT_TOKENS("refargs"); } break; case 89: /* refarg ::= MATCH nm */ { - yygotominor.yy271 = new SqliteForeignKey::Condition(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; + yygotominor.yy347 = new SqliteForeignKey::Condition(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; } break; case 90: /* refarg ::= ON INSERT refact */ -{yygotominor.yy271 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::INSERT, *(yymsp[0].minor.yy312)); delete yymsp[0].minor.yy312;} +{yygotominor.yy347 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::INSERT, *(yymsp[0].minor.yy104)); delete yymsp[0].minor.yy104;} break; case 91: /* refarg ::= ON DELETE refact */ -{yygotominor.yy271 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::DELETE, *(yymsp[0].minor.yy312)); delete yymsp[0].minor.yy312;} +{yygotominor.yy347 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::DELETE, *(yymsp[0].minor.yy104)); delete yymsp[0].minor.yy104;} break; case 92: /* refarg ::= ON UPDATE refact */ case 93: /* refarg ::= MATCH ID_FK_MATCH */ yytestcase(yyruleno==93); -{yygotominor.yy271 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::UPDATE, *(yymsp[0].minor.yy312)); delete yymsp[0].minor.yy312;} +{yygotominor.yy347 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::UPDATE, *(yymsp[0].minor.yy104)); delete yymsp[0].minor.yy104;} break; case 94: /* refact ::= SET NULL */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_NULL);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_NULL);} break; case 95: /* refact ::= SET DEFAULT */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_DEFAULT);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_DEFAULT);} break; case 96: /* refact ::= CASCADE */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::CASCADE);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::CASCADE);} break; case 97: /* refact ::= RESTRICT */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::RESTRICT);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::RESTRICT);} break; case 98: /* refact ::= NO ACTION */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::NO_ACTION);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::NO_ACTION);} break; case 99: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ { - yygotominor.yy131 = new ParserDeferSubClause(SqliteDeferrable::NOT_DEFERRABLE, *(yymsp[0].minor.yy498)); - delete yymsp[0].minor.yy498; + yygotominor.yy329 = new ParserDeferSubClause(SqliteDeferrable::NOT_DEFERRABLE, *(yymsp[0].minor.yy392)); + delete yymsp[0].minor.yy392; } break; case 100: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ { - yygotominor.yy131 = new ParserDeferSubClause(SqliteDeferrable::DEFERRABLE, *(yymsp[0].minor.yy498)); - delete yymsp[0].minor.yy498; + yygotominor.yy329 = new ParserDeferSubClause(SqliteDeferrable::DEFERRABLE, *(yymsp[0].minor.yy392)); + delete yymsp[0].minor.yy392; } break; case 101: /* init_deferred_pred_opt ::= */ -{yygotominor.yy498 = new SqliteInitially(SqliteInitially::null);} +{yygotominor.yy392 = new SqliteInitially(SqliteInitially::null);} break; case 102: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ -{yygotominor.yy498 = new SqliteInitially(SqliteInitially::DEFERRED);} +{yygotominor.yy392 = new SqliteInitially(SqliteInitially::DEFERRED);} break; case 103: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yygotominor.yy498 = new SqliteInitially(SqliteInitially::IMMEDIATE);} +{yygotominor.yy392 = new SqliteInitially(SqliteInitially::IMMEDIATE);} break; case 104: /* conslist_opt ::= */ -{yygotominor.yy87 = new ParserCreateTableConstraintList();} +{yygotominor.yy333 = new ParserCreateTableConstraintList();} break; case 105: /* conslist_opt ::= COMMA conslist */ -{yygotominor.yy87 = yymsp[0].minor.yy87;} +{yygotominor.yy333 = yymsp[0].minor.yy333;} break; case 106: /* conslist ::= conslist tconscomma tcons */ { - yymsp[0].minor.yy8->afterComma = *(yymsp[-1].minor.yy237); - yymsp[-2].minor.yy87->append(yymsp[0].minor.yy8); - yygotominor.yy87 = yymsp[-2].minor.yy87; - delete yymsp[-1].minor.yy237; + yymsp[0].minor.yy406->afterComma = *(yymsp[-1].minor.yy451); + yymsp[-2].minor.yy333->append(yymsp[0].minor.yy406); + yygotominor.yy333 = yymsp[-2].minor.yy333; + delete yymsp[-1].minor.yy451; DONT_INHERIT_TOKENS("conslist"); } break; case 107: /* conslist ::= tcons */ { - yygotominor.yy87 = new ParserCreateTableConstraintList(); - yygotominor.yy87->append(yymsp[0].minor.yy8); + yygotominor.yy333 = new ParserCreateTableConstraintList(); + yygotominor.yy333->append(yymsp[0].minor.yy406); } break; case 110: /* tcons ::= CONSTRAINT nm */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initNameOnly(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initNameOnly(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy406; } break; case 111: /* tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initPk(*(yymsp[-3].minor.yy139), *(yymsp[-2].minor.yy237), *(yymsp[0].minor.yy30)); - delete yymsp[-2].minor.yy237; - delete yymsp[0].minor.yy30; - delete yymsp[-3].minor.yy139; - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initPk(*(yymsp[-3].minor.yy223), *(yymsp[-2].minor.yy451), *(yymsp[0].minor.yy338)); + delete yymsp[-2].minor.yy451; + delete yymsp[0].minor.yy338; + delete yymsp[-3].minor.yy223; + objectForTokens = yygotominor.yy406; } break; case 112: /* tcons ::= UNIQUE LP idxlist RP onconf */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initUnique(*(yymsp[-2].minor.yy139), *(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; - delete yymsp[-2].minor.yy139; - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initUnique(*(yymsp[-2].minor.yy223), *(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; + delete yymsp[-2].minor.yy223; + objectForTokens = yygotominor.yy406; } break; case 113: /* tcons ::= CHECK LP expr RP onconf */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initCheck(yymsp[-2].minor.yy490, *(yymsp[0].minor.yy30)); - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initCheck(yymsp[-2].minor.yy352, *(yymsp[0].minor.yy338)); + objectForTokens = yygotominor.yy406; } break; case 114: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */ case 115: /* tcons ::= CONSTRAINT ID_CONSTR */ yytestcase(yyruleno==115); case 116: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES ID_TAB */ yytestcase(yyruleno==116); { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initFk( - *(yymsp[-6].minor.yy139), - *(yymsp[-3].minor.yy211), - *(yymsp[-2].minor.yy139), - *(yymsp[-1].minor.yy108), - yymsp[0].minor.yy131->initially, - yymsp[0].minor.yy131->deferrable + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initFk( + *(yymsp[-6].minor.yy223), + *(yymsp[-3].minor.yy399), + *(yymsp[-2].minor.yy223), + *(yymsp[-1].minor.yy184), + yymsp[0].minor.yy329->initially, + yymsp[0].minor.yy329->deferrable ); - delete yymsp[-3].minor.yy211; - delete yymsp[-1].minor.yy108; - delete yymsp[0].minor.yy131; - delete yymsp[-2].minor.yy139; - delete yymsp[-6].minor.yy139; - objectForTokens = yygotominor.yy8; + delete yymsp[-3].minor.yy399; + delete yymsp[-1].minor.yy184; + delete yymsp[0].minor.yy329; + delete yymsp[-2].minor.yy223; + delete yymsp[-6].minor.yy223; + objectForTokens = yygotominor.yy406; } break; case 117: /* tcons ::= CHECK LP RP onconf */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initCheck(); - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initCheck(); + objectForTokens = yygotominor.yy406; parserContext->minorErrorAfterLastToken("Syntax error"); - yy_destructor(yypParser,200,&yymsp[0].minor); + yy_destructor(yypParser,202,&yymsp[0].minor); } break; case 118: /* defer_subclause_opt ::= */ -{yygotominor.yy131 = new ParserDeferSubClause(SqliteDeferrable::null, SqliteInitially::null);} +{yygotominor.yy329 = new ParserDeferSubClause(SqliteDeferrable::null, SqliteInitially::null);} break; case 119: /* defer_subclause_opt ::= defer_subclause */ -{yygotominor.yy131 = yymsp[0].minor.yy131;} +{yygotominor.yy329 = yymsp[0].minor.yy329;} break; case 120: /* onconf ::= */ case 122: /* orconf ::= */ yytestcase(yyruleno==122); -{yygotominor.yy30 = new SqliteConflictAlgo(SqliteConflictAlgo::null);} +{yygotominor.yy338 = new SqliteConflictAlgo(SqliteConflictAlgo::null);} break; case 121: /* onconf ::= ON CONFLICT resolvetype */ case 123: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==123); -{yygotominor.yy30 = yymsp[0].minor.yy30;} +{yygotominor.yy338 = yymsp[0].minor.yy338;} break; case 124: /* resolvetype ::= raisetype */ case 125: /* resolvetype ::= IGNORE */ yytestcase(yyruleno==125); case 126: /* resolvetype ::= REPLACE */ yytestcase(yyruleno==126); -{yygotominor.yy30 = new SqliteConflictAlgo(sqliteConflictAlgo(yymsp[0].minor.yy0->value));} +{yygotominor.yy338 = new SqliteConflictAlgo(sqliteConflictAlgo(yymsp[0].minor.yy0->value));} break; case 127: /* cmd ::= DROP TABLE ifexists fullname */ { - yygotominor.yy399 = new SqliteDropTable(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2); - delete yymsp[-1].minor.yy237; - delete yymsp[0].minor.yy66; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDropTable(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy360->name1, yymsp[0].minor.yy360->name2); + delete yymsp[-1].minor.yy451; + delete yymsp[0].minor.yy360; + objectForTokens = yygotominor.yy283; } break; case 128: /* cmd ::= DROP TABLE ifexists nm DOT ID_TAB */ case 129: /* cmd ::= DROP TABLE ifexists ID_DB|ID_TAB */ yytestcase(yyruleno==129); case 136: /* cmd ::= DROP VIEW ifexists nm DOT ID_VIEW */ yytestcase(yyruleno==136); case 137: /* cmd ::= DROP VIEW ifexists ID_DB|ID_VIEW */ yytestcase(yyruleno==137); - case 178: /* singlesrc ::= nm DOT ID_TAB */ yytestcase(yyruleno==178); - case 179: /* singlesrc ::= ID_DB|ID_TAB */ yytestcase(yyruleno==179); - case 180: /* singlesrc ::= nm DOT ID_VIEW */ yytestcase(yyruleno==180); - case 181: /* singlesrc ::= ID_DB|ID_VIEW */ yytestcase(yyruleno==181); - case 259: /* exprx ::= nm DOT ID_TAB|ID_COL */ yytestcase(yyruleno==259); - case 318: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW */ yytestcase(yyruleno==318); - case 319: /* cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW */ yytestcase(yyruleno==319); - case 332: /* cmd ::= DROP INDEX ifexists nm DOT ID_IDX */ yytestcase(yyruleno==332); - case 333: /* cmd ::= DROP INDEX ifexists ID_DB|ID_IDX */ yytestcase(yyruleno==333); - case 341: /* cmd ::= PRAGMA nm DOT ID_PRAGMA */ yytestcase(yyruleno==341); - case 342: /* cmd ::= PRAGMA ID_DB|ID_PRAGMA */ yytestcase(yyruleno==342); - case 380: /* cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG */ yytestcase(yyruleno==380); - case 381: /* cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG */ yytestcase(yyruleno==381); - case 391: /* cmd ::= REINDEX nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==391); - case 392: /* cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==392); - case 395: /* cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==395); - case 396: /* cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==396); - case 400: /* cmd ::= ALTER TABLE nm DOT ID_TAB */ yytestcase(yyruleno==400); - case 401: /* cmd ::= ALTER TABLE ID_DB|ID_TAB */ yytestcase(yyruleno==401); - case 407: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW */ yytestcase(yyruleno==407); - case 408: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW */ yytestcase(yyruleno==408); -{ yy_destructor(yypParser,177,&yymsp[-2].minor); + case 179: /* singlesrc ::= nm DOT ID_TAB */ yytestcase(yyruleno==179); + case 180: /* singlesrc ::= ID_DB|ID_TAB */ yytestcase(yyruleno==180); + case 181: /* singlesrc ::= nm DOT ID_VIEW */ yytestcase(yyruleno==181); + case 182: /* singlesrc ::= ID_DB|ID_VIEW */ yytestcase(yyruleno==182); + case 266: /* exprx ::= nm DOT ID_TAB|ID_COL */ yytestcase(yyruleno==266); + case 325: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW */ yytestcase(yyruleno==325); + case 326: /* cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW */ yytestcase(yyruleno==326); + case 339: /* cmd ::= DROP INDEX ifexists nm DOT ID_IDX */ yytestcase(yyruleno==339); + case 340: /* cmd ::= DROP INDEX ifexists ID_DB|ID_IDX */ yytestcase(yyruleno==340); + case 348: /* cmd ::= PRAGMA nm DOT ID_PRAGMA */ yytestcase(yyruleno==348); + case 349: /* cmd ::= PRAGMA ID_DB|ID_PRAGMA */ yytestcase(yyruleno==349); + case 387: /* cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG */ yytestcase(yyruleno==387); + case 388: /* cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG */ yytestcase(yyruleno==388); + case 398: /* cmd ::= REINDEX nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==398); + case 399: /* cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==399); + case 402: /* cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==402); + case 403: /* cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==403); + case 407: /* cmd ::= ALTER TABLE nm DOT ID_TAB */ yytestcase(yyruleno==407); + case 408: /* cmd ::= ALTER TABLE ID_DB|ID_TAB */ yytestcase(yyruleno==408); + case 414: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW */ yytestcase(yyruleno==414); + case 415: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW */ yytestcase(yyruleno==415); +{ yy_destructor(yypParser,179,&yymsp[-2].minor); } break; case 132: /* cmd ::= CREATE temp VIEW ifnotexists fullname idxlist_opt AS select */ { - yygotominor.yy399 = new SqliteCreateView(*(yymsp[-6].minor.yy376), *(yymsp[-4].minor.yy237), yymsp[-3].minor.yy66->name1, yymsp[-3].minor.yy66->name2, yymsp[0].minor.yy123, *(yymsp[-2].minor.yy139)); - delete yymsp[-6].minor.yy376; - delete yymsp[-4].minor.yy237; - delete yymsp[-3].minor.yy66; - delete yymsp[-2].minor.yy139; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteCreateView(*(yymsp[-6].minor.yy146), *(yymsp[-4].minor.yy451), yymsp[-3].minor.yy360->name1, yymsp[-3].minor.yy360->name2, yymsp[0].minor.yy473, *(yymsp[-2].minor.yy223)); + delete yymsp[-6].minor.yy146; + delete yymsp[-4].minor.yy451; + delete yymsp[-3].minor.yy360; + delete yymsp[-2].minor.yy223; + objectForTokens = yygotominor.yy283; } break; case 135: /* cmd ::= DROP VIEW ifexists fullname */ { - yygotominor.yy399 = new SqliteDropView(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2); - delete yymsp[-1].minor.yy237; - delete yymsp[0].minor.yy66; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDropView(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy360->name1, yymsp[0].minor.yy360->name2); + delete yymsp[-1].minor.yy451; + delete yymsp[0].minor.yy360; + objectForTokens = yygotominor.yy283; } break; case 138: /* cmd ::= select_stmt */ - case 214: /* cmd ::= delete_stmt */ yytestcase(yyruleno==214); - case 223: /* cmd ::= update_stmt */ yytestcase(yyruleno==223); - case 235: /* cmd ::= insert_stmt */ yytestcase(yyruleno==235); + case 215: /* cmd ::= delete_stmt */ yytestcase(yyruleno==215); + case 224: /* cmd ::= update_stmt */ yytestcase(yyruleno==224); + case 245: /* cmd ::= insert_stmt */ yytestcase(yyruleno==245); { - yygotominor.yy399 = yymsp[0].minor.yy399; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = yymsp[0].minor.yy283; + objectForTokens = yygotominor.yy283; } break; case 139: /* select_stmt ::= select */ { - yygotominor.yy399 = yymsp[0].minor.yy123; + yygotominor.yy283 = yymsp[0].minor.yy473; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; case 140: /* select ::= with selectnowith */ { - yygotominor.yy123 = yymsp[0].minor.yy123; - yymsp[0].minor.yy123->setWith(yymsp[-1].minor.yy367); - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = yymsp[0].minor.yy473; + yymsp[0].minor.yy473->setWith(yymsp[-1].minor.yy321); + objectForTokens = yygotominor.yy473; } break; case 141: /* selectnowith ::= oneselect */ { - yygotominor.yy123 = SqliteSelect::append(yymsp[0].minor.yy468); - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = SqliteSelect::append(yymsp[0].minor.yy310); + objectForTokens = yygotominor.yy473; } break; case 142: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - yygotominor.yy123 = SqliteSelect::append(yymsp[-2].minor.yy123, *(yymsp[-1].minor.yy168), yymsp[0].minor.yy468); - delete yymsp[-1].minor.yy168; - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = SqliteSelect::append(yymsp[-2].minor.yy473, *(yymsp[-1].minor.yy462), yymsp[0].minor.yy310); + delete yymsp[-1].minor.yy462; + objectForTokens = yygotominor.yy473; } break; case 143: /* selectnowith ::= values */ { - yygotominor.yy123 = SqliteSelect::append(*(yymsp[0].minor.yy416)); - delete yymsp[0].minor.yy416; - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = SqliteSelect::append(*(yymsp[0].minor.yy166)); + delete yymsp[0].minor.yy166; + objectForTokens = yygotominor.yy473; } break; case 144: /* selectnowith ::= selectnowith COMMA values */ { - yygotominor.yy123 = SqliteSelect::append(yymsp[-2].minor.yy123, SqliteSelect::CompoundOperator::UNION_ALL, *(yymsp[0].minor.yy416)); - delete yymsp[0].minor.yy416; - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = SqliteSelect::append(yymsp[-2].minor.yy473, SqliteSelect::CompoundOperator::UNION_ALL, *(yymsp[0].minor.yy166)); + delete yymsp[0].minor.yy166; + objectForTokens = yygotominor.yy473; } break; - case 145: /* multiselect_op ::= UNION */ -{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);} - break; - case 146: /* multiselect_op ::= UNION ALL */ -{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);} - break; - case 147: /* multiselect_op ::= EXCEPT */ -{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);} - break; - case 148: /* multiselect_op ::= INTERSECT */ -{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);} - break; - case 149: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + case 145: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { - yygotominor.yy468 = new SqliteSelect::Core( - *(yymsp[-7].minor.yy376), - *(yymsp[-6].minor.yy263), - yymsp[-5].minor.yy373, - yymsp[-4].minor.yy490, - *(yymsp[-3].minor.yy13), - yymsp[-2].minor.yy490, - *(yymsp[-1].minor.yy495), - yymsp[0].minor.yy128 + yygotominor.yy310 = new SqliteSelect::Core( + *(yymsp[-7].minor.yy146), + *(yymsp[-6].minor.yy373), + yymsp[-5].minor.yy511, + yymsp[-4].minor.yy352, + *(yymsp[-3].minor.yy551), + yymsp[-2].minor.yy352, + *(yymsp[-1].minor.yy163), + yymsp[0].minor.yy484 ); - delete yymsp[-6].minor.yy263; - delete yymsp[-7].minor.yy376; - delete yymsp[-3].minor.yy13; - delete yymsp[-1].minor.yy495; - objectForTokens = yygotominor.yy468; + delete yymsp[-6].minor.yy373; + delete yymsp[-7].minor.yy146; + delete yymsp[-3].minor.yy551; + delete yymsp[-1].minor.yy163; + objectForTokens = yygotominor.yy310; } break; - case 150: /* values ::= VALUES LP nexprlist RP */ + case 146: /* values ::= VALUES LP nexprlist RP */ { - yygotominor.yy416 = new ParserExprNestedList(); - yygotominor.yy416->append(*(yymsp[-1].minor.yy13)); - delete yymsp[-1].minor.yy13; + yygotominor.yy166 = new ParserExprNestedList(); + yygotominor.yy166->append(*(yymsp[-1].minor.yy551)); + delete yymsp[-1].minor.yy551; } break; - case 151: /* values ::= values COMMA LP exprlist RP */ + case 147: /* values ::= values COMMA LP exprlist RP */ { - yymsp[-4].minor.yy416->append(*(yymsp[-1].minor.yy13)); - yygotominor.yy416 = yymsp[-4].minor.yy416; - delete yymsp[-1].minor.yy13; + yymsp[-4].minor.yy166->append(*(yymsp[-1].minor.yy551)); + yygotominor.yy166 = yymsp[-4].minor.yy166; + delete yymsp[-1].minor.yy551; DONT_INHERIT_TOKENS("values"); } break; + case 148: /* multiselect_op ::= UNION */ +{yygotominor.yy462 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);} + break; + case 149: /* multiselect_op ::= UNION ALL */ +{yygotominor.yy462 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);} + break; + case 150: /* multiselect_op ::= EXCEPT */ +{yygotominor.yy462 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);} + break; + case 151: /* multiselect_op ::= INTERSECT */ +{yygotominor.yy462 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);} + break; case 152: /* distinct ::= DISTINCT */ -{yygotominor.yy376 = new int(1);} +{yygotominor.yy146 = new int(1);} break; case 153: /* distinct ::= ALL */ -{yygotominor.yy376 = new int(2);} +{yygotominor.yy146 = new int(2);} break; case 155: /* sclp ::= selcollist COMMA */ -{yygotominor.yy263 = yymsp[-1].minor.yy263;} +{yygotominor.yy373 = yymsp[-1].minor.yy373;} break; case 156: /* sclp ::= */ -{yygotominor.yy263 = new ParserResultColumnList();} +{yygotominor.yy373 = new ParserResultColumnList();} break; case 157: /* selcollist ::= sclp expr as */ { SqliteSelect::Core::ResultColumn* obj = new SqliteSelect::Core::ResultColumn( - yymsp[-1].minor.yy490, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->asKw : false, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->name : QString::null + yymsp[-1].minor.yy352, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->asKw : false, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->name : QString::null ); - yymsp[-2].minor.yy263->append(obj); - yygotominor.yy263 = yymsp[-2].minor.yy263; - delete yymsp[0].minor.yy28; + yymsp[-2].minor.yy373->append(obj); + yygotominor.yy373 = yymsp[-2].minor.yy373; + delete yymsp[0].minor.yy200; objectForTokens = obj; DONT_INHERIT_TOKENS("sclp"); } @@ -3547,8 +3597,8 @@ static void yy_reduce( SqliteSelect::Core::ResultColumn* obj = new SqliteSelect::Core::ResultColumn(true); - yymsp[-1].minor.yy263->append(obj); - yygotominor.yy263 = yymsp[-1].minor.yy263; + yymsp[-1].minor.yy373->append(obj); + yygotominor.yy373 = yymsp[-1].minor.yy373; objectForTokens = obj; DONT_INHERIT_TOKENS("sclp"); } @@ -3558,11 +3608,11 @@ static void yy_reduce( SqliteSelect::Core::ResultColumn* obj = new SqliteSelect::Core::ResultColumn( true, - *(yymsp[-2].minor.yy211) + *(yymsp[-2].minor.yy399) ); - yymsp[-3].minor.yy263->append(obj); - yygotominor.yy263 = yymsp[-3].minor.yy263; - delete yymsp[-2].minor.yy211; + yymsp[-3].minor.yy373->append(obj); + yygotominor.yy373 = yymsp[-3].minor.yy373; + delete yymsp[-2].minor.yy399; objectForTokens = obj; DONT_INHERIT_TOKENS("sclp"); } @@ -3571,1382 +3621,1439 @@ static void yy_reduce( case 161: /* selcollist ::= sclp ID_TAB DOT STAR */ yytestcase(yyruleno==161); { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy263 = yymsp[0].minor.yy263; + yygotominor.yy373 = yymsp[0].minor.yy373; } break; case 162: /* as ::= AS nm */ { - yygotominor.yy28 = new ParserStubAlias(*(yymsp[0].minor.yy211), true); - delete yymsp[0].minor.yy211; + yygotominor.yy200 = new ParserStubAlias(*(yymsp[0].minor.yy399), true); + delete yymsp[0].minor.yy399; } break; case 163: /* as ::= ids */ case 164: /* as ::= AS ID_ALIAS */ yytestcase(yyruleno==164); case 165: /* as ::= ID_ALIAS */ yytestcase(yyruleno==165); { - yygotominor.yy28 = new ParserStubAlias(*(yymsp[0].minor.yy211), false); - delete yymsp[0].minor.yy211; + yygotominor.yy200 = new ParserStubAlias(*(yymsp[0].minor.yy399), false); + delete yymsp[0].minor.yy399; } break; case 166: /* as ::= */ -{yygotominor.yy28 = nullptr;} +{yygotominor.yy200 = nullptr;} break; case 167: /* from ::= */ -{yygotominor.yy373 = nullptr;} +{yygotominor.yy511 = nullptr;} break; case 168: /* from ::= FROM joinsrc */ -{yygotominor.yy373 = yymsp[0].minor.yy373;} +{yygotominor.yy511 = yymsp[0].minor.yy511;} break; case 169: /* joinsrc ::= singlesrc seltablist */ { - yygotominor.yy373 = new SqliteSelect::Core::JoinSource( - yymsp[-1].minor.yy173, - *(yymsp[0].minor.yy359) + yygotominor.yy511 = new SqliteSelect::Core::JoinSource( + yymsp[-1].minor.yy201, + *(yymsp[0].minor.yy131) ); - delete yymsp[0].minor.yy359; - objectForTokens = yygotominor.yy373; + delete yymsp[0].minor.yy131; + objectForTokens = yygotominor.yy511; } break; case 170: /* joinsrc ::= */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy373 = new SqliteSelect::Core::JoinSource(); - objectForTokens = yygotominor.yy373; + yygotominor.yy511 = new SqliteSelect::Core::JoinSource(); + objectForTokens = yygotominor.yy511; } break; case 171: /* seltablist ::= seltablist joinop singlesrc joinconstr_opt */ { SqliteSelect::Core::JoinSourceOther* src = - new SqliteSelect::Core::JoinSourceOther(yymsp[-2].minor.yy473, yymsp[-1].minor.yy173, yymsp[0].minor.yy117); + new SqliteSelect::Core::JoinSourceOther(yymsp[-2].minor.yy301, yymsp[-1].minor.yy201, yymsp[0].minor.yy295); - yymsp[-3].minor.yy359->append(src); - yygotominor.yy359 = yymsp[-3].minor.yy359; + yymsp[-3].minor.yy131->append(src); + yygotominor.yy131 = yymsp[-3].minor.yy131; objectForTokens = src; DONT_INHERIT_TOKENS("seltablist"); } break; case 172: /* seltablist ::= */ { - yygotominor.yy359 = new ParserOtherSourceList(); + yygotominor.yy131 = new ParserOtherSourceList(); } break; case 173: /* singlesrc ::= nm dbnm as indexed_opt */ { - yygotominor.yy173 = new SqliteSelect::Core::SingleSource( - *(yymsp[-3].minor.yy211), - *(yymsp[-2].minor.yy211), - yymsp[-1].minor.yy28 ? yymsp[-1].minor.yy28->asKw : false, - yymsp[-1].minor.yy28 ? yymsp[-1].minor.yy28->name : QString::null, - yymsp[0].minor.yy472 ? yymsp[0].minor.yy472->notIndexedKw : false, - yymsp[0].minor.yy472 ? yymsp[0].minor.yy472->indexedBy : QString::null + yygotominor.yy201 = new SqliteSelect::Core::SingleSource( + *(yymsp[-3].minor.yy399), + *(yymsp[-2].minor.yy399), + yymsp[-1].minor.yy200 ? yymsp[-1].minor.yy200->asKw : false, + yymsp[-1].minor.yy200 ? yymsp[-1].minor.yy200->name : QString::null, + yymsp[0].minor.yy192 ? yymsp[0].minor.yy192->notIndexedKw : false, + yymsp[0].minor.yy192 ? yymsp[0].minor.yy192->indexedBy : QString::null ); - delete yymsp[-3].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[-1].minor.yy28; - if (yymsp[0].minor.yy472) - delete yymsp[0].minor.yy472; - objectForTokens = yygotominor.yy173; + delete yymsp[-3].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[-1].minor.yy200; + if (yymsp[0].minor.yy192) + delete yymsp[0].minor.yy192; + objectForTokens = yygotominor.yy201; } break; case 174: /* singlesrc ::= LP select RP as */ { - yygotominor.yy173 = new SqliteSelect::Core::SingleSource( - yymsp[-2].minor.yy123, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->asKw : false, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->name : QString::null + yygotominor.yy201 = new SqliteSelect::Core::SingleSource( + yymsp[-2].minor.yy473, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->asKw : false, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->name : QString::null ); - delete yymsp[0].minor.yy28; - objectForTokens = yygotominor.yy173; + delete yymsp[0].minor.yy200; + objectForTokens = yygotominor.yy201; } break; case 175: /* singlesrc ::= LP joinsrc RP as */ { - yygotominor.yy173 = new SqliteSelect::Core::SingleSource( - yymsp[-2].minor.yy373, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->asKw : false, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->name : QString::null + yygotominor.yy201 = new SqliteSelect::Core::SingleSource( + yymsp[-2].minor.yy511, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->asKw : false, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->name : QString::null ); - delete yymsp[0].minor.yy28; - objectForTokens = yygotominor.yy173; + delete yymsp[0].minor.yy200; + objectForTokens = yygotominor.yy201; } break; - case 176: /* singlesrc ::= */ + case 176: /* singlesrc ::= nm dbnm LP exprlist RP as */ +{ + yygotominor.yy201 = new SqliteSelect::Core::SingleSource( + *(yymsp[-5].minor.yy399), + *(yymsp[-4].minor.yy399), + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->asKw : false, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->name : QString::null, + *(yymsp[-2].minor.yy551) + ); + delete yymsp[-5].minor.yy399; + delete yymsp[-4].minor.yy399; + delete yymsp[0].minor.yy200; + if (yymsp[-2].minor.yy551) + delete yymsp[-2].minor.yy551; + + objectForTokens = yygotominor.yy201; + } + break; + case 177: /* singlesrc ::= */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy173 = new SqliteSelect::Core::SingleSource(); - objectForTokens = yygotominor.yy173; + yygotominor.yy201 = new SqliteSelect::Core::SingleSource(); + objectForTokens = yygotominor.yy201; } break; - case 177: /* singlesrc ::= nm DOT */ + case 178: /* singlesrc ::= nm DOT */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy173 = new SqliteSelect::Core::SingleSource(); - yygotominor.yy173->database = *(yymsp[-1].minor.yy211); - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy173; + yygotominor.yy201 = new SqliteSelect::Core::SingleSource(); + yygotominor.yy201->database = *(yymsp[-1].minor.yy399); + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy201; } break; - case 182: /* joinconstr_opt ::= ON expr */ + case 183: /* joinconstr_opt ::= ON expr */ { - yygotominor.yy117 = new SqliteSelect::Core::JoinConstraint(yymsp[0].minor.yy490); - objectForTokens = yygotominor.yy117; + yygotominor.yy295 = new SqliteSelect::Core::JoinConstraint(yymsp[0].minor.yy352); + objectForTokens = yygotominor.yy295; } break; - case 183: /* joinconstr_opt ::= USING LP inscollist RP */ + case 184: /* joinconstr_opt ::= USING LP idlist RP */ { - yygotominor.yy117 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy445)); - delete yymsp[-1].minor.yy445; - objectForTokens = yygotominor.yy117; + yygotominor.yy295 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy95)); + delete yymsp[-1].minor.yy95; + objectForTokens = yygotominor.yy295; } break; - case 184: /* joinconstr_opt ::= */ -{yygotominor.yy117 = nullptr;} + case 185: /* joinconstr_opt ::= */ +{yygotominor.yy295 = nullptr;} break; - case 187: /* fullname ::= nm dbnm */ + case 188: /* fullname ::= nm dbnm */ { - yygotominor.yy66 = new ParserFullName(); - yygotominor.yy66->name1 = *(yymsp[-1].minor.yy211); - yygotominor.yy66->name2 = *(yymsp[0].minor.yy211); - delete yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; + yygotominor.yy360 = new ParserFullName(); + yygotominor.yy360->name1 = *(yymsp[-1].minor.yy399); + yygotominor.yy360->name2 = *(yymsp[0].minor.yy399); + delete yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; } break; - case 188: /* joinop ::= COMMA */ + case 189: /* joinop ::= COMMA */ { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(true); - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(true); + objectForTokens = yygotominor.yy301; } break; - case 189: /* joinop ::= JOIN */ + case 190: /* joinop ::= JOIN */ { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(false); - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(false); + objectForTokens = yygotominor.yy301; } break; - case 190: /* joinop ::= JOIN_KW JOIN */ + case 191: /* joinop ::= JOIN_KW JOIN */ { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(yymsp[-1].minor.yy0->value); - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(yymsp[-1].minor.yy0->value); + objectForTokens = yygotominor.yy301; } break; - case 191: /* joinop ::= JOIN_KW nm JOIN */ + case 192: /* joinop ::= JOIN_KW nm JOIN */ { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(yymsp[-2].minor.yy0->value, *(yymsp[-1].minor.yy211)); - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(yymsp[-2].minor.yy0->value, *(yymsp[-1].minor.yy399)); + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy301; } break; - case 192: /* joinop ::= JOIN_KW nm nm JOIN */ - case 193: /* joinop ::= ID_JOIN_OPTS */ yytestcase(yyruleno==193); + case 193: /* joinop ::= JOIN_KW nm nm JOIN */ + case 194: /* joinop ::= ID_JOIN_OPTS */ yytestcase(yyruleno==194); { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(yymsp[-3].minor.yy0->value, *(yymsp[-2].minor.yy211), *(yymsp[-1].minor.yy211)); - delete yymsp[-2].minor.yy211; - delete yymsp[-2].minor.yy211; - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(yymsp[-3].minor.yy0->value, *(yymsp[-2].minor.yy399), *(yymsp[-1].minor.yy399)); + delete yymsp[-2].minor.yy399; + delete yymsp[-2].minor.yy399; + objectForTokens = yygotominor.yy301; } break; - case 194: /* indexed_opt ::= */ -{yygotominor.yy472 = nullptr;} + case 195: /* indexed_opt ::= */ +{yygotominor.yy192 = nullptr;} break; - case 195: /* indexed_opt ::= INDEXED BY nm */ + case 196: /* indexed_opt ::= INDEXED BY nm */ { - yygotominor.yy472 = new ParserIndexedBy(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; + yygotominor.yy192 = new ParserIndexedBy(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; } break; - case 196: /* indexed_opt ::= NOT INDEXED */ - case 197: /* indexed_opt ::= INDEXED BY ID_IDX */ yytestcase(yyruleno==197); -{yygotominor.yy472 = new ParserIndexedBy(true);} + case 197: /* indexed_opt ::= NOT INDEXED */ + case 198: /* indexed_opt ::= INDEXED BY ID_IDX */ yytestcase(yyruleno==198); +{yygotominor.yy192 = new ParserIndexedBy(true);} break; - case 198: /* orderby_opt ::= */ -{yygotominor.yy495 = new ParserOrderByList();} + case 199: /* orderby_opt ::= */ +{yygotominor.yy163 = new ParserOrderByList();} break; - case 199: /* orderby_opt ::= ORDER BY sortlist */ -{yygotominor.yy495 = yymsp[0].minor.yy495;} + case 200: /* orderby_opt ::= ORDER BY sortlist */ +{yygotominor.yy163 = yymsp[0].minor.yy163;} break; - case 200: /* sortlist ::= sortlist COMMA expr sortorder */ + case 201: /* sortlist ::= sortlist COMMA expr sortorder */ { - SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy490, *(yymsp[0].minor.yy226)); - yymsp[-3].minor.yy495->append(obj); - yygotominor.yy495 = yymsp[-3].minor.yy495; - delete yymsp[0].minor.yy226; + SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy352, *(yymsp[0].minor.yy309)); + yymsp[-3].minor.yy163->append(obj); + yygotominor.yy163 = yymsp[-3].minor.yy163; + delete yymsp[0].minor.yy309; objectForTokens = obj; DONT_INHERIT_TOKENS("sortlist"); } break; - case 201: /* sortlist ::= expr sortorder */ + case 202: /* sortlist ::= expr sortorder */ { - SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy490, *(yymsp[0].minor.yy226)); - yygotominor.yy495 = new ParserOrderByList(); - yygotominor.yy495->append(obj); - delete yymsp[0].minor.yy226; + SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy352, *(yymsp[0].minor.yy309)); + yygotominor.yy163 = new ParserOrderByList(); + yygotominor.yy163->append(obj); + delete yymsp[0].minor.yy309; objectForTokens = obj; } break; - case 202: /* sortorder ::= ASC */ -{yygotominor.yy226 = new SqliteSortOrder(SqliteSortOrder::ASC);} + case 203: /* sortorder ::= ASC */ +{yygotominor.yy309 = new SqliteSortOrder(SqliteSortOrder::ASC);} break; - case 203: /* sortorder ::= DESC */ -{yygotominor.yy226 = new SqliteSortOrder(SqliteSortOrder::DESC);} + case 204: /* sortorder ::= DESC */ +{yygotominor.yy309 = new SqliteSortOrder(SqliteSortOrder::DESC);} break; - case 204: /* sortorder ::= */ -{yygotominor.yy226 = new SqliteSortOrder(SqliteSortOrder::null);} + case 205: /* sortorder ::= */ +{yygotominor.yy309 = new SqliteSortOrder(SqliteSortOrder::null);} break; - case 205: /* groupby_opt ::= */ - case 313: /* exprlist ::= */ yytestcase(yyruleno==313); -{yygotominor.yy13 = new ParserExprList();} + case 206: /* groupby_opt ::= */ + case 320: /* exprlist ::= */ yytestcase(yyruleno==320); +{yygotominor.yy551 = new ParserExprList();} break; - case 206: /* groupby_opt ::= GROUP BY nexprlist */ - case 312: /* exprlist ::= nexprlist */ yytestcase(yyruleno==312); -{yygotominor.yy13 = yymsp[0].minor.yy13;} + case 207: /* groupby_opt ::= GROUP BY nexprlist */ + case 319: /* exprlist ::= nexprlist */ yytestcase(yyruleno==319); +{yygotominor.yy551 = yymsp[0].minor.yy551;} break; - case 207: /* groupby_opt ::= GROUP BY */ + case 208: /* groupby_opt ::= GROUP BY */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy13 = new ParserExprList(); + yygotominor.yy551 = new ParserExprList(); } break; - case 208: /* having_opt ::= */ - case 220: /* where_opt ::= */ yytestcase(yyruleno==220); - case 309: /* case_else ::= */ yytestcase(yyruleno==309); - case 311: /* case_operand ::= */ yytestcase(yyruleno==311); - case 369: /* when_clause ::= */ yytestcase(yyruleno==369); - case 384: /* key_opt ::= */ yytestcase(yyruleno==384); -{yygotominor.yy490 = nullptr;} + case 209: /* having_opt ::= */ + case 221: /* where_opt ::= */ yytestcase(yyruleno==221); + case 316: /* case_else ::= */ yytestcase(yyruleno==316); + case 318: /* case_operand ::= */ yytestcase(yyruleno==318); + case 376: /* when_clause ::= */ yytestcase(yyruleno==376); + case 391: /* key_opt ::= */ yytestcase(yyruleno==391); +{yygotominor.yy352 = nullptr;} break; - case 209: /* having_opt ::= HAVING expr */ - case 221: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==221); - case 302: /* expr ::= exprx */ yytestcase(yyruleno==302); - case 308: /* case_else ::= ELSE expr */ yytestcase(yyruleno==308); - case 310: /* case_operand ::= exprx */ yytestcase(yyruleno==310); - case 370: /* when_clause ::= WHEN expr */ yytestcase(yyruleno==370); - case 385: /* key_opt ::= KEY expr */ yytestcase(yyruleno==385); -{yygotominor.yy490 = yymsp[0].minor.yy490;} + case 210: /* having_opt ::= HAVING expr */ + case 222: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==222); + case 309: /* expr ::= exprx */ yytestcase(yyruleno==309); + case 315: /* case_else ::= ELSE expr */ yytestcase(yyruleno==315); + case 317: /* case_operand ::= exprx */ yytestcase(yyruleno==317); + case 377: /* when_clause ::= WHEN expr */ yytestcase(yyruleno==377); + case 392: /* key_opt ::= KEY expr */ yytestcase(yyruleno==392); +{yygotominor.yy352 = yymsp[0].minor.yy352;} break; - case 210: /* limit_opt ::= */ -{yygotominor.yy128 = nullptr;} + case 211: /* limit_opt ::= */ +{yygotominor.yy484 = nullptr;} break; - case 211: /* limit_opt ::= LIMIT expr */ + case 212: /* limit_opt ::= LIMIT expr */ { - yygotominor.yy128 = new SqliteLimit(yymsp[0].minor.yy490); - objectForTokens = yygotominor.yy128; + yygotominor.yy484 = new SqliteLimit(yymsp[0].minor.yy352); + objectForTokens = yygotominor.yy484; } break; - case 212: /* limit_opt ::= LIMIT expr OFFSET expr */ + case 213: /* limit_opt ::= LIMIT expr OFFSET expr */ { - yygotominor.yy128 = new SqliteLimit(yymsp[-2].minor.yy490, yymsp[0].minor.yy490, true); - objectForTokens = yygotominor.yy128; + yygotominor.yy484 = new SqliteLimit(yymsp[-2].minor.yy352, yymsp[0].minor.yy352, true); + objectForTokens = yygotominor.yy484; } break; - case 213: /* limit_opt ::= LIMIT expr COMMA expr */ + case 214: /* limit_opt ::= LIMIT expr COMMA expr */ { - yygotominor.yy128 = new SqliteLimit(yymsp[-2].minor.yy490, yymsp[0].minor.yy490, false); - objectForTokens = yygotominor.yy128; + yygotominor.yy484 = new SqliteLimit(yymsp[-2].minor.yy352, yymsp[0].minor.yy352, false); + objectForTokens = yygotominor.yy484; } break; - case 215: /* delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt */ + case 216: /* delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt */ { - if (yymsp[-1].minor.yy472) + if (yymsp[-1].minor.yy192) { - if (!yymsp[-1].minor.yy472->indexedBy.isNull()) + if (!yymsp[-1].minor.yy192->indexedBy.isNull()) { - yygotominor.yy399 = new SqliteDelete( - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, - yymsp[-1].minor.yy472->indexedBy, - yymsp[0].minor.yy490, - yymsp[-5].minor.yy367 + yygotominor.yy283 = new SqliteDelete( + yymsp[-2].minor.yy360->name1, + yymsp[-2].minor.yy360->name2, + yymsp[-1].minor.yy192->indexedBy, + yymsp[0].minor.yy352, + yymsp[-5].minor.yy321 ); } else { - yygotominor.yy399 = new SqliteDelete( - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, - yymsp[-1].minor.yy472->notIndexedKw, - yymsp[0].minor.yy490, - yymsp[-5].minor.yy367 + yygotominor.yy283 = new SqliteDelete( + yymsp[-2].minor.yy360->name1, + yymsp[-2].minor.yy360->name2, + yymsp[-1].minor.yy192->notIndexedKw, + yymsp[0].minor.yy352, + yymsp[-5].minor.yy321 ); } - delete yymsp[-1].minor.yy472; + delete yymsp[-1].minor.yy192; } else { - yygotominor.yy399 = new SqliteDelete( - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, + yygotominor.yy283 = new SqliteDelete( + yymsp[-2].minor.yy360->name1, + yymsp[-2].minor.yy360->name2, false, - yymsp[0].minor.yy490, - yymsp[-5].minor.yy367 + yymsp[0].minor.yy352, + yymsp[-5].minor.yy321 ); } - delete yymsp[-2].minor.yy66; + delete yymsp[-2].minor.yy360; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 216: /* delete_stmt ::= with DELETE FROM */ + case 217: /* delete_stmt ::= with DELETE FROM */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteDelete* q = new SqliteDelete(); - q->with = yymsp[-2].minor.yy367; - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; + q->with = yymsp[-2].minor.yy321; + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; } break; - case 217: /* delete_stmt ::= with DELETE FROM nm DOT */ + case 218: /* delete_stmt ::= with DELETE FROM nm DOT */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteDelete* q = new SqliteDelete(); - q->with = yymsp[-4].minor.yy367; - q->database = *(yymsp[-1].minor.yy211); - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[-1].minor.yy211; + q->with = yymsp[-4].minor.yy321; + q->database = *(yymsp[-1].minor.yy399); + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[-1].minor.yy399; } break; - case 218: /* delete_stmt ::= with DELETE FROM nm DOT ID_TAB */ - case 227: /* update_stmt ::= with UPDATE orconf nm DOT ID_TAB */ yytestcase(yyruleno==227); -{ yy_destructor(yypParser,219,&yymsp[-5].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 219: /* delete_stmt ::= with DELETE FROM nm DOT ID_TAB */ + case 228: /* update_stmt ::= with UPDATE orconf nm DOT ID_TAB */ yytestcase(yyruleno==228); +{ yy_destructor(yypParser,221,&yymsp[-5].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; - case 219: /* delete_stmt ::= with DELETE FROM ID_DB|ID_TAB */ - case 228: /* update_stmt ::= with UPDATE orconf ID_DB|ID_TAB */ yytestcase(yyruleno==228); -{ yy_destructor(yypParser,219,&yymsp[-3].minor); + case 220: /* delete_stmt ::= with DELETE FROM ID_DB|ID_TAB */ + case 229: /* update_stmt ::= with UPDATE orconf ID_DB|ID_TAB */ yytestcase(yyruleno==229); +{ yy_destructor(yypParser,221,&yymsp[-3].minor); } break; - case 222: /* where_opt ::= WHERE */ + case 223: /* where_opt ::= WHERE */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy490 = new SqliteExpr(); + yygotominor.yy352 = new SqliteExpr(); } break; - case 224: /* update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ + case 225: /* update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ { - yygotominor.yy399 = new SqliteUpdate( - *(yymsp[-5].minor.yy30), - yymsp[-4].minor.yy66->name1, - yymsp[-4].minor.yy66->name2, - yymsp[-3].minor.yy472 ? yymsp[-3].minor.yy472->notIndexedKw : false, - yymsp[-3].minor.yy472 ? yymsp[-3].minor.yy472->indexedBy : QString::null, - *(yymsp[-1].minor.yy381), - yymsp[0].minor.yy490, - yymsp[-7].minor.yy367 + yygotominor.yy283 = new SqliteUpdate( + *(yymsp[-5].minor.yy338), + yymsp[-4].minor.yy360->name1, + yymsp[-4].minor.yy360->name2, + yymsp[-3].minor.yy192 ? yymsp[-3].minor.yy192->notIndexedKw : false, + yymsp[-3].minor.yy192 ? yymsp[-3].minor.yy192->indexedBy : QString::null, + *(yymsp[-1].minor.yy521), + yymsp[0].minor.yy352, + yymsp[-7].minor.yy321 ); - delete yymsp[-5].minor.yy30; - delete yymsp[-4].minor.yy66; - delete yymsp[-1].minor.yy381; - if (yymsp[-3].minor.yy472) - delete yymsp[-3].minor.yy472; + delete yymsp[-5].minor.yy338; + delete yymsp[-4].minor.yy360; + delete yymsp[-1].minor.yy521; + if (yymsp[-3].minor.yy192) + delete yymsp[-3].minor.yy192; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 225: /* update_stmt ::= with UPDATE orconf */ + case 226: /* update_stmt ::= with UPDATE orconf */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteUpdate* q = new SqliteUpdate(); - q->with = yymsp[-2].minor.yy367; - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[0].minor.yy30; + q->with = yymsp[-2].minor.yy321; + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[0].minor.yy338; } break; - case 226: /* update_stmt ::= with UPDATE orconf nm DOT */ + case 227: /* update_stmt ::= with UPDATE orconf nm DOT */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteUpdate* q = new SqliteUpdate(); - q->with = yymsp[-4].minor.yy367; - q->database = *(yymsp[-1].minor.yy211); - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[-2].minor.yy30; - delete yymsp[-1].minor.yy211; + q->with = yymsp[-4].minor.yy321; + q->database = *(yymsp[-1].minor.yy399); + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[-2].minor.yy338; + delete yymsp[-1].minor.yy399; } break; - case 229: /* setlist ::= setlist COMMA nm EQ expr */ + case 230: /* setlist ::= setlist COMMA nm EQ expr */ { - yymsp[-4].minor.yy381->append(ParserSetValue(*(yymsp[-2].minor.yy211), yymsp[0].minor.yy490)); - yygotominor.yy381 = yymsp[-4].minor.yy381; - delete yymsp[-2].minor.yy211; - DONT_INHERIT_TOKENS("setlist"); + yymsp[-4].minor.yy521->append(ParserSetValue(*(yymsp[-2].minor.yy399), yymsp[0].minor.yy352)); + yygotominor.yy521 = yymsp[-4].minor.yy521; + delete yymsp[-2].minor.yy399; } break; - case 230: /* setlist ::= nm EQ expr */ + case 231: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { - yygotominor.yy381 = new ParserSetValueList(); - yygotominor.yy381->append(ParserSetValue(*(yymsp[-2].minor.yy211), yymsp[0].minor.yy490)); - delete yymsp[-2].minor.yy211; + yymsp[-6].minor.yy521->append(ParserSetValue(*(yymsp[-3].minor.yy95), yymsp[0].minor.yy352)); + yygotominor.yy521 = yymsp[-6].minor.yy521; + delete yymsp[-3].minor.yy95; } break; - case 231: /* setlist ::= */ + case 232: /* setlist ::= nm EQ expr */ +{ + yygotominor.yy521 = new ParserSetValueList(); + yygotominor.yy521->append(ParserSetValue(*(yymsp[-2].minor.yy399), yymsp[0].minor.yy352)); + delete yymsp[-2].minor.yy399; + } + break; + case 233: /* setlist ::= LP idlist RP EQ expr */ +{ + yygotominor.yy521 = new ParserSetValueList(); + yygotominor.yy521->append(ParserSetValue(*(yymsp[-3].minor.yy95), yymsp[0].minor.yy352)); + delete yymsp[-3].minor.yy95; + } + break; + case 234: /* setlist ::= */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy381 = new ParserSetValueList(); + yygotominor.yy521 = new ParserSetValueList(); } break; - case 232: /* setlist ::= setlist COMMA */ + case 235: /* setlist ::= setlist COMMA */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy381 = yymsp[-1].minor.yy381; + yygotominor.yy521 = yymsp[-1].minor.yy521; } break; - case 233: /* setlist ::= setlist COMMA ID_COL */ - case 234: /* setlist ::= ID_COL */ yytestcase(yyruleno==234); -{ yy_destructor(yypParser,247,&yymsp[-2].minor); + case 236: /* setlist ::= setlist COMMA ID_COL */ + case 237: /* setlist ::= ID_COL */ yytestcase(yyruleno==237); +{ yy_destructor(yypParser,249,&yymsp[-2].minor); } break; - case 236: /* insert_stmt ::= with insert_cmd INTO fullname inscollist_opt select */ + case 238: /* idlist_opt ::= */ +{yygotominor.yy95 = new QStringList();} + break; + case 239: /* idlist_opt ::= LP idlist RP */ +{yygotominor.yy95 = yymsp[-1].minor.yy95;} + break; + case 240: /* idlist ::= idlist COMMA nm */ +{ + yygotominor.yy95 = yymsp[-2].minor.yy95; + *(yygotominor.yy95) << *(yymsp[0].minor.yy399); + delete yymsp[0].minor.yy399; + } + break; + case 241: /* idlist ::= nm */ { - yygotominor.yy399 = new SqliteInsert( - yymsp[-4].minor.yy250->replace, - yymsp[-4].minor.yy250->orConflict, - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, - *(yymsp[-1].minor.yy445), - yymsp[0].minor.yy123, - yymsp[-5].minor.yy367 + yygotominor.yy95 = new QStringList(); + *(yygotominor.yy95) << *(yymsp[0].minor.yy399); + delete yymsp[0].minor.yy399; + } + break; + case 242: /* idlist ::= */ +{ + parserContext->minorErrorBeforeNextToken("Syntax error"); + yygotominor.yy95 = new QStringList(); + } + break; + case 243: /* idlist ::= idlist COMMA ID_COL */ + case 244: /* idlist ::= ID_COL */ yytestcase(yyruleno==244); +{ yy_destructor(yypParser,245,&yymsp[-2].minor); +} + break; + case 246: /* insert_stmt ::= with insert_cmd INTO fullname idlist_opt select upsert */ +{ + yygotominor.yy283 = new SqliteInsert( + yymsp[-5].minor.yy105->replace, + yymsp[-5].minor.yy105->orConflict, + yymsp[-3].minor.yy360->name1, + yymsp[-3].minor.yy360->name2, + *(yymsp[-2].minor.yy95), + yymsp[-1].minor.yy473, + yymsp[-6].minor.yy321, + yymsp[0].minor.yy560 ); - delete yymsp[-2].minor.yy66; - delete yymsp[-4].minor.yy250; - delete yymsp[-1].minor.yy445; + delete yymsp[-3].minor.yy360; + delete yymsp[-5].minor.yy105; + delete yymsp[-2].minor.yy95; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 237: /* insert_stmt ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES */ + case 247: /* insert_stmt ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ { - yygotominor.yy399 = new SqliteInsert( - yymsp[-5].minor.yy250->replace, - yymsp[-5].minor.yy250->orConflict, - yymsp[-3].minor.yy66->name1, - yymsp[-3].minor.yy66->name2, - *(yymsp[-2].minor.yy445), - yymsp[-6].minor.yy367 + yygotominor.yy283 = new SqliteInsert( + yymsp[-5].minor.yy105->replace, + yymsp[-5].minor.yy105->orConflict, + yymsp[-3].minor.yy360->name1, + yymsp[-3].minor.yy360->name2, + *(yymsp[-2].minor.yy95), + yymsp[-6].minor.yy321 ); - delete yymsp[-3].minor.yy66; - delete yymsp[-5].minor.yy250; - delete yymsp[-2].minor.yy445; + delete yymsp[-3].minor.yy360; + delete yymsp[-5].minor.yy105; + delete yymsp[-2].minor.yy95; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 238: /* insert_stmt ::= with insert_cmd INTO */ + case 248: /* insert_stmt ::= with insert_cmd INTO */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteInsert* q = new SqliteInsert(); - q->replaceKw = yymsp[-1].minor.yy250->replace; - q->onConflict = yymsp[-1].minor.yy250->orConflict; - q->with = yymsp[-2].minor.yy367; - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[-1].minor.yy250; + q->replaceKw = yymsp[-1].minor.yy105->replace; + q->onConflict = yymsp[-1].minor.yy105->orConflict; + q->with = yymsp[-2].minor.yy321; + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[-1].minor.yy105; } break; - case 239: /* insert_stmt ::= with insert_cmd INTO nm DOT */ + case 249: /* insert_stmt ::= with insert_cmd INTO nm DOT */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteInsert* q = new SqliteInsert(); - q->replaceKw = yymsp[-3].minor.yy250->replace; - q->onConflict = yymsp[-3].minor.yy250->orConflict; - q->with = yymsp[-4].minor.yy367; - q->database = *(yymsp[-1].minor.yy211); - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[-3].minor.yy250; - delete yymsp[-1].minor.yy211; - } - break; - case 240: /* insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB */ -{ yy_destructor(yypParser,219,&yymsp[-3].minor); - yy_destructor(yypParser,249,&yymsp[-2].minor); + q->replaceKw = yymsp[-3].minor.yy105->replace; + q->onConflict = yymsp[-3].minor.yy105->orConflict; + q->with = yymsp[-4].minor.yy321; + q->database = *(yymsp[-1].minor.yy399); + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[-3].minor.yy105; + delete yymsp[-1].minor.yy399; + } + break; + case 250: /* insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB */ +{ yy_destructor(yypParser,221,&yymsp[-3].minor); + yy_destructor(yypParser,252,&yymsp[-2].minor); } break; - case 241: /* insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB */ -{ yy_destructor(yypParser,219,&yymsp[-5].minor); - yy_destructor(yypParser,249,&yymsp[-4].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 251: /* insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB */ +{ yy_destructor(yypParser,221,&yymsp[-5].minor); + yy_destructor(yypParser,252,&yymsp[-4].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; - case 242: /* insert_cmd ::= INSERT orconf */ + case 252: /* insert_cmd ::= INSERT orconf */ { - yygotominor.yy250 = new ParserStubInsertOrReplace(false, *(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; + yygotominor.yy105 = new ParserStubInsertOrReplace(false, *(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; } break; - case 243: /* insert_cmd ::= REPLACE */ -{yygotominor.yy250 = new ParserStubInsertOrReplace(true);} - break; - case 244: /* inscollist_opt ::= */ -{yygotominor.yy445 = new ParserStringList();} + case 253: /* insert_cmd ::= REPLACE */ +{yygotominor.yy105 = new ParserStubInsertOrReplace(true);} break; - case 245: /* inscollist_opt ::= LP inscollist RP */ -{yygotominor.yy445 = yymsp[-1].minor.yy445;} - break; - case 246: /* inscollist ::= inscollist COMMA nm */ + case 254: /* upsert ::= */ { - yymsp[-2].minor.yy445->append(*(yymsp[0].minor.yy211)); - yygotominor.yy445 = yymsp[-2].minor.yy445; - delete yymsp[0].minor.yy211; - DONT_INHERIT_TOKENS("inscollist"); + yygotominor.yy560 = nullptr; } break; - case 247: /* inscollist ::= nm */ + case 255: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ { - yygotominor.yy445 = new ParserStringList(); - yygotominor.yy445->append(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; + yygotominor.yy560 = new SqliteUpsert(*(yymsp[-7].minor.yy163), yymsp[-5].minor.yy352, *(yymsp[-1].minor.yy521), yymsp[0].minor.yy352); + delete yymsp[-7].minor.yy163; + delete yymsp[-1].minor.yy521; + objectForTokens = yygotominor.yy560; } break; - case 248: /* inscollist ::= */ + case 256: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ { - parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy445 = new ParserStringList(); + yygotominor.yy560 = new SqliteUpsert(*(yymsp[-4].minor.yy163), yymsp[-2].minor.yy352); + delete yymsp[-4].minor.yy163; + objectForTokens = yygotominor.yy560; } break; - case 249: /* inscollist ::= inscollist COMMA ID_COL */ - case 250: /* inscollist ::= ID_COL */ yytestcase(yyruleno==250); -{ yy_destructor(yypParser,243,&yymsp[-2].minor); -} + case 257: /* upsert ::= ON CONFLICT DO NOTHING */ +{ + yygotominor.yy560 = new SqliteUpsert(); + objectForTokens = yygotominor.yy560; + } break; - case 251: /* exprx ::= nm DOT */ + case 258: /* exprx ::= nm DOT */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[-1].minor.yy211), QString::null, QString::null); - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[-1].minor.yy399), QString::null, QString::null); + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error <exprx: nm.>"); } break; - case 252: /* exprx ::= nm DOT nm DOT */ + case 259: /* exprx ::= nm DOT nm DOT */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[-3].minor.yy211), *(yymsp[-1].minor.yy211), QString::null); - delete yymsp[-3].minor.yy211; - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[-3].minor.yy399), *(yymsp[-1].minor.yy399), QString::null); + delete yymsp[-3].minor.yy399; + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error <exprx: nm.nm.>"); } break; - case 253: /* exprx ::= expr not_opt BETWEEN expr AND */ + case 260: /* exprx ::= expr not_opt BETWEEN expr AND */ { - yygotominor.yy490 = new SqliteExpr(); - delete yymsp[-3].minor.yy237; - delete yymsp[-4].minor.yy490; - delete yymsp[-1].minor.yy490; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + delete yymsp[-3].minor.yy451; + delete yymsp[-4].minor.yy352; + delete yymsp[-1].minor.yy352; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error <exprx: expr not_opt BETWEEN expr AND>"); } break; - case 254: /* exprx ::= CASE case_operand case_exprlist case_else */ + case 261: /* exprx ::= CASE case_operand case_exprlist case_else */ { - yygotominor.yy490 = new SqliteExpr(); - delete yymsp[-1].minor.yy13; - delete yymsp[-2].minor.yy490; - delete yymsp[0].minor.yy490; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + delete yymsp[-1].minor.yy551; + delete yymsp[-2].minor.yy352; + delete yymsp[0].minor.yy352; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error <exprx: CASE operand exprlist else>"); } break; - case 255: /* exprx ::= expr not_opt IN LP exprlist */ + case 262: /* exprx ::= expr not_opt IN LP exprlist */ { - yygotominor.yy490 = new SqliteExpr(); - delete yymsp[-3].minor.yy237; - delete yymsp[0].minor.yy13; - delete yymsp[-4].minor.yy490; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + delete yymsp[-3].minor.yy451; + delete yymsp[0].minor.yy551; + delete yymsp[-4].minor.yy352; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error <exprx: expr not_opt IN LP exprlist>"); } break; - case 256: /* exprx ::= expr not_opt IN ID_DB */ -{ yy_destructor(yypParser,199,&yymsp[-3].minor); + case 263: /* exprx ::= expr not_opt IN ID_DB */ +{ yy_destructor(yypParser,201,&yymsp[-3].minor); } break; - case 257: /* exprx ::= expr not_opt IN nm DOT ID_TAB */ - case 258: /* exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN */ yytestcase(yyruleno==258); -{ yy_destructor(yypParser,199,&yymsp[-5].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 264: /* exprx ::= expr not_opt IN nm DOT ID_TAB */ + case 265: /* exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN */ yytestcase(yyruleno==265); +{ yy_destructor(yypParser,201,&yymsp[-5].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; - case 260: /* exprx ::= nm DOT nm DOT ID_COL */ -{ yy_destructor(yypParser,177,&yymsp[-4].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 267: /* exprx ::= nm DOT nm DOT ID_COL */ +{ yy_destructor(yypParser,179,&yymsp[-4].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; - case 261: /* exprx ::= expr COLLATE ID_COLLATE */ - case 262: /* exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP */ yytestcase(yyruleno==262); -{ yy_destructor(yypParser,199,&yymsp[-2].minor); + case 268: /* exprx ::= expr COLLATE ID_COLLATE */ + case 269: /* exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP */ yytestcase(yyruleno==269); +{ yy_destructor(yypParser,201,&yymsp[-2].minor); } break; - case 263: /* exprx ::= term */ + case 270: /* exprx ::= term */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initLiteral(*(yymsp[0].minor.yy21)); - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initLiteral(*(yymsp[0].minor.yy469)); + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy352; } break; - case 264: /* exprx ::= CTIME_KW */ + case 271: /* exprx ::= CTIME_KW */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initCTime(yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initCTime(yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 265: /* exprx ::= LP nexprlist RP */ + case 272: /* exprx ::= LP nexprlist RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initRowValue(*(yymsp[-1].minor.yy13)); - delete yymsp[-1].minor.yy13; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initRowValue(*(yymsp[-1].minor.yy551)); + delete yymsp[-1].minor.yy551; + objectForTokens = yygotominor.yy352; } break; - case 266: /* exprx ::= id */ + case 273: /* exprx ::= id */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 267: /* exprx ::= JOIN_KW */ + case 274: /* exprx ::= JOIN_KW */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 268: /* exprx ::= nm DOT nm */ + case 275: /* exprx ::= nm DOT nm */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[-2].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[-2].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 269: /* exprx ::= nm DOT nm DOT nm */ + case 276: /* exprx ::= nm DOT nm DOT nm */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[-4].minor.yy211), *(yymsp[-2].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-4].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[-4].minor.yy399), *(yymsp[-2].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-4].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 270: /* exprx ::= VARIABLE */ + case 277: /* exprx ::= VARIABLE */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initBindParam(yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initBindParam(yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 271: /* exprx ::= expr COLLATE ids */ + case 278: /* exprx ::= expr COLLATE ids */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initCollate(yymsp[-2].minor.yy490, *(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initCollate(yymsp[-2].minor.yy352, *(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 272: /* exprx ::= CAST LP expr AS typetoken RP */ + case 279: /* exprx ::= CAST LP expr AS typetoken RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initCast(yymsp[-3].minor.yy490, yymsp[-1].minor.yy299); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initCast(yymsp[-3].minor.yy352, yymsp[-1].minor.yy537); + objectForTokens = yygotominor.yy352; } break; - case 273: /* exprx ::= ID LP distinct exprlist RP */ + case 280: /* exprx ::= ID LP distinct exprlist RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initFunction(yymsp[-4].minor.yy0->value, *(yymsp[-2].minor.yy376), *(yymsp[-1].minor.yy13)); - delete yymsp[-2].minor.yy376; - delete yymsp[-1].minor.yy13; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initFunction(yymsp[-4].minor.yy0->value, *(yymsp[-2].minor.yy146), *(yymsp[-1].minor.yy551)); + delete yymsp[-2].minor.yy146; + delete yymsp[-1].minor.yy551; + objectForTokens = yygotominor.yy352; } break; - case 274: /* exprx ::= ID LP STAR RP */ + case 281: /* exprx ::= ID LP STAR RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initFunction(yymsp[-3].minor.yy0->value, true); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initFunction(yymsp[-3].minor.yy0->value, true); + objectForTokens = yygotominor.yy352; } break; - case 275: /* exprx ::= expr AND expr */ - case 276: /* exprx ::= expr OR expr */ yytestcase(yyruleno==276); - case 277: /* exprx ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==277); - case 278: /* exprx ::= expr EQ|NE expr */ yytestcase(yyruleno==278); - case 279: /* exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==279); - case 280: /* exprx ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==280); - case 281: /* exprx ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==281); - case 282: /* exprx ::= expr CONCAT expr */ yytestcase(yyruleno==282); + case 282: /* exprx ::= expr AND expr */ + case 283: /* exprx ::= expr OR expr */ yytestcase(yyruleno==283); + case 284: /* exprx ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==284); + case 285: /* exprx ::= expr EQ|NE expr */ yytestcase(yyruleno==285); + case 286: /* exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==286); + case 287: /* exprx ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==287); + case 288: /* exprx ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==288); + case 289: /* exprx ::= expr CONCAT expr */ yytestcase(yyruleno==289); { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initBinOp(yymsp[-2].minor.yy490, yymsp[-1].minor.yy0->value, yymsp[0].minor.yy490); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initBinOp(yymsp[-2].minor.yy352, yymsp[-1].minor.yy0->value, yymsp[0].minor.yy352); + objectForTokens = yygotominor.yy352; } break; - case 283: /* exprx ::= expr not_opt likeop expr */ + case 290: /* exprx ::= expr not_opt likeop expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initLike(yymsp[-3].minor.yy490, *(yymsp[-2].minor.yy237), *(yymsp[-1].minor.yy374), yymsp[0].minor.yy490); - delete yymsp[-2].minor.yy237; - delete yymsp[-1].minor.yy374; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initLike(yymsp[-3].minor.yy352, *(yymsp[-2].minor.yy451), *(yymsp[-1].minor.yy520), yymsp[0].minor.yy352); + delete yymsp[-2].minor.yy451; + delete yymsp[-1].minor.yy520; + objectForTokens = yygotominor.yy352; } break; - case 284: /* exprx ::= expr not_opt likeop expr ESCAPE expr */ + case 291: /* exprx ::= expr not_opt likeop expr ESCAPE expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initLike(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), *(yymsp[-3].minor.yy374), yymsp[-2].minor.yy490, yymsp[0].minor.yy490); - delete yymsp[-4].minor.yy237; - delete yymsp[-3].minor.yy374; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initLike(yymsp[-5].minor.yy352, *(yymsp[-4].minor.yy451), *(yymsp[-3].minor.yy520), yymsp[-2].minor.yy352, yymsp[0].minor.yy352); + delete yymsp[-4].minor.yy451; + delete yymsp[-3].minor.yy520; + objectForTokens = yygotominor.yy352; } break; - case 285: /* exprx ::= expr ISNULL|NOTNULL */ + case 292: /* exprx ::= expr ISNULL|NOTNULL */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initNull(yymsp[-1].minor.yy490, yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initNull(yymsp[-1].minor.yy352, yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 286: /* exprx ::= expr NOT NULL */ + case 293: /* exprx ::= expr NOT NULL */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initNull(yymsp[-2].minor.yy490, "NOT NULL"); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initNull(yymsp[-2].minor.yy352, "NOT NULL"); + objectForTokens = yygotominor.yy352; } break; - case 287: /* exprx ::= expr IS not_opt expr */ + case 294: /* exprx ::= expr IS not_opt expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initIs(yymsp[-3].minor.yy490, *(yymsp[-1].minor.yy237), yymsp[0].minor.yy490); - delete yymsp[-1].minor.yy237; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initIs(yymsp[-3].minor.yy352, *(yymsp[-1].minor.yy451), yymsp[0].minor.yy352); + delete yymsp[-1].minor.yy451; + objectForTokens = yygotominor.yy352; } break; - case 288: /* exprx ::= NOT expr */ + case 295: /* exprx ::= NOT expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initUnaryOp(yymsp[0].minor.yy490, yymsp[-1].minor.yy0->value); + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initUnaryOp(yymsp[0].minor.yy352, yymsp[-1].minor.yy0->value); } break; - case 289: /* exprx ::= BITNOT expr */ - case 291: /* exprx ::= PLUS expr */ yytestcase(yyruleno==291); + case 296: /* exprx ::= BITNOT expr */ + case 298: /* exprx ::= PLUS expr */ yytestcase(yyruleno==298); { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initUnaryOp(yymsp[0].minor.yy490, yymsp[-1].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initUnaryOp(yymsp[0].minor.yy352, yymsp[-1].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 290: /* exprx ::= MINUS expr */ + case 297: /* exprx ::= MINUS expr */ { - yygotominor.yy490 = new SqliteExpr(); - if (yymsp[0].minor.yy490->mode == SqliteExpr::Mode::LITERAL_VALUE && + yygotominor.yy352 = new SqliteExpr(); + if (yymsp[0].minor.yy352->mode == SqliteExpr::Mode::LITERAL_VALUE && parserContext->isCandidateForMaxNegativeNumber() && - yymsp[0].minor.yy490->literalValue == static_cast<qint64>(0L)) + yymsp[0].minor.yy352->literalValue == static_cast<qint64>(0L)) { - yygotominor.yy490->initLiteral(std::numeric_limits<qint64>::min()); - delete yymsp[0].minor.yy490; + yygotominor.yy352->initLiteral(std::numeric_limits<qint64>::min()); + delete yymsp[0].minor.yy352; } else { - yygotominor.yy490->initUnaryOp(yymsp[0].minor.yy490, yymsp[-1].minor.yy0->value); + yygotominor.yy352->initUnaryOp(yymsp[0].minor.yy352, yymsp[-1].minor.yy0->value); } - objectForTokens = yygotominor.yy490; + objectForTokens = yygotominor.yy352; } break; - case 292: /* exprx ::= expr not_opt BETWEEN expr AND expr */ + case 299: /* exprx ::= expr not_opt BETWEEN expr AND expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initBetween(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), yymsp[-2].minor.yy490, yymsp[0].minor.yy490); - delete yymsp[-4].minor.yy237; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initBetween(yymsp[-5].minor.yy352, *(yymsp[-4].minor.yy451), yymsp[-2].minor.yy352, yymsp[0].minor.yy352); + delete yymsp[-4].minor.yy451; + objectForTokens = yygotominor.yy352; } break; - case 293: /* exprx ::= expr not_opt IN LP exprlist RP */ + case 300: /* exprx ::= expr not_opt IN LP exprlist RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initIn(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), *(yymsp[-1].minor.yy13)); - delete yymsp[-4].minor.yy237; - delete yymsp[-1].minor.yy13; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initIn(yymsp[-5].minor.yy352, *(yymsp[-4].minor.yy451), *(yymsp[-1].minor.yy551)); + delete yymsp[-4].minor.yy451; + delete yymsp[-1].minor.yy551; + objectForTokens = yygotominor.yy352; } break; - case 294: /* exprx ::= LP select RP */ + case 301: /* exprx ::= LP select RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initSubSelect(yymsp[-1].minor.yy123); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initSubSelect(yymsp[-1].minor.yy473); + objectForTokens = yygotominor.yy352; } break; - case 295: /* exprx ::= expr not_opt IN LP select RP */ + case 302: /* exprx ::= expr not_opt IN LP select RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initIn(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), yymsp[-1].minor.yy123); - delete yymsp[-4].minor.yy237; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initIn(yymsp[-5].minor.yy352, *(yymsp[-4].minor.yy451), yymsp[-1].minor.yy473); + delete yymsp[-4].minor.yy451; + objectForTokens = yygotominor.yy352; } break; - case 296: /* exprx ::= expr not_opt IN nm dbnm */ + case 303: /* exprx ::= expr not_opt IN nm dbnm */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initIn(yymsp[-4].minor.yy490, *(yymsp[-3].minor.yy237), *(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-3].minor.yy237; - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initIn(yymsp[-4].minor.yy352, *(yymsp[-3].minor.yy451), *(yymsp[-1].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-3].minor.yy451; + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 297: /* exprx ::= EXISTS LP select RP */ + case 304: /* exprx ::= EXISTS LP select RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initExists(yymsp[-1].minor.yy123); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initExists(yymsp[-1].minor.yy473); + objectForTokens = yygotominor.yy352; } break; - case 298: /* exprx ::= CASE case_operand case_exprlist case_else END */ + case 305: /* exprx ::= CASE case_operand case_exprlist case_else END */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initCase(yymsp[-3].minor.yy490, *(yymsp[-2].minor.yy13), yymsp[-1].minor.yy490); - delete yymsp[-2].minor.yy13; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initCase(yymsp[-3].minor.yy352, *(yymsp[-2].minor.yy551), yymsp[-1].minor.yy352); + delete yymsp[-2].minor.yy551; + objectForTokens = yygotominor.yy352; } break; - case 299: /* exprx ::= RAISE LP IGNORE RP */ + case 306: /* exprx ::= RAISE LP IGNORE RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initRaise(yymsp[-1].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initRaise(yymsp[-1].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 300: /* exprx ::= RAISE LP raisetype COMMA nm RP */ + case 307: /* exprx ::= RAISE LP raisetype COMMA nm RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initRaise(yymsp[-3].minor.yy0->value, *(yymsp[-1].minor.yy211)); - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initRaise(yymsp[-3].minor.yy0->value, *(yymsp[-1].minor.yy399)); + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 301: /* expr ::= */ + case 308: /* expr ::= */ { - yygotominor.yy490 = new SqliteExpr(); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + objectForTokens = yygotominor.yy352; parserContext->minorErrorAfterLastToken("Syntax error <expr>"); } break; - case 305: /* likeop ::= LIKE_KW|MATCH */ -{yygotominor.yy374 = new SqliteExpr::LikeOp(SqliteExpr::likeOp(yymsp[0].minor.yy0->value));} + case 312: /* likeop ::= LIKE_KW|MATCH */ +{yygotominor.yy520 = new SqliteExpr::LikeOp(SqliteExpr::likeOp(yymsp[0].minor.yy0->value));} break; - case 306: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 313: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { - yymsp[-4].minor.yy13->append(yymsp[-2].minor.yy490); - yymsp[-4].minor.yy13->append(yymsp[0].minor.yy490); - yygotominor.yy13 = yymsp[-4].minor.yy13; + yymsp[-4].minor.yy551->append(yymsp[-2].minor.yy352); + yymsp[-4].minor.yy551->append(yymsp[0].minor.yy352); + yygotominor.yy551 = yymsp[-4].minor.yy551; } break; - case 307: /* case_exprlist ::= WHEN expr THEN expr */ + case 314: /* case_exprlist ::= WHEN expr THEN expr */ { - yygotominor.yy13 = new ParserExprList(); - yygotominor.yy13->append(yymsp[-2].minor.yy490); - yygotominor.yy13->append(yymsp[0].minor.yy490); + yygotominor.yy551 = new ParserExprList(); + yygotominor.yy551->append(yymsp[-2].minor.yy352); + yygotominor.yy551->append(yymsp[0].minor.yy352); } break; - case 314: /* nexprlist ::= nexprlist COMMA expr */ + case 321: /* nexprlist ::= nexprlist COMMA expr */ { - yymsp[-2].minor.yy13->append(yymsp[0].minor.yy490); - yygotominor.yy13 = yymsp[-2].minor.yy13; + yymsp[-2].minor.yy551->append(yymsp[0].minor.yy352); + yygotominor.yy551 = yymsp[-2].minor.yy551; DONT_INHERIT_TOKENS("nexprlist"); } break; - case 315: /* nexprlist ::= exprx */ + case 322: /* nexprlist ::= exprx */ { - yygotominor.yy13 = new ParserExprList(); - yygotominor.yy13->append(yymsp[0].minor.yy490); + yygotominor.yy551 = new ParserExprList(); + yygotominor.yy551->append(yymsp[0].minor.yy352); } break; - case 316: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 323: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { - yygotominor.yy399 = new SqliteCreateIndex( - *(yymsp[-10].minor.yy237), - *(yymsp[-8].minor.yy237), - *(yymsp[-7].minor.yy211), - *(yymsp[-6].minor.yy211), - *(yymsp[-4].minor.yy211), - *(yymsp[-2].minor.yy495), - yymsp[0].minor.yy490 + yygotominor.yy283 = new SqliteCreateIndex( + *(yymsp[-10].minor.yy451), + *(yymsp[-8].minor.yy451), + *(yymsp[-7].minor.yy399), + *(yymsp[-6].minor.yy399), + *(yymsp[-4].minor.yy399), + *(yymsp[-2].minor.yy163), + yymsp[0].minor.yy352 ); - delete yymsp[-8].minor.yy237; - delete yymsp[-10].minor.yy237; - delete yymsp[-7].minor.yy211; - delete yymsp[-6].minor.yy211; - delete yymsp[-4].minor.yy211; - delete yymsp[-2].minor.yy495; - objectForTokens = yygotominor.yy399; + delete yymsp[-8].minor.yy451; + delete yymsp[-10].minor.yy451; + delete yymsp[-7].minor.yy399; + delete yymsp[-6].minor.yy399; + delete yymsp[-4].minor.yy399; + delete yymsp[-2].minor.yy163; + objectForTokens = yygotominor.yy283; } break; - case 317: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB */ -{ yy_destructor(yypParser,177,&yymsp[-3].minor); + case 324: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB */ +{ yy_destructor(yypParser,179,&yymsp[-3].minor); } break; - case 322: /* idxlist_opt ::= */ -{yygotominor.yy139 = new ParserIndexedColumnList();} + case 329: /* idxlist_opt ::= */ +{yygotominor.yy223 = new ParserIndexedColumnList();} break; - case 323: /* idxlist_opt ::= LP idxlist RP */ -{yygotominor.yy139 = yymsp[-1].minor.yy139;} + case 330: /* idxlist_opt ::= LP idxlist RP */ +{yygotominor.yy223 = yymsp[-1].minor.yy223;} break; - case 324: /* idxlist ::= idxlist COMMA idxlist_single */ + case 331: /* idxlist ::= idxlist COMMA idxlist_single */ { - yymsp[-2].minor.yy139->append(yymsp[0].minor.yy90); - yygotominor.yy139 = yymsp[-2].minor.yy139; + yymsp[-2].minor.yy223->append(yymsp[0].minor.yy108); + yygotominor.yy223 = yymsp[-2].minor.yy223; DONT_INHERIT_TOKENS("idxlist"); } break; - case 325: /* idxlist ::= idxlist_single */ + case 332: /* idxlist ::= idxlist_single */ { - yygotominor.yy139 = new ParserIndexedColumnList(); - yygotominor.yy139->append(yymsp[0].minor.yy90); + yygotominor.yy223 = new ParserIndexedColumnList(); + yygotominor.yy223->append(yymsp[0].minor.yy108); } break; - case 326: /* idxlist_single ::= nm collate sortorder */ - case 327: /* idxlist_single ::= ID_COL */ yytestcase(yyruleno==327); + case 333: /* idxlist_single ::= nm collate sortorder */ + case 334: /* idxlist_single ::= ID_COL */ yytestcase(yyruleno==334); { SqliteIndexedColumn* obj = new SqliteIndexedColumn( - *(yymsp[-2].minor.yy211), - *(yymsp[-1].minor.yy211), - *(yymsp[0].minor.yy226) + *(yymsp[-2].minor.yy399), + *(yymsp[-1].minor.yy399), + *(yymsp[0].minor.yy309) ); - yygotominor.yy90 = obj; - delete yymsp[0].minor.yy226; - delete yymsp[-2].minor.yy211; - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy90; + yygotominor.yy108 = obj; + delete yymsp[0].minor.yy309; + delete yymsp[-2].minor.yy399; + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy108; } break; - case 331: /* cmd ::= DROP INDEX ifexists fullname */ + case 338: /* cmd ::= DROP INDEX ifexists fullname */ { - yygotominor.yy399 = new SqliteDropIndex(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2); - delete yymsp[-1].minor.yy237; - delete yymsp[0].minor.yy66; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDropIndex(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy360->name1, yymsp[0].minor.yy360->name2); + delete yymsp[-1].minor.yy451; + delete yymsp[0].minor.yy360; + objectForTokens = yygotominor.yy283; } break; - case 334: /* cmd ::= VACUUM */ + case 341: /* cmd ::= VACUUM */ { - yygotominor.yy399 = new SqliteVacuum(); - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteVacuum(); + objectForTokens = yygotominor.yy283; } break; - case 335: /* cmd ::= VACUUM nm */ + case 342: /* cmd ::= VACUUM nm */ { - yygotominor.yy399 = new SqliteVacuum(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteVacuum(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 336: /* cmd ::= PRAGMA nm dbnm */ + case 343: /* cmd ::= PRAGMA nm dbnm */ { - yygotominor.yy399 = new SqlitePragma(*(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqlitePragma(*(yymsp[-1].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 337: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ - case 339: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ yytestcase(yyruleno==339); + case 344: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 346: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ yytestcase(yyruleno==346); { - yygotominor.yy399 = new SqlitePragma(*(yymsp[-3].minor.yy211), *(yymsp[-2].minor.yy211), *(yymsp[0].minor.yy21), true); - delete yymsp[-3].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqlitePragma(*(yymsp[-3].minor.yy399), *(yymsp[-2].minor.yy399), *(yymsp[0].minor.yy469), true); + delete yymsp[-3].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy283; } break; - case 338: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ - case 340: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ yytestcase(yyruleno==340); + case 345: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 347: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ yytestcase(yyruleno==347); { - yygotominor.yy399 = new SqlitePragma(*(yymsp[-4].minor.yy211), *(yymsp[-3].minor.yy211), *(yymsp[-1].minor.yy21), false); - delete yymsp[-4].minor.yy211; - delete yymsp[-3].minor.yy211; - delete yymsp[-1].minor.yy21; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqlitePragma(*(yymsp[-4].minor.yy399), *(yymsp[-3].minor.yy399), *(yymsp[-1].minor.yy469), false); + delete yymsp[-4].minor.yy399; + delete yymsp[-3].minor.yy399; + delete yymsp[-1].minor.yy469; + objectForTokens = yygotominor.yy283; } break; - case 344: /* nmnum ::= nm */ + case 351: /* nmnum ::= nm */ { - yygotominor.yy21 = new QVariant(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; + yygotominor.yy469 = new QVariant(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; } break; - case 350: /* minus_num ::= MINUS number */ + case 357: /* minus_num ::= MINUS number */ { - if (yymsp[0].minor.yy21->type() == QVariant::Double) - *(yymsp[0].minor.yy21) = -(yymsp[0].minor.yy21->toDouble()); - else if (yymsp[0].minor.yy21->type() == QVariant::LongLong) + if (yymsp[0].minor.yy469->type() == QVariant::Double) + *(yymsp[0].minor.yy469) = -(yymsp[0].minor.yy469->toDouble()); + else if (yymsp[0].minor.yy469->type() == QVariant::LongLong) { if (parserContext->isCandidateForMaxNegativeNumber()) - *(yymsp[0].minor.yy21) = std::numeric_limits<qint64>::min(); + *(yymsp[0].minor.yy469) = std::numeric_limits<qint64>::min(); else - *(yymsp[0].minor.yy21) = -(yymsp[0].minor.yy21->toLongLong()); + *(yymsp[0].minor.yy469) = -(yymsp[0].minor.yy469->toLongLong()); } else Q_ASSERT_X(true, "producing minus number", "QVariant is neither of Double or LongLong."); - yygotominor.yy21 = yymsp[0].minor.yy21; - } - break; - case 353: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END */ -{ - yygotominor.yy399 = new SqliteCreateTrigger( - *(yymsp[-13].minor.yy376), - *(yymsp[-11].minor.yy237), - *(yymsp[-10].minor.yy211), - *(yymsp[-9].minor.yy211), - *(yymsp[-5].minor.yy211), - *(yymsp[-8].minor.yy152), - yymsp[-7].minor.yy309, - *(yymsp[-4].minor.yy409), - yymsp[-3].minor.yy490, - *(yymsp[-1].minor.yy214), + yygotominor.yy469 = yymsp[0].minor.yy469; + } + break; + case 360: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END */ +{ + yygotominor.yy283 = new SqliteCreateTrigger( + *(yymsp[-13].minor.yy146), + *(yymsp[-11].minor.yy451), + *(yymsp[-10].minor.yy399), + *(yymsp[-9].minor.yy399), + *(yymsp[-5].minor.yy399), + *(yymsp[-8].minor.yy132), + yymsp[-7].minor.yy552, + *(yymsp[-4].minor.yy3), + yymsp[-3].minor.yy352, + *(yymsp[-1].minor.yy430), 3 ); - delete yymsp[-11].minor.yy237; - delete yymsp[-13].minor.yy376; - delete yymsp[-8].minor.yy152; - delete yymsp[-4].minor.yy409; - delete yymsp[-10].minor.yy211; - delete yymsp[-5].minor.yy211; - delete yymsp[-9].minor.yy211; - delete yymsp[-1].minor.yy214; - objectForTokens = yygotominor.yy399; + delete yymsp[-11].minor.yy451; + delete yymsp[-13].minor.yy146; + delete yymsp[-8].minor.yy132; + delete yymsp[-4].minor.yy3; + delete yymsp[-10].minor.yy399; + delete yymsp[-5].minor.yy399; + delete yymsp[-9].minor.yy399; + delete yymsp[-1].minor.yy430; + objectForTokens = yygotominor.yy283; } break; - case 354: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause */ + case 361: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause */ { QList<SqliteQuery *> CL; - yygotominor.yy399 = new SqliteCreateTrigger( - *(yymsp[-10].minor.yy376), - *(yymsp[-8].minor.yy237), - *(yymsp[-7].minor.yy211), - *(yymsp[-6].minor.yy211), - *(yymsp[-2].minor.yy211), - *(yymsp[-5].minor.yy152), - yymsp[-4].minor.yy309, - *(yymsp[-1].minor.yy409), - yymsp[0].minor.yy490, + yygotominor.yy283 = new SqliteCreateTrigger( + *(yymsp[-10].minor.yy146), + *(yymsp[-8].minor.yy451), + *(yymsp[-7].minor.yy399), + *(yymsp[-6].minor.yy399), + *(yymsp[-2].minor.yy399), + *(yymsp[-5].minor.yy132), + yymsp[-4].minor.yy552, + *(yymsp[-1].minor.yy3), + yymsp[0].minor.yy352, CL, 3 ); - delete yymsp[-8].minor.yy237; - delete yymsp[-10].minor.yy376; - delete yymsp[-5].minor.yy152; - delete yymsp[-1].minor.yy409; - delete yymsp[-7].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[-6].minor.yy211; - objectForTokens = yygotominor.yy399; + delete yymsp[-8].minor.yy451; + delete yymsp[-10].minor.yy146; + delete yymsp[-5].minor.yy132; + delete yymsp[-1].minor.yy3; + delete yymsp[-7].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[-6].minor.yy399; + objectForTokens = yygotominor.yy283; parserContext->minorErrorAfterLastToken("Syntax error"); } break; - case 355: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list */ + case 362: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list */ { - yygotominor.yy399 = new SqliteCreateTrigger( - *(yymsp[-12].minor.yy376), - *(yymsp[-10].minor.yy237), - *(yymsp[-9].minor.yy211), - *(yymsp[-8].minor.yy211), - *(yymsp[-4].minor.yy211), - *(yymsp[-7].minor.yy152), - yymsp[-6].minor.yy309, - *(yymsp[-3].minor.yy409), - yymsp[-2].minor.yy490, - *(yymsp[0].minor.yy214), + yygotominor.yy283 = new SqliteCreateTrigger( + *(yymsp[-12].minor.yy146), + *(yymsp[-10].minor.yy451), + *(yymsp[-9].minor.yy399), + *(yymsp[-8].minor.yy399), + *(yymsp[-4].minor.yy399), + *(yymsp[-7].minor.yy132), + yymsp[-6].minor.yy552, + *(yymsp[-3].minor.yy3), + yymsp[-2].minor.yy352, + *(yymsp[0].minor.yy430), 3 ); - delete yymsp[-10].minor.yy237; - delete yymsp[-12].minor.yy376; - delete yymsp[-7].minor.yy152; - delete yymsp[-3].minor.yy409; - delete yymsp[-9].minor.yy211; - delete yymsp[-4].minor.yy211; - delete yymsp[-8].minor.yy211; - delete yymsp[0].minor.yy214; - objectForTokens = yygotominor.yy399; + delete yymsp[-10].minor.yy451; + delete yymsp[-12].minor.yy146; + delete yymsp[-7].minor.yy132; + delete yymsp[-3].minor.yy3; + delete yymsp[-9].minor.yy399; + delete yymsp[-4].minor.yy399; + delete yymsp[-8].minor.yy399; + delete yymsp[0].minor.yy430; + objectForTokens = yygotominor.yy283; parserContext->minorErrorAfterLastToken("Syntax error"); } break; - case 356: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB */ -{ yy_destructor(yypParser,179,&yymsp[-8].minor); - yy_destructor(yypParser,177,&yymsp[-5].minor); - yy_destructor(yypParser,262,&yymsp[-3].minor); - yy_destructor(yypParser,263,&yymsp[-2].minor); + case 363: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB */ +{ yy_destructor(yypParser,181,&yymsp[-8].minor); + yy_destructor(yypParser,179,&yymsp[-5].minor); + yy_destructor(yypParser,265,&yymsp[-3].minor); + yy_destructor(yypParser,266,&yymsp[-2].minor); } break; - case 359: /* trigger_time ::= BEFORE */ -{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::BEFORE);} + case 366: /* trigger_time ::= BEFORE */ +{yygotominor.yy132 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::BEFORE);} break; - case 360: /* trigger_time ::= AFTER */ -{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::AFTER);} + case 367: /* trigger_time ::= AFTER */ +{yygotominor.yy132 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::AFTER);} break; - case 361: /* trigger_time ::= INSTEAD OF */ -{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::INSTEAD_OF);} + case 368: /* trigger_time ::= INSTEAD OF */ +{yygotominor.yy132 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::INSTEAD_OF);} break; - case 362: /* trigger_time ::= */ -{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::null);} + case 369: /* trigger_time ::= */ +{yygotominor.yy132 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::null);} break; - case 363: /* trigger_event ::= DELETE */ + case 370: /* trigger_event ::= DELETE */ { - yygotominor.yy309 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::DELETE); - objectForTokens = yygotominor.yy309; + yygotominor.yy552 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::DELETE); + objectForTokens = yygotominor.yy552; } break; - case 364: /* trigger_event ::= INSERT */ + case 371: /* trigger_event ::= INSERT */ { - yygotominor.yy309 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::INSERT); - objectForTokens = yygotominor.yy309; + yygotominor.yy552 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::INSERT); + objectForTokens = yygotominor.yy552; } break; - case 365: /* trigger_event ::= UPDATE */ + case 372: /* trigger_event ::= UPDATE */ { - yygotominor.yy309 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::UPDATE); - objectForTokens = yygotominor.yy309; + yygotominor.yy552 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::UPDATE); + objectForTokens = yygotominor.yy552; } break; - case 366: /* trigger_event ::= UPDATE OF inscollist */ + case 373: /* trigger_event ::= UPDATE OF idlist */ { - yygotominor.yy309 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy445)); - delete yymsp[0].minor.yy445; - objectForTokens = yygotominor.yy309; + yygotominor.yy552 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy95)); + delete yymsp[0].minor.yy95; + objectForTokens = yygotominor.yy552; } break; - case 367: /* foreach_clause ::= */ -{yygotominor.yy409 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::null);} + case 374: /* foreach_clause ::= */ +{yygotominor.yy3 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::null);} break; - case 368: /* foreach_clause ::= FOR EACH ROW */ -{yygotominor.yy409 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_ROW);} + case 375: /* foreach_clause ::= FOR EACH ROW */ +{yygotominor.yy3 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_ROW);} break; - case 371: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 378: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { - yymsp[-2].minor.yy214->append(yymsp[-1].minor.yy399); - yygotominor.yy214 = yymsp[-2].minor.yy214; + yymsp[-2].minor.yy430->append(yymsp[-1].minor.yy283); + yygotominor.yy430 = yymsp[-2].minor.yy430; DONT_INHERIT_TOKENS("trigger_cmd_list"); } break; - case 372: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 379: /* trigger_cmd_list ::= trigger_cmd SEMI */ { - yygotominor.yy214 = new ParserQueryList(); - yygotominor.yy214->append(yymsp[-1].minor.yy399); + yygotominor.yy430 = new ParserQueryList(); + yygotominor.yy430->append(yymsp[-1].minor.yy283); } break; - case 373: /* trigger_cmd_list ::= SEMI */ + case 380: /* trigger_cmd_list ::= SEMI */ { - yygotominor.yy214 = new ParserQueryList(); + yygotominor.yy430 = new ParserQueryList(); parserContext->minorErrorAfterLastToken("Syntax error"); } break; - case 378: /* raisetype ::= ROLLBACK|ABORT|FAIL */ + case 385: /* raisetype ::= ROLLBACK|ABORT|FAIL */ {yygotominor.yy0 = yymsp[0].minor.yy0;} break; - case 379: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 386: /* cmd ::= DROP TRIGGER ifexists fullname */ { - yygotominor.yy399 = new SqliteDropTrigger(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2); - delete yymsp[-1].minor.yy237; - delete yymsp[0].minor.yy66; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDropTrigger(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy360->name1, yymsp[0].minor.yy360->name2); + delete yymsp[-1].minor.yy451; + delete yymsp[0].minor.yy360; + objectForTokens = yygotominor.yy283; } break; - case 382: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 389: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { - yygotominor.yy399 = new SqliteAttach(*(yymsp[-4].minor.yy237), yymsp[-3].minor.yy490, yymsp[-1].minor.yy490, yymsp[0].minor.yy490); - delete yymsp[-4].minor.yy237; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteAttach(*(yymsp[-4].minor.yy451), yymsp[-3].minor.yy352, yymsp[-1].minor.yy352, yymsp[0].minor.yy352); + delete yymsp[-4].minor.yy451; + objectForTokens = yygotominor.yy283; } break; - case 383: /* cmd ::= DETACH database_kw_opt expr */ + case 390: /* cmd ::= DETACH database_kw_opt expr */ { - yygotominor.yy399 = new SqliteDetach(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy490); - delete yymsp[-1].minor.yy237; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDetach(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy352); + delete yymsp[-1].minor.yy451; + objectForTokens = yygotominor.yy283; } break; - case 388: /* cmd ::= REINDEX */ -{yygotominor.yy399 = new SqliteReindex();} + case 395: /* cmd ::= REINDEX */ +{yygotominor.yy283 = new SqliteReindex();} break; - case 389: /* cmd ::= REINDEX nm dbnm */ - case 390: /* cmd ::= REINDEX ID_COLLATE */ yytestcase(yyruleno==390); + case 396: /* cmd ::= REINDEX nm dbnm */ + case 397: /* cmd ::= REINDEX ID_COLLATE */ yytestcase(yyruleno==397); { - yygotominor.yy399 = new SqliteReindex(*(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteReindex(*(yymsp[-1].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 393: /* cmd ::= ANALYZE */ + case 400: /* cmd ::= ANALYZE */ { - yygotominor.yy399 = new SqliteAnalyze(); - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteAnalyze(); + objectForTokens = yygotominor.yy283; } break; - case 394: /* cmd ::= ANALYZE nm dbnm */ + case 401: /* cmd ::= ANALYZE nm dbnm */ { - yygotominor.yy399 = new SqliteAnalyze(*(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteAnalyze(*(yymsp[-1].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 397: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 404: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - yygotominor.yy399 = new SqliteAlterTable( - yymsp[-3].minor.yy66->name1, - yymsp[-3].minor.yy66->name2, - *(yymsp[0].minor.yy211) + yygotominor.yy283 = new SqliteAlterTable( + yymsp[-3].minor.yy360->name1, + yymsp[-3].minor.yy360->name2, + *(yymsp[0].minor.yy399) ); - delete yymsp[0].minor.yy211; - delete yymsp[-3].minor.yy66; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy399; + delete yymsp[-3].minor.yy360; + objectForTokens = yygotominor.yy283; } break; - case 398: /* cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column */ + case 405: /* cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column */ { - yygotominor.yy399 = new SqliteAlterTable( - yymsp[-3].minor.yy66->name1, - yymsp[-3].minor.yy66->name2, - *(yymsp[-1].minor.yy237), - yymsp[0].minor.yy425 + yygotominor.yy283 = new SqliteAlterTable( + yymsp[-3].minor.yy360->name1, + yymsp[-3].minor.yy360->name2, + *(yymsp[-1].minor.yy451), + yymsp[0].minor.yy227 ); - delete yymsp[-1].minor.yy237; - delete yymsp[-3].minor.yy66; - objectForTokens = yygotominor.yy399; + delete yymsp[-1].minor.yy451; + delete yymsp[-3].minor.yy360; + objectForTokens = yygotominor.yy283; } break; - case 399: /* cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW */ -{ yy_destructor(yypParser,181,&yymsp[-3].minor); + case 406: /* cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW */ +{ yy_destructor(yypParser,183,&yymsp[-3].minor); } break; - case 405: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 412: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { - yygotominor.yy399 = new SqliteCreateVirtualTable( - *(yymsp[-4].minor.yy237), - *(yymsp[-3].minor.yy211), - *(yymsp[-2].minor.yy211), - *(yymsp[0].minor.yy211) + yygotominor.yy283 = new SqliteCreateVirtualTable( + *(yymsp[-4].minor.yy451), + *(yymsp[-3].minor.yy399), + *(yymsp[-2].minor.yy399), + *(yymsp[0].minor.yy399) ); - delete yymsp[-4].minor.yy237; - delete yymsp[-3].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + delete yymsp[-4].minor.yy451; + delete yymsp[-3].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 406: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP */ + case 413: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP */ { - yygotominor.yy399 = new SqliteCreateVirtualTable( - *(yymsp[-7].minor.yy237), - *(yymsp[-6].minor.yy211), - *(yymsp[-5].minor.yy211), - *(yymsp[-3].minor.yy211), - *(yymsp[-1].minor.yy445) + yygotominor.yy283 = new SqliteCreateVirtualTable( + *(yymsp[-7].minor.yy451), + *(yymsp[-6].minor.yy399), + *(yymsp[-5].minor.yy399), + *(yymsp[-3].minor.yy399), + *(yymsp[-1].minor.yy95) ); - delete yymsp[-6].minor.yy211; - delete yymsp[-5].minor.yy211; - delete yymsp[-3].minor.yy211; - delete yymsp[-7].minor.yy237; - delete yymsp[-1].minor.yy445; - objectForTokens = yygotominor.yy399; + delete yymsp[-6].minor.yy399; + delete yymsp[-5].minor.yy399; + delete yymsp[-3].minor.yy399; + delete yymsp[-7].minor.yy451; + delete yymsp[-1].minor.yy95; + objectForTokens = yygotominor.yy283; } break; - case 409: /* vtabarglist ::= vtabarg */ + case 416: /* vtabarglist ::= vtabarg */ { - yygotominor.yy445 = new ParserStringList(); - yygotominor.yy445->append((yymsp[0].minor.yy211)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg - delete yymsp[0].minor.yy211; + yygotominor.yy95 = new QStringList(); + yygotominor.yy95->append((yymsp[0].minor.yy399)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg + delete yymsp[0].minor.yy399; } break; - case 410: /* vtabarglist ::= vtabarglist COMMA vtabarg */ + case 417: /* vtabarglist ::= vtabarglist COMMA vtabarg */ { - yymsp[-2].minor.yy445->append((yymsp[0].minor.yy211)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg - yygotominor.yy445 = yymsp[-2].minor.yy445; - delete yymsp[0].minor.yy211; + yymsp[-2].minor.yy95->append((yymsp[0].minor.yy399)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg + yygotominor.yy95 = yymsp[-2].minor.yy95; + delete yymsp[0].minor.yy399; DONT_INHERIT_TOKENS("vtabarglist"); } break; - case 412: /* vtabarg ::= vtabarg vtabargtoken */ + case 419: /* vtabarg ::= vtabarg vtabargtoken */ { - yymsp[-1].minor.yy211->append(" "+ *(yymsp[0].minor.yy211)); - yygotominor.yy211 = yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; + yymsp[-1].minor.yy399->append(" "+ *(yymsp[0].minor.yy399)); + yygotominor.yy399 = yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; } break; - case 413: /* vtabargtoken ::= ANY */ + case 420: /* vtabargtoken ::= ANY */ { - yygotominor.yy211 = new QString(yymsp[0].minor.yy0->value); + yygotominor.yy399 = new QString(yymsp[0].minor.yy0->value); } break; - case 414: /* vtabargtoken ::= LP anylist RP */ + case 421: /* vtabargtoken ::= LP anylist RP */ { - yygotominor.yy211 = new QString("("); - yygotominor.yy211->append(*(yymsp[-1].minor.yy211)); - yygotominor.yy211->append(")"); - delete yymsp[-1].minor.yy211; + yygotominor.yy399 = new QString("("); + yygotominor.yy399->append(*(yymsp[-1].minor.yy399)); + yygotominor.yy399->append(")"); + delete yymsp[-1].minor.yy399; } break; - case 416: /* anylist ::= anylist LP anylist RP */ + case 423: /* anylist ::= anylist LP anylist RP */ { - yygotominor.yy211 = yymsp[-3].minor.yy211; - yygotominor.yy211->append("("); - yygotominor.yy211->append(*(yymsp[-1].minor.yy211)); - yygotominor.yy211->append(")"); - delete yymsp[-1].minor.yy211; + yygotominor.yy399 = yymsp[-3].minor.yy399; + yygotominor.yy399->append("("); + yygotominor.yy399->append(*(yymsp[-1].minor.yy399)); + yygotominor.yy399->append(")"); + delete yymsp[-1].minor.yy399; DONT_INHERIT_TOKENS("anylist"); } break; - case 417: /* anylist ::= anylist ANY */ + case 424: /* anylist ::= anylist ANY */ { - yygotominor.yy211 = yymsp[-1].minor.yy211; - yygotominor.yy211->append(yymsp[0].minor.yy0->value); + yygotominor.yy399 = yymsp[-1].minor.yy399; + yygotominor.yy399->append(yymsp[0].minor.yy0->value); DONT_INHERIT_TOKENS("anylist"); } break; - case 418: /* with ::= */ -{yygotominor.yy367 = nullptr;} + case 425: /* with ::= */ +{yygotominor.yy321 = nullptr;} break; - case 419: /* with ::= WITH wqlist */ + case 426: /* with ::= WITH wqlist */ { - yygotominor.yy367 = yymsp[0].minor.yy367; - objectForTokens = yygotominor.yy367; + yygotominor.yy321 = yymsp[0].minor.yy321; + objectForTokens = yygotominor.yy321; } break; - case 420: /* with ::= WITH RECURSIVE wqlist */ + case 427: /* with ::= WITH RECURSIVE wqlist */ { - yygotominor.yy367 = yymsp[0].minor.yy367; - yygotominor.yy367->recursive = true; - objectForTokens = yygotominor.yy367; + yygotominor.yy321 = yymsp[0].minor.yy321; + yygotominor.yy321->recursive = true; + objectForTokens = yygotominor.yy321; } break; - case 421: /* wqlist ::= nm idxlist_opt AS LP select RP */ + case 428: /* wqlist ::= nm idxlist_opt AS LP select RP */ { - yygotominor.yy367 = SqliteWith::append(*(yymsp[-5].minor.yy211), *(yymsp[-4].minor.yy139), yymsp[-1].minor.yy123); - delete yymsp[-5].minor.yy211; - delete yymsp[-4].minor.yy139; + yygotominor.yy321 = SqliteWith::append(*(yymsp[-5].minor.yy399), *(yymsp[-4].minor.yy223), yymsp[-1].minor.yy473); + delete yymsp[-5].minor.yy399; + delete yymsp[-4].minor.yy223; } break; - case 422: /* wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP */ + case 429: /* wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP */ { - yygotominor.yy367 = SqliteWith::append(yymsp[-7].minor.yy367, *(yymsp[-5].minor.yy211), *(yymsp[-4].minor.yy139), yymsp[-1].minor.yy123); - delete yymsp[-5].minor.yy211; - delete yymsp[-4].minor.yy139; + yygotominor.yy321 = SqliteWith::append(yymsp[-7].minor.yy321, *(yymsp[-5].minor.yy399), *(yymsp[-4].minor.yy223), yymsp[-1].minor.yy473); + delete yymsp[-5].minor.yy399; + delete yymsp[-4].minor.yy223; DONT_INHERIT_TOKENS("wqlist"); } break; - case 423: /* wqlist ::= ID_TAB_NEW */ + case 430: /* wqlist ::= ID_TAB_NEW */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy367 = new SqliteWith(); + yygotominor.yy321 = new SqliteWith(); } break; default: diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h index 92a40ca..050ebd3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h @@ -131,12 +131,12 @@ #define TK3_DROP 131 #define TK3_ID_VIEW_NEW 132 #define TK3_ID_VIEW 133 -#define TK3_UNION 134 -#define TK3_ALL 135 -#define TK3_EXCEPT 136 -#define TK3_INTERSECT 137 -#define TK3_SELECT 138 -#define TK3_VALUES 139 +#define TK3_SELECT 134 +#define TK3_VALUES 135 +#define TK3_UNION 136 +#define TK3_ALL 137 +#define TK3_EXCEPT 138 +#define TK3_INTERSECT 139 #define TK3_DISTINCT 140 #define TK3_ID_ALIAS 141 #define TK3_FROM 142 @@ -151,17 +151,19 @@ #define TK3_WHERE 151 #define TK3_ID_COL 152 #define TK3_INTO 153 -#define TK3_CASE 154 -#define TK3_ID_FN 155 -#define TK3_ID_ERR_MSG 156 -#define TK3_VARIABLE 157 -#define TK3_WHEN 158 -#define TK3_THEN 159 -#define TK3_ELSE 160 -#define TK3_INDEX 161 -#define TK3_ID_IDX_NEW 162 -#define TK3_ID_PRAGMA 163 -#define TK3_ID_TRIG_NEW 164 -#define TK3_ID_TRIG 165 -#define TK3_ALTER 166 -#define TK3_ADD 167 +#define TK3_DO 154 +#define TK3_NOTHING 155 +#define TK3_CASE 156 +#define TK3_ID_FN 157 +#define TK3_ID_ERR_MSG 158 +#define TK3_VARIABLE 159 +#define TK3_WHEN 160 +#define TK3_THEN 161 +#define TK3_ELSE 162 +#define TK3_INDEX 163 +#define TK3_ID_IDX_NEW 164 +#define TK3_ID_PRAGMA 165 +#define TK3_ID_TRIG_NEW 166 +#define TK3_ID_TRIG 167 +#define TK3_ALTER 168 +#define TK3_ADD 169 diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y index 0dc9154..7e29506 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y @@ -55,6 +55,7 @@ #include "parser/ast/sqliteindexedcolumn.h" #include "parser/ast/sqliteforeignkey.h" #include "parser/ast/sqlitewith.h" +#include "parser/ast/sqliteupsert.h" #include <QObject> #include <QDebug> #include <limits.h> @@ -810,14 +811,6 @@ selectnowith(X) ::= selectnowith(S1) delete V; objectForTokens = X; } - -%type multiselect_op {SqliteSelect::CompoundOperator*} -%destructor multiselect_op {delete $$;} -multiselect_op(X) ::= UNION. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);} -multiselect_op(X) ::= UNION ALL. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);} -multiselect_op(X) ::= EXCEPT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);} -multiselect_op(X) ::= INTERSECT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);} - %type oneselect {SqliteSelect::Core*} %destructor oneselect {delete $$;} oneselect(X) ::= SELECT distinct(D) @@ -857,6 +850,13 @@ values(X) ::= values(L) COMMA LP DONT_INHERIT_TOKENS("values"); } +%type multiselect_op {SqliteSelect::CompoundOperator*} +%destructor multiselect_op {delete $$;} +multiselect_op(X) ::= UNION. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);} +multiselect_op(X) ::= UNION ALL. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);} +multiselect_op(X) ::= EXCEPT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);} +multiselect_op(X) ::= INTERSECT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);} + %type distinct {int*} %destructor distinct {delete $$;} distinct(X) ::= DISTINCT. {X = new int(1);} @@ -1005,6 +1005,23 @@ singlesrc(X) ::= LP joinsrc(J) RP as(A). { delete A; objectForTokens = X; } +singlesrc(X) ::= nm(N1) dbnm(N2) + LP exprlist(E) RP as(A). { + X = new SqliteSelect::Core::SingleSource( + *(N1), + *(N2), + A ? A->asKw : false, + A ? A->name : QString::null, + *(E) + ); + delete N1; + delete N2; + delete A; + if (E) + delete E; + + objectForTokens = X; + } singlesrc(X) ::= . { parserContext->minorErrorBeforeNextToken("Syntax error"); X = new SqliteSelect::Core::SingleSource(); @@ -1030,7 +1047,7 @@ joinconstr_opt(X) ::= ON expr(E). { objectForTokens = X; } joinconstr_opt(X) ::= USING LP - inscollist(L) RP. { + idlist(L) RP. { X = new SqliteSelect::Core::JoinConstraint(*(L)); delete L; objectForTokens = X; @@ -1321,13 +1338,23 @@ setlist(X) ::= setlist(L) COMMA nm(N) EQ L->append(ParserSetValue(*(N), E)); X = L; delete N; - DONT_INHERIT_TOKENS("setlist"); + } +setlist(X) ::= setlist(L) COMMA LP + idlist(N) RP EQ expr(E). { + L->append(ParserSetValue(*(N), E)); + X = L; + delete N; } setlist(X) ::= nm(N) EQ expr(E). { X = new ParserSetValueList(); X->append(ParserSetValue(*(N), E)); delete N; } +setlist(X) ::= LP idlist(N) RP EQ expr(E). { + X = new ParserSetValueList(); + X->append(ParserSetValue(*(N), E)); + delete N; + } setlist(X) ::= . { parserContext->minorErrorBeforeNextToken("Syntax error"); X = new ParserSetValueList(); @@ -1340,6 +1367,31 @@ setlist(X) ::= setlist(L) COMMA. { setlist ::= setlist COMMA ID_COL. {} setlist ::= ID_COL. {} +%type idlist_opt {QStringList*} +%destructor idlist_opt {delete $$;} +idlist_opt(X) ::= . {X = new QStringList();} +idlist_opt(X) ::= LP idlist(L) RP. {X = L;} + +%type idlist {QStringList*} +%destructor idlist {delete $$;} +idlist(X) ::= idlist(L) COMMA nm(N). { + X = L; + *(X) << *(N); + delete N; + } +idlist(X) ::= nm(N). { + X = new QStringList(); + *(X) << *(N); + delete N; + } +idlist(X) ::= . { + parserContext->minorErrorBeforeNextToken("Syntax error"); + X = new QStringList(); + } + +idlist ::= idlist COMMA ID_COL. {} +idlist ::= ID_COL. {} + ////////////////////////// The INSERT command ///////////////////////////////// cmd(X) ::= insert_stmt(S). { @@ -1352,7 +1404,8 @@ cmd(X) ::= insert_stmt(S). { insert_stmt(X) ::= with(W) insert_cmd(C) INTO fullname(N) - inscollist_opt(I) select(S). { + idlist_opt(I) select(S) + upsert(U). { X = new SqliteInsert( C->replace, C->orConflict, @@ -1360,7 +1413,8 @@ insert_stmt(X) ::= with(W) insert_cmd(C) N->name2, *(I), S, - W + W, + U ); delete N; delete C; @@ -1370,7 +1424,7 @@ insert_stmt(X) ::= with(W) insert_cmd(C) } insert_stmt(X) ::= with(W) insert_cmd(C) INTO fullname(N) - inscollist_opt(I) DEFAULT + idlist_opt(I) DEFAULT VALUES. { X = new SqliteInsert( C->replace, @@ -1424,32 +1478,33 @@ insert_cmd(X) ::= INSERT orconf(C). { } insert_cmd(X) ::= REPLACE. {X = new ParserStubInsertOrReplace(true);} -%type inscollist_opt {ParserStringList*} -%destructor inscollist_opt {delete $$;} -inscollist_opt(X) ::= . {X = new ParserStringList();} -inscollist_opt(X) ::= LP inscollist(L) RP. {X = L;} -%type inscollist {ParserStringList*} -%destructor inscollist {delete $$;} -inscollist(X) ::= inscollist(L) COMMA - nm(N). { - L->append(*(N)); - X = L; - delete N; - DONT_INHERIT_TOKENS("inscollist"); +%type upsert {SqliteUpsert*} +%destructor upsert {delete $$;} + +upsert(X) ::= . { + X = nullptr; } -inscollist(X) ::= nm(N). { - X = new ParserStringList(); - X->append(*(N)); - delete N; +upsert(X) ::= ON CONFLICT LP sortlist(C) RP + where_opt(CW) + DO UPDATE SET setlist(S) + where_opt(SW). + { + X = new SqliteUpsert(*(C), CW, *(S), SW); + delete C; + delete S; + objectForTokens = X; } -inscollist(X) ::= . { - parserContext->minorErrorBeforeNextToken("Syntax error"); - X = new ParserStringList(); +upsert(X) ::= ON CONFLICT LP sortlist(C) RP + where_opt(CW) DO NOTHING. { + X = new SqliteUpsert(*(C), CW); + delete C; + objectForTokens = X; + } +upsert(X) ::= ON CONFLICT DO NOTHING. { + X = new SqliteUpsert(); + objectForTokens = X; } - -inscollist ::= inscollist COMMA ID_COL. {} -inscollist ::= ID_COL. {} /////////////////////////// Expression Processing ///////////////////////////// @@ -2149,7 +2204,7 @@ trigger_event(X) ::= UPDATE. { objectForTokens = X; } trigger_event(X) ::= UPDATE OF - inscollist(L). { + idlist(L). { X = new SqliteCreateTrigger::Event(*(L)); delete L; objectForTokens = X; @@ -2341,10 +2396,10 @@ create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW. {} -%type vtabarglist {ParserStringList*} +%type vtabarglist {QStringList*} %destructor vtabarglist {delete $$;} vtabarglist(X) ::= vtabarg(A). { - X = new ParserStringList(); + X = new QStringList(); X->append((A)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg delete A; } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp index a0a0e3a..07d1976 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp @@ -29,7 +29,7 @@ StatementTokenBuilder&StatementTokenBuilder::withStringPossiblyOther(const QStri StatementTokenBuilder& StatementTokenBuilder::withOtherList(const QList<QString>& value, Dialect dialect, const QString& separator) { bool first = true; - foreach (const QString& str, value) + for (const QString& str : value) { if (!first) { @@ -47,7 +47,7 @@ StatementTokenBuilder& StatementTokenBuilder::withOtherList(const QList<QString> StatementTokenBuilder& StatementTokenBuilder::withOtherList(const QList<QString>& value, const QString& separator) { bool first = true; - foreach (const QString& str, value) + for (const QString& str : value) { if (!first) { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h index 14856e7..9ccfaa3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h @@ -238,7 +238,7 @@ class StatementTokenBuilder StatementTokenBuilder& withStatementList(QList<T*> stmtList, const QString& separator = ",") { bool first = true; - foreach (T* stmt, stmtList) + for (T* stmt : stmtList) { if (!first) { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp index 5396edd..cd7e4b0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp @@ -210,13 +210,21 @@ QString TokenList::toString() const QStringList TokenList::toStringList() const { QStringList strList; - TokenPtr t; - foreach (t, *this) + for (const TokenPtr& t : *this) strList << t->toString(); return strList; } +QStringList TokenList::toValueList() const +{ + QStringList strList; + for (const TokenPtr& t : *this) + strList << t->value; + + return strList; +} + int TokenList::indexOf(TokenPtr token) const { return QList<TokenPtr>::indexOf(token); @@ -301,7 +309,7 @@ TokenPtr TokenList::findLast(const QString& value, Qt::CaseSensitivity caseSensi TokenPtr TokenList::atCursorPosition(quint64 cursorPosition) const { - foreach (TokenPtr token, *this) + for (TokenPtr token : *this) { if (token->getRange().contains(cursorPosition)) return token; @@ -311,7 +319,7 @@ TokenPtr TokenList::atCursorPosition(quint64 cursorPosition) const void TokenList::insert(int i, const TokenList &list) { - foreach (TokenPtr token, list) + for (TokenPtr token : list) QList<TokenPtr>::insert(i++, token); } @@ -483,7 +491,7 @@ TokenList& TokenList::trim(Token::Type type, const QString& alsoTrim) TokenList TokenList::filter(Token::Type type) const { TokenList filtered; - foreach (TokenPtr token, *this) + for (TokenPtr token : *this) if (token->type == type) filtered << token; @@ -493,7 +501,7 @@ TokenList TokenList::filter(Token::Type type) const TokenList TokenList::filterOut(Token::Type type) const { TokenList filtered; - foreach (TokenPtr token, *this) + for (TokenPtr token : *this) if (token->type != type) filtered << token; @@ -503,7 +511,7 @@ TokenList TokenList::filterOut(Token::Type type) const TokenList TokenList::filterWhiteSpaces(bool includeComments) const { TokenList filtered; - foreach (TokenPtr token, *this) + for (TokenPtr token : *this) if (!token->isWhitespace(includeComments)) filtered << token; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/token.h b/SQLiteStudio3/coreSQLiteStudio/parser/token.h index aeb505c..85c46c1 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/token.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/token.h @@ -253,7 +253,7 @@ struct API_EXPORT Token /** * @brief Literal value of the token, captured directly from the query. */ - QString value = QString::null; + QString value; /** * @brief Start position (first character index) of the token in the query. @@ -335,6 +335,12 @@ class API_EXPORT TokenList : public QList<TokenPtr> QStringList toStringList() const; /** + * @brief Converts list of tokens into list of their values. + * @return List of tokens values. + */ + QStringList toValueList() const; + + /** * @brief Provides index of first occurrence of the token in the list. * @param token Token to look for. * @return Index of the token, or -1 if token was not found. diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/plugin.h b/SQLiteStudio3/coreSQLiteStudio/plugins/plugin.h index 183adf7..8cbbe78 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/plugin.h +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/plugin.h @@ -34,7 +34,7 @@ class CfgMain; * }; * @endcode * - * Full tutorial for writting plugins is at: http://wiki.sqlitestudio.pl/index.php/Writting_plugins + * Full tutorial for writting plugins is at: https://github.com/pawelsalawa/sqlitestudio/wiki/Writting_plugins * * SQLiteStudio looks for plugins in following directories: * <ul> diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/pluginsymbolresolver.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/pluginsymbolresolver.cpp index 39988bd..43540b0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/pluginsymbolresolver.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/pluginsymbolresolver.cpp @@ -19,14 +19,14 @@ void PluginSymbolResolver::addLookupSubFolder(const QString &name) bool PluginSymbolResolver::load() { QStringList paths = qApp->libraryPaths(); - foreach (QString path, paths) - foreach (QString subFolder, subFolders) + for (QString path : paths) + for (QString subFolder : subFolders) paths << path + "/" + subFolder; - foreach (QString path, paths) + for (QString path : paths) { QDir dir(path); - foreach (QString file, dir.entryList(nameFilters)) + for (QString file : dir.entryList(nameFilters)) { lib.setFileName(path+"/"+file); if (lib.load()) diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/populatedictionary.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/populatedictionary.cpp index 3d78de5..fd654ad 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/populatedictionary.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/populatedictionary.cpp @@ -35,7 +35,7 @@ bool PopulateDictionaryEngine::beforePopulating(Db* db, const QString& table) file.close(); if (cfg.PopulateDictionary.Lines.get()) - dictionary = dataStr.split("\n"); + dictionary = dataStr.split(QRegExp("(\r\n|\n|\r)")); else dictionary = dataStr.split(QRegExp("\\s+")); diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp index 334c0cc..79824dc 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp @@ -221,7 +221,7 @@ bool ScriptingQt::init() void ScriptingQt::deinit() { - foreach (Context* ctx, contexts) + for (Context* ctx : contexts) delete ctx; contexts.clear(); diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/sqlformatterplugin.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/sqlformatterplugin.cpp index 5e1d610..350c024 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/sqlformatterplugin.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/sqlformatterplugin.cpp @@ -17,7 +17,7 @@ QString SqlFormatterPlugin::format(const QString& code, Db* contextDb) } QStringList formattedQueries; - foreach (SqliteQueryPtr query, parser.getQueries()) + for (SqliteQueryPtr query : parser.getQueries()) formattedQueries << format(query); return formattedQueries.join("\n"); diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/uiconfiguredplugin.h b/SQLiteStudio3/coreSQLiteStudio/plugins/uiconfiguredplugin.h index 1426117..b2a0b8d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/uiconfiguredplugin.h +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/uiconfiguredplugin.h @@ -15,7 +15,7 @@ class API_EXPORT UiConfiguredPlugin * * This method should return the object name of the top-most widget found in the provided *.ui file. * - * For more details see: http://wiki.sqlitestudio.pl/index.php/Plugin_UI_forms + * For more details see: https://github.com/pawelsalawa/sqlitestudio/wiki/Plugin_UI_forms */ virtual QString getConfigUiForm() const = 0; diff --git a/SQLiteStudio3/coreSQLiteStudio/populateworker.cpp b/SQLiteStudio3/coreSQLiteStudio/populateworker.cpp index f25a6ac..e1c207a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/populateworker.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/populateworker.cpp @@ -57,6 +57,13 @@ void PopulateWorker::run() for (PopulateEngine* engine : engines) args << engine->nextValue(nextValueError); + if (nextValueError) + { + db->rollback(); + emit finished(false); + return; + } + query->setArgs(args); if (!query->execute()) { diff --git a/SQLiteStudio3/coreSQLiteStudio/querygenerator.cpp b/SQLiteStudio3/coreSQLiteStudio/querygenerator.cpp index c10e8f7..75b0e89 100644 --- a/SQLiteStudio3/coreSQLiteStudio/querygenerator.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/querygenerator.cpp @@ -41,7 +41,7 @@ QString QueryGenerator::generateInsertToTable(Db* db, const QString& database, c if (values.isEmpty()) { QStringList valueList = wrapStrings(tableCols); - QList<QString> wrappedCols = wrapObjNamesIfNeeded(tableCols, dialect); + QStringList wrappedCols = wrapObjNamesIfNeeded(tableCols, dialect); return tpl.arg(target, wrappedCols.join(", "), rowTpl.arg(valueList.join(", "))); } @@ -54,7 +54,7 @@ QString QueryGenerator::generateInsertToTable(Db* db, const QString& database, c QString valueStr = rowTpl.arg(valueSets.join("), (")); // Wrap given column names - QList<QString> wrappedCols = wrapObjNamesIfNeeded(valueCols, dialect); + QStringList wrappedCols = wrapObjNamesIfNeeded(valueCols, dialect); return tpl.arg(target, wrappedCols.join(", "), valueStr); } diff --git a/SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp b/SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp index 48fe541..62a685c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp @@ -76,7 +76,7 @@ StrHash< QStringList> SchemaResolver::getGroupedObjects(const QString &database, SqliteQueryPtr parsedQuery; SqliteTableRelatedDdlPtr tableRelatedDdl; - foreach (QString object, inputList) + for (QString object : inputList) { parsedQuery = getParsedObject(database, object, ANY); if (!parsedQuery) @@ -136,7 +136,7 @@ QStringList SchemaResolver::getTableColumns(const QString &database, const QStri if (!createTable && !createVirtualTable) { qDebug() << "Parsed DDL is neither a CREATE TABLE or CREATE VIRTUAL TABLE statement. It's: " - << sqliteQueryTypeToString(query->queryType); + << sqliteQueryTypeToString(query->queryType) << "when trying to parse DDL of" << database << table; return columns; } @@ -150,7 +150,7 @@ QStringList SchemaResolver::getTableColumns(const QString &database, const QStri } // Now we have a regular table, let's extract columns. - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) columns << column->name; return columns; @@ -193,7 +193,7 @@ QList<DataType> SchemaResolver::getTableColumnDataTypes(const QString& database, StrHash<QStringList> SchemaResolver::getAllTableColumns(const QString &database) { StrHash< QStringList> tableColumns; - foreach (QString table, getTables(database)) + for (QString table : getTables(database)) tableColumns[table] = getTableColumns(database, table); return tableColumns; @@ -208,7 +208,7 @@ QStringList SchemaResolver::getViewColumns(const QString& database, const QStrin { QList<SelectResolver::Column> resolvedColumns = getViewColumnObjects(database, view); QStringList columns; - foreach (const SelectResolver::Column& col, resolvedColumns) + for (const SelectResolver::Column& col : resolvedColumns) columns << col.displayName; return columns; @@ -555,7 +555,7 @@ SqliteQueryPtr SchemaResolver::getParsedDdl(const QString& ddl) if (!parser->parse(ddl)) { qDebug() << "Could not parse DDL for parsing object by SchemaResolver. Errors are:"; - foreach (ParserError* err, parser->getErrors()) + for (ParserError* err : parser->getErrors()) qDebug() << err->getMessage(); return SqliteQueryPtr(); @@ -591,7 +591,7 @@ QStringList SchemaResolver::getObjects(const QString &database, const QString &t SqlQueryPtr results = db->exec(QString("SELECT name FROM %1.sqlite_master WHERE type = ?;").arg(dbName), {type}, dbFlags); QString value; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) { value = row->value(0).toString(); if (!isFilteredOut(value, type)) @@ -623,7 +623,7 @@ QStringList SchemaResolver::getAllObjects(const QString& database) QString value; QString type; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) { value = row->value("name").toString(); type = row->value("type").toString(); @@ -720,7 +720,7 @@ QStringList SchemaResolver::getFkReferencingTables(const QString& table, const Q QStringList SchemaResolver::getIndexesForTable(const QString& database, const QString& table) { QStringList names; - foreach (SqliteCreateIndexPtr idx, getParsedIndexesForTable(database, table)) + for (SqliteCreateIndexPtr idx : getParsedIndexesForTable(database, table)) names << idx->index; return names; @@ -734,7 +734,7 @@ QStringList SchemaResolver::getIndexesForTable(const QString& table) QStringList SchemaResolver::getTriggersForTable(const QString& database, const QString& table) { QStringList names; - foreach (SqliteCreateTriggerPtr trig, getParsedTriggersForTable(database, table)) + for (SqliteCreateTriggerPtr trig : getParsedTriggersForTable(database, table)) names << trig->trigger; return names; @@ -748,7 +748,7 @@ QStringList SchemaResolver::getTriggersForTable(const QString& table) QStringList SchemaResolver::getTriggersForView(const QString& database, const QString& view) { QStringList names; - foreach (SqliteCreateTriggerPtr trig, getParsedTriggersForView(database, view)) + for (SqliteCreateTriggerPtr trig : getParsedTriggersForView(database, view)) names << trig->trigger; return names; @@ -762,7 +762,7 @@ QStringList SchemaResolver::getTriggersForView(const QString& view) QStringList SchemaResolver::getViewsForTable(const QString& database, const QString& table) { QStringList names; - foreach (SqliteCreateViewPtr view, getParsedViewsForTable(database, table)) + for (SqliteCreateViewPtr view : getParsedViewsForTable(database, table)) names << view->view; return names; @@ -885,7 +885,7 @@ QList<SqliteCreateTriggerPtr> SchemaResolver::getParsedTriggersForTableOrView(co QStringList triggers = getTriggers(database); SqliteQueryPtr query; SqliteCreateTriggerPtr createTrigger; - foreach (const QString& trig, triggers) + for (const QString& trig : triggers) { query = getParsedObject(database, trig, TRIGGER); if (!query) @@ -963,7 +963,7 @@ QList<SqliteCreateViewPtr> SchemaResolver::getParsedViewsForTable(const QString& QStringList views = getViews(database); SqliteQueryPtr query; SqliteCreateViewPtr createView; - foreach (const QString& view, views) + for (const QString& view : views) { query = getParsedObject(database, view, VIEW); if (!query) diff --git a/SQLiteStudio3/coreSQLiteStudio/schemaresolver.h b/SQLiteStudio3/coreSQLiteStudio/schemaresolver.h index 676d0f5..fb19cee 100644 --- a/SQLiteStudio3/coreSQLiteStudio/schemaresolver.h +++ b/SQLiteStudio3/coreSQLiteStudio/schemaresolver.h @@ -234,7 +234,7 @@ StrHash<QSharedPointer<T>> SchemaResolver::getAllParsedObjectsForType(const QStr QString name; SqliteQueryPtr parsedObject; QSharedPointer<T> castedObject; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) { name = row->value("name").toString(); parsedObject = getParsedDdl(row->value("sql").toString()); diff --git a/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp b/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp index 1b7e33d..64da5b2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp @@ -47,12 +47,14 @@ QList<QList<SelectResolver::Column>> SelectResolver::resolveColumns() QList<SelectResolver::Column> SelectResolver::resolve(SqliteSelect::Core *selectCore) { errors.clear(); + extractCte(selectCore); return resolveCore(selectCore); } QList<QList<SelectResolver::Column>> SelectResolver::resolve(SqliteSelect *select) { errors.clear(); + extractCte(select); QList<QList<SelectResolver::Column> > results; for (SqliteSelect::Core* core : select->coreSelects) { @@ -66,12 +68,14 @@ QList<QList<SelectResolver::Column>> SelectResolver::resolve(SqliteSelect *selec QList<SelectResolver::Column> SelectResolver::resolveAvailableColumns(SqliteSelect::Core *selectCore) { errors.clear(); + extractCte(selectCore); return resolveAvailableCoreColumns(selectCore); } QList<QList<SelectResolver::Column> > SelectResolver::resolveAvailableColumns(SqliteSelect *select) { errors.clear(); + extractCte(select); QList<QList<SelectResolver::Column> > results; for (SqliteSelect::Core* core : select->coreSelects) results << resolveAvailableCoreColumns(core); @@ -82,6 +86,7 @@ QList<QList<SelectResolver::Column> > SelectResolver::resolveAvailableColumns(Sq QSet<SelectResolver::Table> SelectResolver::resolveTables(SqliteSelect::Core *selectCore) { QSet<Table> tables; + extractCte(selectCore); QList<Column> columns = resolveAvailableColumns(selectCore); for (const Column& col : columns) { @@ -97,6 +102,7 @@ QSet<SelectResolver::Table> SelectResolver::resolveTables(SqliteSelect::Core *se QList<QSet<SelectResolver::Table> > SelectResolver::resolveTables(SqliteSelect *select) { QList<QSet<Table> > results; + extractCte(select); QList<QList<Column> > columnLists = resolveAvailableColumns(select); for (const QList<Column>& columns : columnLists) { @@ -118,6 +124,7 @@ QList<QSet<SelectResolver::Table> > SelectResolver::resolveTables(SqliteSelect * QList<SelectResolver::Column> SelectResolver::translateToColumns(SqliteSelect* select, const TokenList& columnTokens) { errors.clear(); + extractCte(select); QList<SelectResolver::Column> results; for (const TokenPtr& token : columnTokens) results << translateTokenToColumn(select, token); @@ -175,7 +182,7 @@ QList<SelectResolver::Column> SelectResolver::resolveAvailableCoreColumns(Sqlite SqliteSelect* select = dynamic_cast<SqliteSelect*>(selectCore->parentStatement()); if (select && select->with) - markCteColumns(); + markCteColumns(&columns); return columns; } @@ -237,9 +244,9 @@ void SelectResolver::markCompoundColumns() markCurrentColumnsWithFlag(FROM_COMPOUND_SELECT); } -void SelectResolver::markCteColumns() +void SelectResolver::markCteColumns(QList<Column>* columnList) { - markCurrentColumnsWithFlag(FROM_CTE_SELECT); + markCurrentColumnsWithFlag(FROM_CTE_SELECT, columnList); } void SelectResolver::markGroupedColumns() @@ -283,9 +290,9 @@ void SelectResolver::fixColumnNames() } } -void SelectResolver::markCurrentColumnsWithFlag(SelectResolver::Flag flag) +void SelectResolver::markCurrentColumnsWithFlag(SelectResolver::Flag flag, QList<Column>* columnList) { - QMutableListIterator<Column> it(currentCoreResults); + QMutableListIterator<Column> it(columnList ? *columnList : currentCoreResults); while (it.hasNext()) it.next().flags |= flag; } @@ -528,6 +535,24 @@ TokenList SelectResolver::getResColTokensWithoutAlias(SqliteSelect::Core::Result return allTokens; } +void SelectResolver::extractCte(SqliteSelect *select) +{ + cteList.clear(); + if (!select->with) + return; + + for (SqliteWith::CommonTableExpression* cte : select->with->cteList) + cteList[cte->table] = cte; +} + +void SelectResolver::extractCte(SqliteSelect::Core *core) +{ + if (!core->parentStatement()) + return; + + extractCte(dynamic_cast<SqliteSelect*>(core->parentStatement())); +} + QList<SelectResolver::Column> SelectResolver::resolveJoinSource(SqliteSelect::Core::JoinSource *joinSrc) { QList<SelectResolver::Column> columnSources; @@ -549,28 +574,56 @@ QList<SelectResolver::Column> SelectResolver::resolveSingleSource(SqliteSelect:: if (joinSrc->joinSource) return resolveJoinSource(joinSrc->joinSource); + if (!joinSrc->funcName.isNull()) + return resolveTableFunctionColumns(joinSrc); + if (isView(joinSrc->database, joinSrc->table)) return resolveView(joinSrc->database, joinSrc->table, joinSrc->alias); QList<Column> columnSources; QStringList columns = getTableColumns(joinSrc->database, joinSrc->table, joinSrc->alias); Column column; + column.type = Column::COLUMN; + column.table = joinSrc->table;; + column.database = joinSrc->database; + column.originalDatabase = resolveDatabase(joinSrc->database); + if (!joinSrc->alias.isNull()) + column.tableAlias = joinSrc->alias; + for (const QString& columnName : columns) { - column.type = Column::COLUMN; column.column = columnName; - column.table = joinSrc->table;; - column.database = joinSrc->database; - column.originalDatabase = resolveDatabase(joinSrc->database); - if (!joinSrc->alias.isNull()) - column.tableAlias = joinSrc->alias; - columnSources << column; } return columnSources; } +QList<SelectResolver::Column> SelectResolver::resolveTableFunctionColumns(SqliteSelect::Core::SingleSource *joinSrc) +{ + static_qstring(columnSqlTpl, "SELECT * FROM %1 LIMIT 0"); + SqlQueryPtr result = db->exec(columnSqlTpl.arg(joinSrc->detokenize())); + if (result->isError()) + errors << result->getErrorText(); + + QStringList columnNames = result->getColumnNames(); + + QList<Column> columnSources; + Column column; + column.type = Column::OTHER; + column.database = joinSrc->database; + column.originalDatabase = resolveDatabase(joinSrc->database); + if (!joinSrc->alias.isNull()) + column.tableAlias = joinSrc->alias; + + for (const QString& columnName : columnNames) + { + column.column = columnName; + columnSources << column; + } + return columnSources; +} + QList<SelectResolver::Column> SelectResolver::resolveSingleSourceSubSelect(SqliteSelect::Core::SingleSource *joinSrc) { QList<Column> columnSources = resolveSubSelect(joinSrc->select); @@ -652,7 +705,17 @@ QStringList SelectResolver::getTableColumns(const QString &database, const QStri dbTable.tableAlias = alias; if (tableColumnsCache.contains(dbTable)) + { return tableColumnsCache.value(dbTable); + } + else if (database.isNull() && cteList.contains(table)) + { + QStringList columns; + for (SqliteIndexedColumn* idxCol : cteList[table]->indexedColumns) + columns << idxCol->name; + + return columns; + } else { QStringList columns = schemaResolver->getTableColumns(database, table); diff --git a/SQLiteStudio3/coreSQLiteStudio/selectresolver.h b/SQLiteStudio3/coreSQLiteStudio/selectresolver.h index 7640fc6..92924ea 100644 --- a/SQLiteStudio3/coreSQLiteStudio/selectresolver.h +++ b/SQLiteStudio3/coreSQLiteStudio/selectresolver.h @@ -5,6 +5,7 @@ #include "common/bistrhash.h" #include "dialect.h" #include "expectedtoken.h" +#include "parser/ast/sqlitewith.h" #include <QString> #include <QHash> #include <QStringList> @@ -106,7 +107,6 @@ class API_EXPORT SelectResolver QString alias; QString displayName; bool aliasDefinedInSubQuery = false; - int flags = 0; SqliteSelect::Core::ResultColumn* originalColumn = nullptr; int operator==(const Column& other); @@ -204,6 +204,7 @@ class API_EXPORT SelectResolver QList<Column> resolveJoinSource(SqliteSelect::Core::JoinSource* joinSrc); QList<Column> resolveSingleSource(SqliteSelect::Core::SingleSource* joinSrc); + QList<Column> resolveTableFunctionColumns(SqliteSelect::Core::SingleSource* joinSrc); QList<Column> resolveSingleSourceSubSelect(SqliteSelect::Core::SingleSource* joinSrc); QList<Column> resolveOtherSource(SqliteSelect::Core::JoinSourceOther *otherSrc); QList<Column> resolveSubSelect(SqliteSelect* select); @@ -216,16 +217,19 @@ class API_EXPORT SelectResolver void markDistinctColumns(); void markCompoundColumns(); - void markCteColumns(); + void markCteColumns(QList<Column>* columnList = nullptr); void markGroupedColumns(); void fixColumnNames(); - void markCurrentColumnsWithFlag(Flag flag); + void markCurrentColumnsWithFlag(Flag flag, QList<Column>* columnList = nullptr); bool matchTable(const Column& sourceColumn, const QString& table); TokenList getResColTokensWithoutAlias(SqliteSelect::Core::ResultColumn *resCol); + void extractCte(SqliteSelect* select); + void extractCte(SqliteSelect::Core* core); Db* db = nullptr; QString query; SqliteSelectPtr originalQueryParsed; + QHash<QString, SqliteWith::CommonTableExpression*> cteList; /** * @brief Database name to attach name map. diff --git a/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.cpp b/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.cpp deleted file mode 100644 index 54b0905..0000000 --- a/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "bugreporter.h" -#include "services/config.h" -#include "services/notifymanager.h" -#include <QNetworkAccessManager> -#include <QNetworkReply> -#include <QNetworkRequest> -#include <QUrlQuery> - -BugReporter::BugReporter(QObject *parent) : - QObject(parent) -{ - networkManager = new QNetworkAccessManager(this); - connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*))); -} - -QUrl BugReporter::getReporterEmailHelpUrl() const -{ - return QUrl(QString::fromLatin1(reporterEmailHelpUrl)); -} - -QUrl BugReporter::getReporterUserAndPasswordHelpUrl() const -{ - return QUrl(QString::fromLatin1(reporterUserPassHelpUrl)); -} - -void BugReporter::validateBugReportCredentials(const QString& login, const QString& password) -{ - if (credentialsValidationInProgress) - { - credentialsValidationInProgress->abort(); - credentialsValidationInProgress->deleteLater(); - } - - QUrlQuery query; - query.addQueryItem("validateUser", login); - query.addQueryItem("password", password); - - QUrl url = QUrl(QString::fromLatin1(bugReportServiceUrl) + "?" + query.query(QUrl::FullyEncoded)); - QNetworkRequest request(url); - credentialsValidationInProgress = networkManager->get(request); - replyToHandler[credentialsValidationInProgress] = [this](bool success, const QString& data) - { - if (success && data.trimmed() != "OK") - { - success = false; - emit credentialsValidationResult(success, tr("Invalid login or password")); - } - else - { - emit credentialsValidationResult(success, success ? QString() : data); - } - }; -} - -void BugReporter::abortCredentialsValidation() -{ - if (credentialsValidationInProgress) - { - credentialsValidationInProgress->abort(); - credentialsValidationInProgress->deleteLater(); - credentialsValidationInProgress = nullptr; - } -} - -void BugReporter::useBugReportCredentials(const QString& login, const QString& password) -{ - CFG_CORE.Internal.BugReportUser.set(login); - CFG_CORE.Internal.BugReportPassword.set(password); -} - -void BugReporter::clearBugReportCredentials() -{ - CFG_CORE.Internal.BugReportUser.set(QString()); - CFG_CORE.Internal.BugReportPassword.set(QString()); -} - -void BugReporter::reportBug(const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, BugReporter::ResponseHandler responseHandler, const QString& urlSuffix) -{ - static_qstring(contentsTpl, "%1\n\n<b>Plugins loaded:</b>\n%2\n\n<b>Version:</b>\n%3\n\n<b>Operating System:</b>\n%4"); - QString contents = contentsTpl.arg(escapeParam(details), plugins, version, os); - - QUrlQuery query; - query.addQueryItem("brief", escapeParam(title)); - query.addQueryItem("contents", contents); - query.addQueryItem("os", os); - query.addQueryItem("version", version); - query.addQueryItem("featureRequest", "0"); - - QUrl url = QUrl(QString::fromLatin1(bugReportServiceUrl) + "?" + escapeUrl(query.query(QUrl::FullyEncoded) + urlSuffix)); - QNetworkRequest request(url); - QNetworkReply* reply = networkManager->get(request); - if (responseHandler) - replyToHandler[reply] = responseHandler; - - replyToTypeAndTitle[reply] = QPair<bool,QString>(false, title); -} - -void BugReporter::requestFeature(const QString& title, const QString& details, BugReporter::ResponseHandler responseHandler, const QString& urlSuffix) -{ - QUrlQuery query; - query.addQueryItem("brief", escapeParam(title)); - query.addQueryItem("contents", escapeParam(details)); - query.addQueryItem("featureRequest", "1"); - - QUrl url = QUrl(QString::fromLatin1(bugReportServiceUrl) + "?" + escapeUrl(query.query(QUrl::FullyEncoded) + urlSuffix)); - QNetworkRequest request(url); - QNetworkReply* reply = networkManager->get(request); - if (responseHandler) - replyToHandler[reply] = responseHandler; - - replyToTypeAndTitle[reply] = QPair<bool,QString>(true, title); -} - -QString BugReporter::escapeParam(const QString &input) -{ - return input.toHtmlEscaped(); -} - -QString BugReporter::escapeUrl(const QString &input) -{ - // For some reason the ";" character is not encodedy by QUrlQuery when using FullEncoded. Pity. We have to do it manually. - QString copy = input; - return copy.replace(";", "%3B"); -} - -void BugReporter::finished(QNetworkReply* reply) -{ - if (reply == credentialsValidationInProgress) - credentialsValidationInProgress = nullptr; - - if (!replyToHandler.contains(reply)) - { - reply->deleteLater(); - return; - } - - bool success = (reply->error() == QNetworkReply::NoError); - QString data; - if (success) - data = QString::fromLatin1(reply->readAll()); - else - data = reply->errorString(); - - replyToHandler[reply](success, data); - replyToHandler.remove(reply); - - if (replyToTypeAndTitle.contains(reply)) - { - if (success) - CFG->addReportHistory(replyToTypeAndTitle[reply].first, replyToTypeAndTitle[reply].second, data); - - replyToTypeAndTitle.remove(reply); - } - - reply->deleteLater(); -} - -void BugReporter::reportBug(const QString& email, const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, - ResponseHandler responseHandler) -{ - QUrlQuery query; - query.addQueryItem("byEmail", email); - QString urlSuffix = "&" + query.query(QUrl::FullyEncoded); - - reportBug(title, details, version, os, plugins, responseHandler, urlSuffix); -} - -void BugReporter::reportBug(const QString& title, const QString& details, const QString& version, const QString& os, - const QString& plugins, ResponseHandler responseHandler) -{ - QString user = CFG_CORE.Internal.BugReportUser.get(); - QString pass = CFG_CORE.Internal.BugReportPassword.get(); - - QUrlQuery query; - query.addQueryItem("byUser", user); - query.addQueryItem("password", pass); - QString urlSuffix = "&" + query.query(QUrl::FullyEncoded); - - reportBug(title, details, version, os, plugins, responseHandler, urlSuffix); -} - -void BugReporter::requestFeature(const QString& email, const QString& title, const QString& details, ResponseHandler responseHandler) -{ - QUrlQuery query; - query.addQueryItem("byEmail", email); - QString urlSuffix = "&" + query.query(QUrl::FullyEncoded); - - requestFeature(title, details, responseHandler, urlSuffix); -} - -void BugReporter::requestFeature(const QString& title, const QString& details, ResponseHandler responseHandler) -{ - QString user = CFG_CORE.Internal.BugReportUser.get(); - QString pass = CFG_CORE.Internal.BugReportPassword.get(); - - QUrlQuery query; - query.addQueryItem("byUser", user); - query.addQueryItem("password", pass); - QString urlSuffix = "&" + query.query(QUrl::FullyEncoded); - - requestFeature(title, details, responseHandler, urlSuffix); -} diff --git a/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.h b/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.h deleted file mode 100644 index 3e8eb8d..0000000 --- a/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef BUGREPORTER_H -#define BUGREPORTER_H - -#include "common/global.h" -#include "sqlitestudio.h" -#include <QObject> -#include <QHash> - -class QNetworkAccessManager; -class QNetworkReply; - -class API_EXPORT BugReporter : public QObject -{ - Q_OBJECT - - public: - typedef std::function<void(bool success, const QString& data)> ResponseHandler; - - explicit BugReporter(QObject *parent = 0); - - QUrl getReporterEmailHelpUrl() const; - QUrl getReporterUserAndPasswordHelpUrl() const; - void validateBugReportCredentials(const QString& login, const QString& password); - void abortCredentialsValidation(); - void useBugReportCredentials(const QString& login, const QString& password); - void clearBugReportCredentials(); - - private: - void reportBug(const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, - ResponseHandler responseHandler, const QString& urlSuffix); - void requestFeature(const QString& title, const QString& details, ResponseHandler responseHandler, const QString& urlSuffix); - - static QString escapeParam(const QString& input); - static QString escapeUrl(const QString& input); - - QNetworkAccessManager* networkManager = nullptr; - QHash<QNetworkReply*,ResponseHandler> replyToHandler; - QHash<QNetworkReply*,QPair<bool,QString>> replyToTypeAndTitle; - QNetworkReply* credentialsValidationInProgress = nullptr; - - static_char* bugReportServiceUrl = "http://sqlitestudio.pl/report_bug3.rvt"; - static_char* reporterEmailHelpUrl = "http://wiki.sqlitestudio.pl/index.php/User_Manual#Reporter_email_address"; - static_char* reporterUserPassHelpUrl = "http://wiki.sqlitestudio.pl/index.php/User_Manual#Reporter_user_and_password"; - - signals: - void credentialsValidationResult(bool success, const QString& errorMessage); - - private slots: - void finished(QNetworkReply* reply); - - public slots: - void reportBug(const QString& email, const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, - ResponseHandler responseHandler = nullptr); - void reportBug(const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, - ResponseHandler responseHandler = nullptr); - void requestFeature(const QString& email, const QString& title, const QString& details, ResponseHandler responseHandler = nullptr); - void requestFeature(const QString& title, const QString& details, ResponseHandler responseHandler = nullptr); -}; - -#define BUGS SQLITESTUDIO->getBugReporter() - -#endif // BUGREPORTER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/services/config.h b/SQLiteStudio3/coreSQLiteStudio/services/config.h index 1e4c410..202120a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/config.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/config.h @@ -20,6 +20,8 @@ CFG_CATEGORIES(Core, CFG_CATEGORY(General, CFG_ENTRY(int, SqlHistorySize, 10000) CFG_ENTRY(int, DdlHistorySize, 1000) + CFG_ENTRY(int, BindParamsCacheSize, 1000) + CFG_ENTRY(int, PopulateHistorySize, 100) CFG_ENTRY(QString, LoadedPlugins, "") CFG_ENTRY(QVariantHash, ActiveCodeFormatter, QVariantHash()) CFG_ENTRY(bool, CheckUpdatesOnStartup, true) @@ -31,6 +33,7 @@ CFG_CATEGORIES(Core, CFG_CATEGORY(Internal, CFG_ENTRY(QVariantList, Functions, QVariantList()) CFG_ENTRY(QVariantList, Collations, QVariantList()) + CFG_ENTRY(QVariantList, Extensions, QVariantList()) CFG_ENTRY(QString, BugReportUser, QString()) CFG_ENTRY(QString, BugReportPassword, QString()) CFG_ENTRY(QString, BugReportRecentTitle, QString()) @@ -118,6 +121,7 @@ class API_EXPORT Config : public QObject virtual bool isMassSaving() const = 0; virtual void set(const QString& group, const QString& key, const QVariant& value) = 0; virtual QVariant get(const QString& group, const QString& key) = 0; + virtual QVariant get(const QString& group, const QString& key, const QVariant& defaultValue) = 0; virtual QHash<QString,QVariant> getAll() = 0; virtual bool addDb(const QString& name, const QString& path, const QHash<QString, QVariant> &options) = 0; @@ -144,6 +148,7 @@ class API_EXPORT Config : public QObject virtual qint64 addSqlHistory(const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected) = 0; virtual void updateSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected) = 0; virtual void clearSqlHistory() = 0; + virtual void deleteSqlHistory(const QList<qint64>& ids) = 0; virtual QAbstractItemModel* getSqlHistoryModel() = 0; virtual void addCliHistory(const QString& text) = 0; @@ -151,6 +156,15 @@ class API_EXPORT Config : public QObject virtual void clearCliHistory() = 0; virtual QStringList getCliHistory() const = 0; + virtual void addBindParamHistory(const QVector<QPair<QString, QVariant>>& params) = 0; + virtual void applyBindParamHistoryLimit() = 0; + virtual QVector<QPair<QString, QVariant>> getBindParamHistory(const QStringList& paramNames) const = 0; + + virtual void addPopulateHistory(const QString& database, const QString& table, int rows, const QHash<QString, QPair<QString, QVariant>>& columnsPluginsConfig) = 0; + virtual void applyPopulateHistoryLimit() = 0; + virtual QHash<QString, QPair<QString, QVariant>> getPopulateHistory(const QString& database, const QString& table, int& rows) const = 0; + virtual QVariant getPopulateHistory(const QString& pluginName) const = 0; + virtual void addDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile) = 0; virtual QList<DdlHistoryEntryPtr> getDdlHistoryFor(const QString& dbName, const QString& dbFile, const QDate& date) = 0; virtual DdlHistoryModel* getDdlHistoryModel() = 0; diff --git a/SQLiteStudio3/coreSQLiteStudio/services/dbmanager.h b/SQLiteStudio3/coreSQLiteStudio/services/dbmanager.h index 52746e4..2b5fa41 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/dbmanager.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/dbmanager.h @@ -144,12 +144,13 @@ class API_EXPORT DbManager : public QObject /** * @brief Creates in-memory SQLite3 database. + * @param pureInit If true, avoids registering collations/functions/extensions in a database. Skips rich initialization and gives pure database connection. * @return Created database. * * Created database can be used for any purpose. Note that DbManager doesn't own created * database and it's up to the caller to delete the database when it's no longer needed. */ - virtual Db* createInMemDb() = 0; + virtual Db* createInMemDb(bool pureInit = false) = 0; /** * @brief Tells if given database is temporary. diff --git a/SQLiteStudio3/coreSQLiteStudio/services/functionmanager.h b/SQLiteStudio3/coreSQLiteStudio/services/functionmanager.h index 2581b4f..5fb4908 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/functionmanager.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/functionmanager.h @@ -3,6 +3,7 @@ #include "coreSQLiteStudio_global.h" #include "common/global.h" +#include <QVariant> #include <QList> #include <QSharedPointer> #include <QObject> diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/collationmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/collationmanagerimpl.cpp index 5876021..7d24e47 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/collationmanagerimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/collationmanagerimpl.cpp @@ -27,7 +27,7 @@ QList<CollationManager::CollationPtr> CollationManagerImpl::getAllCollations() c QList<CollationManager::CollationPtr> CollationManagerImpl::getCollationsForDatabase(const QString& dbName) const { QList<CollationPtr> results; - foreach (const CollationPtr& coll, collations) + for (const CollationPtr& coll : collations) { if (coll->allDatabases || coll->databases.contains(dbName, Qt::CaseInsensitive)) results << coll; @@ -120,6 +120,6 @@ void CollationManagerImpl::loadFromConfig() void CollationManagerImpl::refreshCollationsByKey() { collationsByKey.clear(); - foreach (CollationPtr collation, collations) + for (CollationPtr collation : collations) collationsByKey[collation->name] = collation; } diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp index cf8b115..860e828 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp @@ -4,6 +4,7 @@ #include "services/notifymanager.h" #include "sqlitestudio.h" #include "db/dbsqlite3.h" +#include "common/utils.h" #include <QtGlobal> #include <QDebug> #include <QList> @@ -94,11 +95,7 @@ bool ConfigImpl::isMassSaving() const void ConfigImpl::set(const QString &group, const QString &key, const QVariant &value) { - QByteArray bytes; - QDataStream stream(&bytes, QIODevice::WriteOnly); - stream << value; - - db->exec("INSERT OR REPLACE INTO settings VALUES (?, ?, ?)", {group, key, bytes}); + db->exec("INSERT OR REPLACE INTO settings VALUES (?, ?, ?)", {group, key, serializeToBytes(value)}); } QVariant ConfigImpl::get(const QString &group, const QString &key) @@ -107,6 +104,15 @@ QVariant ConfigImpl::get(const QString &group, const QString &key) return deserializeValue(results->getSingleCell()); } +QVariant ConfigImpl::get(const QString &group, const QString &key, const QVariant &defaultValue) +{ + QVariant value = get(group, key); + if (!value.isValid() || value.isNull()) + return defaultValue; + + return value; +} + QHash<QString,QVariant> ConfigImpl::getAll() { SqlQueryPtr results = db->exec("SELECT [group], [key], value FROM settings"); @@ -225,7 +231,7 @@ void ConfigImpl::storeGroups(const QList<DbGroupPtr>& groups) db->begin(); db->exec("DELETE FROM groups"); - foreach (const DbGroupPtr& group, groups) + for (const DbGroupPtr& group : groups) storeGroup(group); db->commit(); @@ -241,7 +247,7 @@ void ConfigImpl::storeGroup(const ConfigImpl::DbGroupPtr &group, qint64 parentId {group->name, group->order, parent, group->open, group->referencedDbName}); qint64 newParentId = results->getRegularInsertRowId(); - foreach (const DbGroupPtr& childGroup, group->childs) + for (const DbGroupPtr& childGroup : group->childs) storeGroup(childGroup, newParentId); } @@ -304,6 +310,11 @@ void ConfigImpl::clearSqlHistory() QtConcurrent::run(this, &ConfigImpl::asyncClearSqlHistory); } +void ConfigImpl::deleteSqlHistory(const QList<qint64>& ids) +{ + QtConcurrent::run(this, &ConfigImpl::asyncDeleteSqlHistory, ids); +} + QAbstractItemModel* ConfigImpl::getSqlHistoryModel() { if (!sqlHistoryModel) @@ -338,6 +349,122 @@ QStringList ConfigImpl::getCliHistory() const return results->columnAsList<QString>("text"); } +void ConfigImpl::addBindParamHistory(const QVector<QPair<QString, QVariant> >& params) +{ + QtConcurrent::run(this, &ConfigImpl::asyncAddBindParamHistory, params); +} + +void ConfigImpl::applyBindParamHistoryLimit() +{ + QtConcurrent::run(this, &ConfigImpl::asyncApplyBindParamHistoryLimit); +} + +QVector<QPair<QString, QVariant>> ConfigImpl::getBindParamHistory(const QStringList& paramNames) const +{ + static_qstring(directQuery, "SELECT id FROM bind_params WHERE pattern = ? ORDER BY id DESC"); + static_qstring(paramsByIdQuery, "SELECT name, value FROM bind_param_values WHERE bind_params_id = ? ORDER BY position"); + static_qstring(singleParamQuery, "SELECT value FROM bind_param_values WHERE %1 = ? ORDER BY id DESC LIMIT 1;"); + static_qstring(singleParamName, "name"); + static_qstring(singleParamPosition, "position"); + + QVector<QPair<QString, QVariant>> bindParams; + bindParams.reserve(paramNames.size()); + + SqlQueryPtr results = db->exec(directQuery, {paramNames.join(",")}); + if (results->isError()) + { + qWarning() << "Error while getting BindParams (1):" << db->getErrorText(); + return bindParams; + } + + // Got an exact match? Extract values and return. + QVariant exactMatch = results->getSingleCell(); + if (!exactMatch.isNull()) + { + results = db->exec(paramsByIdQuery, {exactMatch.toLongLong()}); + if (results->isError()) + { + qWarning() << "Error while getting BindParams (2):" << db->getErrorText(); + } + else + { + for (const SqlResultsRowPtr& row : results->getAll()) + bindParams << QPair<QString, QVariant>(row->value("name").toString(), row->value("value")); + } + return bindParams; + } + + // No exact match. Will look for values one by one using param name and position. + int position = 0; + for (const QString& bindParam : paramNames) + { + if (bindParam == "?") + results = db->exec(singleParamQuery.arg(singleParamPosition), {position}); + else + results = db->exec(singleParamQuery.arg(singleParamName), {bindParam}); + + bindParams << QPair<QString, QVariant>(bindParam, results->getSingleCell()); + position++; + } + return bindParams; +} + +void ConfigImpl::addPopulateHistory(const QString& database, const QString& table, int rows, const QHash<QString, QPair<QString, QVariant> >& columnsPluginsConfig) +{ + QtConcurrent::run(this, &ConfigImpl::asyncAddPopulateHistory, database, table, rows, columnsPluginsConfig); +} + +void ConfigImpl::applyPopulateHistoryLimit() +{ + QtConcurrent::run(this, &ConfigImpl::asyncApplyPopulateHistoryLimit); +} + +QHash<QString, QPair<QString, QVariant>> ConfigImpl::getPopulateHistory(const QString& database, const QString& table, int& rows) const +{ + static_qstring(initialQuery, "SELECT id, rows FROM populate_history WHERE [database] = ? AND [table] = ? ORDER BY id DESC LIMIT 1"); + static_qstring(columnsQuery, "SELECT column_name, plugin_name, plugin_config FROM populate_column_history WHERE populate_history_id = ?"); + + QHash<QString, QPair<QString, QVariant>> historyEntry; + SqlQueryPtr results = db->exec(initialQuery, {database, table}); + if (results->isError()) + { + qWarning() << "Error while getting Populating history entry (1):" << db->getErrorText(); + return historyEntry; + } + + if (!results->hasNext()) + return historyEntry; + + SqlResultsRowPtr row = results->next(); + qint64 historyEntryId = row->value("id").toLongLong(); + rows = row->value("rows").toInt(); + + results = db->exec(columnsQuery, {historyEntryId}); + QVariant value; + while (results->hasNext()) + { + row = results->next(); + value = deserializeValue(row->value("plugin_config")); + historyEntry[row->value("column_name").toString()] = QPair<QString, QVariant>(row->value("plugin_name").toString(), value); + } + + return historyEntry; +} + +QVariant ConfigImpl::getPopulateHistory(const QString& pluginName) const +{ + static_qstring(columnsQuery, "SELECT plugin_config FROM populate_column_history WHERE plugin_name = ? ORDER BY id DESC LiMIT 1"); + + SqlQueryPtr results = db->exec(columnsQuery, {pluginName}); + if (results->isError()) + { + qWarning() << "Error while getting Populating history entry (2):" << db->getErrorText(); + return QVariant(); + } + + return deserializeValue(results->getSingleCell()); +} + void ConfigImpl::addDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile) { QtConcurrent::run(this, &ConfigImpl::asyncAddDdlHistory, queries, dbName, dbFile); @@ -503,9 +630,9 @@ QString ConfigImpl::getPortableConfigPath() if (!file.isDir() || !file.isReadable() || !file.isWritable()) continue; - foreach (file, dir.entryInfoList()) + for (const QFileInfo& entryFile : dir.entryInfoList()) { - if (!file.isReadable() || !file.isWritable()) + if (!entryFile.isReadable() || !entryFile.isWritable()) continue; } @@ -522,8 +649,7 @@ void ConfigImpl::initTables() if (!tables.contains("version")) { - QString table; - foreach (table, tables) + for (const QString& table : tables) db->exec("DROP TABLE "+table); tables.clear(); @@ -554,6 +680,34 @@ void ConfigImpl::initTables() if (!tables.contains("reports_history")) db->exec("CREATE TABLE reports_history (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, feature_request BOOLEAN, title TEXT, url TEXT)"); + + if (!tables.contains("bind_params")) + { + db->exec("CREATE TABLE bind_params (id INTEGER PRIMARY KEY AUTOINCREMENT, pattern TEXT NOT NULL)"); + db->exec("CREATE INDEX bind_params_patt_idx ON bind_params (pattern);"); + } + + if (!tables.contains("bind_param_values")) + { + db->exec("CREATE TABLE bind_param_values (id INTEGER PRIMARY KEY AUTOINCREMENT, bind_params_id INTEGER REFERENCES bind_params (id) " + "ON DELETE CASCADE ON UPDATE CASCADE NOT NULL, position INTEGER NOT NULL, name TEXT NOT NULL, value)"); + db->exec("CREATE INDEX bind_param_values_fk_idx ON bind_param_values (bind_params_id);"); + } + + if (!tables.contains("populate_history")) + { + db->exec("CREATE TABLE populate_history (id INTEGER PRIMARY KEY AUTOINCREMENT, [database] TEXT NOT NULL, [table] TEXT NOT NULL, rows INTEGER NOT NULL)"); + } + + if (!tables.contains("populate_column_history")) + { + db->exec("CREATE TABLE populate_column_history (id INTEGER PRIMARY KEY AUTOINCREMENT, populate_history_id INTEGER REFERENCES populate_history (id) " + "ON DELETE CASCADE ON UPDATE CASCADE NOT NULL, column_name TEXT NOT NULL, plugin_name TEXT NOT NULL, plugin_config BLOB)"); + db->exec("CREATE INDEX populate_plugin_history_idx ON populate_column_history (plugin_name)"); + } + + if (!tables.contains("reports_history")) + db->exec("CREATE TABLE reports_history (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, feature_request BOOLEAN, title TEXT, url TEXT)"); } void ConfigImpl::initDbFile() @@ -646,19 +800,13 @@ bool ConfigImpl::tryInitDbFile(const QPair<QString, bool> &dbPath) return true; } -QVariant ConfigImpl::deserializeValue(const QVariant &value) +QVariant ConfigImpl::deserializeValue(const QVariant &value) const { if (!value.isValid()) return QVariant(); QByteArray bytes = value.toByteArray(); - if (bytes.isNull()) - return QVariant(); - - QVariant deserializedValue; - QDataStream stream(bytes); - stream >> deserializedValue; - return deserializedValue; + return deserializeFromBytes(bytes); } void ConfigImpl::asyncAddSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected) @@ -709,6 +857,23 @@ void ConfigImpl::asyncClearSqlHistory() emit sqlHistoryRefreshNeeded(); } +void ConfigImpl::asyncDeleteSqlHistory(const QList<qint64>& ids) +{ + if (!db->begin()) { + NOTIFY_MANAGER->warn(tr("Could not start database transaction for deleting SQL history, therefore it's not deleted.")); + return; + } + for (const qint64& id : ids) + db->exec("DELETE FROM sqleditor_history WHERE id = ?", id); + + if (!db->commit()) { + NOTIFY_MANAGER->warn(tr("Could not commit database transaction for deleting SQL history, therefore it's not deleted.")); + db->rollback(); + return; + } + emit sqlHistoryRefreshNeeded(); +} + void ConfigImpl::asyncAddCliHistory(const QString& text) { static_qstring(insertQuery, "INSERT INTO cli_history (text) VALUES (?)"); @@ -722,7 +887,7 @@ void ConfigImpl::asyncAddCliHistory(const QString& text) void ConfigImpl::asyncApplyCliHistoryLimit() { - static_qstring(limitQuery, "DELETE FROM cli_history WHERE id >= (SELECT id FROM cli_history ORDER BY id LIMIT 1 OFFSET %1)"); + static_qstring(limitQuery, "DELETE FROM cli_history WHERE id <= (SELECT id FROM cli_history ORDER BY id DESC LIMIT 1 OFFSET %1)"); SqlQueryPtr results = db->exec(limitQuery.arg(CFG_CORE.Console.HistorySize.get())); if (results->isError()) @@ -738,6 +903,105 @@ void ConfigImpl::asyncClearCliHistory() qWarning() << "Error while clearing CLI history:" << db->getErrorText(); } +void ConfigImpl::asyncAddBindParamHistory(const QVector<QPair<QString, QVariant> >& params) +{ + static_qstring(insertParamsQuery, "INSERT INTO bind_params (pattern) VALUES (?)"); + static_qstring(insertValuesQuery, "INSERT INTO bind_param_values (bind_params_id, position, name, value) VALUES (?, ?, ?, ?)"); + + if (!db->begin()) + { + qWarning() << "Failed to store BindParam cache, because could not begin SQL transaction. Details:" << db->getErrorText(); + return; + } + + QStringList paramNames; + for (const QPair<QString, QVariant>& paramPair : params) + paramNames << paramPair.first; + + SqlQueryPtr results = db->exec(insertParamsQuery, {paramNames.join(",")}); + RowId rowId = results->getInsertRowId(); + qint64 bindParamsId = rowId["ROWID"].toLongLong(); + + int position = 0; + for (const QPair<QString, QVariant>& paramPair : params) + { + results = db->exec(insertValuesQuery, {bindParamsId, position++, paramPair.first, paramPair.second}); + if (results->isError()) + { + qWarning() << "Failed to store BindParam cache, due to SQL error:" << db->getErrorText(); + db->rollback(); + return; + } + } + + if (!db->commit()) + { + qWarning() << "Failed to store BindParam cache, because could not commit SQL transaction. Details:" << db->getErrorText(); + db->rollback(); + } + + asyncApplyBindParamHistoryLimit(); +} + +void ConfigImpl::asyncApplyBindParamHistoryLimit() +{ + static_qstring(findBindParamIdQuery, "SELECT bind_params_id FROM bind_param_values ORDER BY id DESC LIMIT 1 OFFSET %1"); + static_qstring(limitBindParamsQuery, "DELETE FROM bind_params WHERE id <= ?"); // will cascade with FK to bind_param_values + + SqlQueryPtr results = db->exec(findBindParamIdQuery.arg(CFG_CORE.General.BindParamsCacheSize.get())); + if (results->isError()) + qWarning() << "Error while limiting BindParam history (step 1):" << db->getErrorText(); + + qint64 bindParamId = results->getSingleCell().toLongLong(); + results = db->exec(limitBindParamsQuery, {bindParamId}); + if (results->isError()) + qWarning() << "Error while limiting BindParam history (step 2):" << db->getErrorText(); +} + +void ConfigImpl::asyncAddPopulateHistory(const QString& database, const QString& table, int rows, const QHash<QString, QPair<QString, QVariant>>& columnsPluginsConfig) +{ + static_qstring(insertQuery, "INSERT INTO populate_history ([database], [table], rows) VALUES (?, ?, ?)"); + static_qstring(insertColumnQuery, "INSERT INTO populate_column_history (populate_history_id, column_name, plugin_name, plugin_config) VALUES (?, ?, ?, ?)"); + + if (!db->begin()) + { + qWarning() << "Failed to store Populating history entry, because could not begin SQL transaction. Details:" << db->getErrorText(); + return; + } + + SqlQueryPtr results = db->exec(insertQuery, {database, table, rows}); + RowId rowId = results->getInsertRowId(); + qint64 populateHistoryId = rowId["ROWID"].toLongLong(); + + for (QHash<QString, QPair<QString, QVariant>>::const_iterator colIt = columnsPluginsConfig.begin(); colIt != columnsPluginsConfig.end(); colIt++) + { + results = db->exec(insertColumnQuery, {populateHistoryId, colIt.key(), colIt.value().first, serializeToBytes(colIt.value().second)}); + if (results->isError()) + { + qWarning() << "Failed to store Populating history entry, due to SQL error:" << db->getErrorText(); + db->rollback(); + return; + } + } + + if (!db->commit()) + { + qWarning() << "Failed to store Populating history entry, because could not commit SQL transaction. Details:" << db->getErrorText(); + db->rollback(); + } + + asyncApplyPopulateHistoryLimit(); +} + +void ConfigImpl::asyncApplyPopulateHistoryLimit() +{ + static_qstring(limitQuery, "DELETE FROM populate_history WHERE id <= (SELECT id FROM populate_history ORDER BY id DESC LIMIT 1 OFFSET %1)"); + + SqlQueryPtr results = db->exec(limitQuery.arg(CFG_CORE.General.PopulateHistorySize.get())); + if (results->isError()) + qWarning() << "Error while limiting Populating history:" << db->getErrorText(); +} + void ConfigImpl::asyncAddDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile) { static_qstring(insert, "INSERT INTO ddl_history (dbname, file, timestamp, queries) VALUES (?, ?, ?, ?)"); @@ -799,7 +1063,12 @@ void ConfigImpl::mergeMasterConfig() if (masterConfigFile.isEmpty()) return; - qInfo() << "Updating settings from master configuration file: " << masterConfigFile; +#if QT_VERSION >= 0x050500 + qInfo() +#else + qDebug() +#endif + << "Updating settings from master configuration file: " << masterConfigFile; Db* masterDb = new DbSqlite3("SQLiteStudio master settings", masterConfigFile, {{DB_PURE_INIT, true}}); if (!masterDb->open()) diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h index 08bcec7..561aab4 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h @@ -29,6 +29,7 @@ class API_EXPORT ConfigImpl : public Config bool isMassSaving() const; void set(const QString& group, const QString& key, const QVariant& value); QVariant get(const QString& group, const QString& key); + QVariant get(const QString& group, const QString& key, const QVariant& defaultValue); QHash<QString,QVariant> getAll(); bool addDb(const QString& name, const QString& path, const QHash<QString, QVariant> &options); @@ -56,6 +57,7 @@ class API_EXPORT ConfigImpl : public Config qint64 addSqlHistory(const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected); void updateSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected); void clearSqlHistory(); + void deleteSqlHistory(const QList<qint64>& ids); QAbstractItemModel* getSqlHistoryModel(); void addCliHistory(const QString& text); @@ -63,6 +65,15 @@ class API_EXPORT ConfigImpl : public Config void clearCliHistory(); QStringList getCliHistory() const; + void addBindParamHistory(const QVector<QPair<QString, QVariant>>& params); + void applyBindParamHistoryLimit(); + QVector<QPair<QString, QVariant>> getBindParamHistory(const QStringList& paramNames) const; + + void addPopulateHistory(const QString& database, const QString& table, int rows, const QHash<QString, QPair<QString, QVariant>>& columnsPluginsConfig); + void applyPopulateHistoryLimit(); + QHash<QString, QPair<QString, QVariant>> getPopulateHistory(const QString& database, const QString& table, int& rows) const; + QVariant getPopulateHistory(const QString& pluginName) const; + void addDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile); QList<DdlHistoryEntryPtr> getDdlHistoryFor(const QString& dbName, const QString& dbFile, const QDate& date); DdlHistoryModel* getDdlHistoryModel(); @@ -94,16 +105,23 @@ class API_EXPORT ConfigImpl : public Config void initTables(); void initDbFile(); bool tryInitDbFile(const QPair<QString, bool>& dbPath); - QVariant deserializeValue(const QVariant& value); + QVariant deserializeValue(const QVariant& value) const; void asyncAddSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected); void asyncUpdateSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected); void asyncClearSqlHistory(); + void asyncDeleteSqlHistory(const QList<qint64> &ids); void asyncAddCliHistory(const QString& text); void asyncApplyCliHistoryLimit(); void asyncClearCliHistory(); + void asyncAddBindParamHistory(const QVector<QPair<QString, QVariant>>& params); + void asyncApplyBindParamHistoryLimit(); + + void asyncAddPopulateHistory(const QString& database, const QString& table, int rows, const QHash<QString, QPair<QString, QVariant>>& columnsPluginsConfig); + void asyncApplyPopulateHistoryLimit(); + void asyncAddDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile); void asyncClearDdlHistory(); diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.cpp index 74f482f..217c2b7 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.cpp @@ -23,7 +23,8 @@ DbManagerImpl::DbManagerImpl(QObject *parent) : DbManagerImpl::~DbManagerImpl() { - foreach (Db* db, dbList) +// qDebug() << "DbManagerImpl::~DbManagerImpl()"; + for (Db* db : dbList) { disconnect(db, SIGNAL(disconnected()), this, SLOT(dbDisconnectedSlot())); disconnect(db, SIGNAL(aboutToDisconnect(bool&)), this, SLOT(dbAboutToDisconnect(bool&))); @@ -261,12 +262,16 @@ Db* DbManagerImpl::getByPath(const QString &path) return pathToDb.value(pathDir.absolutePath()); } -Db* DbManagerImpl::createInMemDb() +Db* DbManagerImpl::createInMemDb(bool pureInit) { if (!inMemDbCreatorPlugin) return nullptr; - return inMemDbCreatorPlugin->getInstance("", ":memory:", {}); + QHash<QString, QVariant> opts; + if (pureInit) + opts[DB_PURE_INIT] = true; + + return inMemDbCreatorPlugin->getInstance("", ":memory:", opts); } bool DbManagerImpl::isTemporary(Db* db) @@ -341,7 +346,7 @@ void DbManagerImpl::loadInitialDbList() { QUrl url; InvalidDb* db = nullptr; - foreach (const Config::CfgDbPtr& cfgDb, CFG->dbList()) + for (const Config::CfgDbPtr& cfgDb : CFG->dbList()) { db = new InvalidDb(cfgDb->name, cfgDb->path, cfgDb->options); diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.h b/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.h index 2e3630a..5f99f86 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.h @@ -42,7 +42,7 @@ class API_EXPORT DbManagerImpl : public DbManager QStringList getDbNames(); Db* getByName(const QString& name, Qt::CaseSensitivity cs = Qt::CaseInsensitive); Db* getByPath(const QString& path); - Db* createInMemDb(); + Db* createInMemDb(bool pureInit = false); bool isTemporary(Db* db); QString quickAddDb(const QString &path, const QHash<QString, QVariant> &options); DbPlugin* getPluginForDbFile(const QString& filePath); diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp index 826b34b..2fcc689 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp @@ -40,7 +40,7 @@ QList<FunctionManager::ScriptFunction*> FunctionManagerImpl::getAllScriptFunctio QList<FunctionManager::ScriptFunction*> FunctionManagerImpl::getScriptFunctionsForDatabase(const QString& dbName) const { QList<ScriptFunction*> results; - foreach (ScriptFunction* func, functions) + for (ScriptFunction* func : functions) { if (func->allDatabases || func->databases.contains(dbName, Qt::CaseInsensitive)) results << func; @@ -280,10 +280,10 @@ void FunctionManagerImpl::initNativeFunctions() void FunctionManagerImpl::refreshFunctionsByKey() { functionsByKey.clear(); - foreach (ScriptFunction* func, functions) + for (ScriptFunction* func : functions) functionsByKey[Key(func)] = func; - foreach (NativeFunction* func, nativeFunctions) + for (NativeFunction* func : nativeFunctions) nativeFunctionsByKey[Key(func)] = func; } @@ -291,7 +291,7 @@ void FunctionManagerImpl::storeInConfig() { QVariantList list; QHash<QString,QVariant> fnHash; - foreach (ScriptFunction* func, functions) + for (ScriptFunction* func : functions) { fnHash["name"] = func->name; fnHash["lang"] = func->lang; diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/pluginmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/pluginmanagerimpl.cpp index 9fe21de..c67156c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/pluginmanagerimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/pluginmanagerimpl.cpp @@ -50,7 +50,7 @@ void PluginManagerImpl::deinit() emit aboutToQuit(); // Plugin containers and their plugins - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) { if (container->builtIn) { @@ -61,13 +61,13 @@ void PluginManagerImpl::deinit() unload(container->name); } - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) delete container; pluginContainer.clear(); // Types - foreach (PluginType* type, registeredPluginTypes) + for (PluginType* type : registeredPluginTypes) delete type; registeredPluginTypes.clear(); @@ -113,10 +113,10 @@ void PluginManagerImpl::scanPlugins() nameFilters << "*.so" << "*.dll" << "*.dylib"; QPluginLoader* loader = nullptr; - foreach (QString pluginDirPath, pluginDirs) + for (QString pluginDirPath : pluginDirs) { QDir pluginDir(pluginDirPath); - foreach (QString fileName, pluginDir.entryList(nameFilters, QDir::Files)) + for (QString fileName : pluginDir.entryList(nameFilters, QDir::Files)) { fileName = pluginDir.absoluteFilePath(fileName); loader = new QPluginLoader(fileName); @@ -158,7 +158,7 @@ bool PluginManagerImpl::initPlugin(QPluginLoader* loader, const QString& fileNam QJsonObject pluginMetaData = loader->metaData(); QString pluginTypeName = pluginMetaData.value("MetaData").toObject().value("type").toString(); PluginType* pluginType = nullptr; - foreach (PluginType* type, registeredPluginTypes) + for (PluginType* type : registeredPluginTypes) { if (type->getName() == pluginTypeName) { @@ -169,7 +169,7 @@ bool PluginManagerImpl::initPlugin(QPluginLoader* loader, const QString& fileNam if (!pluginType) { - qWarning() << "Could not load plugin" + fileName + "because its type was not recognized:" << pluginTypeName; + qWarning() << "Could not load plugin" << fileName << "because its type was not recognized:" << pluginTypeName; return false; } @@ -305,7 +305,7 @@ bool PluginManagerImpl::initPlugin(Plugin* plugin) { QString pluginName = plugin->getName(); PluginType* pluginType = nullptr; - foreach (PluginType* type, registeredPluginTypes) + for (PluginType* type : registeredPluginTypes) { if (type->test(plugin)) { @@ -316,7 +316,7 @@ bool PluginManagerImpl::initPlugin(Plugin* plugin) if (!pluginType) { - qWarning() << "Could not load built-in plugin" + pluginName + "because its type was not recognized."; + qWarning() << "Could not load built-in plugin" << pluginName << "because its type was not recognized."; return false; } @@ -363,7 +363,7 @@ QStringList PluginManagerImpl::getAllPluginNames(PluginType* type) const if (!pluginCategories.contains(type)) return names; - foreach (PluginContainer* container, pluginCategories[type]) + for (PluginContainer* container : pluginCategories[type]) names << container->name; return names; @@ -685,7 +685,7 @@ QList<Plugin*> PluginManagerImpl::getLoadedPlugins(PluginType* type) const if (!pluginCategories.contains(type)) return list; - foreach (PluginContainer* container, pluginCategories[type]) + for (PluginContainer* container : pluginCategories[type]) { if (container->loaded) list << container->plugin; @@ -769,7 +769,7 @@ bool PluginManagerImpl::arePluginsInitiallyLoaded() const QList<Plugin*> PluginManagerImpl::getLoadedPlugins() const { QList<Plugin*> plugins; - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) { if (container->loaded) plugins << container->plugin; @@ -780,7 +780,7 @@ QList<Plugin*> PluginManagerImpl::getLoadedPlugins() const QStringList PluginManagerImpl::getLoadedPluginNames() const { QStringList names; - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) { if (container->loaded) names << container->name; @@ -792,7 +792,7 @@ QList<PluginManager::PluginDetails> PluginManagerImpl::getAllPluginDetails() con { QList<PluginManager::PluginDetails> results; PluginManager::PluginDetails details; - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) { details.name = container->name; details.title = container->title; diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.cpp new file mode 100644 index 0000000..63dbaf6 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.cpp @@ -0,0 +1,70 @@ +#include "sqliteextensionmanagerimpl.h" +#include "services/notifymanager.h" +#include "services/dbmanager.h" + +SqliteExtensionManagerImpl::SqliteExtensionManagerImpl() +{ + init(); +} + +void SqliteExtensionManagerImpl::setExtensions(const QList<SqliteExtensionManager::ExtensionPtr>& newExtensions) +{ + extensions = newExtensions; + storeInConfig(); + emit extensionListChanged(); +} + +QList<SqliteExtensionManager::ExtensionPtr> SqliteExtensionManagerImpl::getAllExtensions() const +{ + return extensions; +} + +QList<SqliteExtensionManager::ExtensionPtr> SqliteExtensionManagerImpl::getExtensionForDatabase(const QString& dbName) const +{ + QList<ExtensionPtr> results; + for (const ExtensionPtr& ext : extensions) + { + if (ext->allDatabases || ext->databases.contains(dbName, Qt::CaseInsensitive)) + results << ext; + } + return results; +} + +void SqliteExtensionManagerImpl::init() +{ + loadFromConfig(); +} + +void SqliteExtensionManagerImpl::storeInConfig() +{ + QVariantList list; + QHash<QString,QVariant> extHash; + for (ExtensionPtr ext : extensions) + { + extHash["filePath"] = ext->filePath; + extHash["initFunc"] = ext->initFunc; + extHash["allDatabases"] = ext->allDatabases; + extHash["databases"] =common(DBLIST->getDbNames(), ext->databases); + list << extHash; + } + CFG_CORE.Internal.Extensions.set(list); +} + +void SqliteExtensionManagerImpl::loadFromConfig() +{ + extensions.clear(); + + QVariantList list = CFG_CORE.Internal.Extensions.get(); + QHash<QString,QVariant> extHash; + ExtensionPtr ext; + for (const QVariant& var : list) + { + extHash = var.toHash(); + ext = ExtensionPtr::create(); + ext->filePath = extHash["filePath"].toString(); + ext->initFunc = extHash["initFunc"].toString(); + ext->databases = extHash["databases"].toStringList(); + ext->allDatabases = extHash["allDatabases"].toBool(); + extensions << ext; + } +} diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.h b/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.h new file mode 100644 index 0000000..6fd7f46 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.h @@ -0,0 +1,23 @@ +#ifndef SQLITEEXTENSIONMANAGERIMPL_H +#define SQLITEEXTENSIONMANAGERIMPL_H + +#include "services/sqliteextensionmanager.h" + +class SqliteExtensionManagerImpl : public SqliteExtensionManager +{ + public: + SqliteExtensionManagerImpl(); + + void setExtensions(const QList<ExtensionPtr>& newExtensions); + QList<ExtensionPtr> getAllExtensions() const; + QList<ExtensionPtr> getExtensionForDatabase(const QString& dbName) const; + + private: + void init(); + void storeInConfig(); + void loadFromConfig(); + + QList<ExtensionPtr> extensions; +}; + +#endif // SQLITEEXTENSIONMANAGERIMPL_H diff --git a/SQLiteStudio3/coreSQLiteStudio/services/pluginmanager.h b/SQLiteStudio3/coreSQLiteStudio/services/pluginmanager.h index 4f822bc..f771c2c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/pluginmanager.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/pluginmanager.h @@ -380,7 +380,7 @@ class API_EXPORT PluginManager : public QObject template <class T> PluginType* getPluginType() const { - foreach (PluginType* type, getPluginTypes()) + for (PluginType* type : getPluginTypes()) { if (!dynamic_cast<DefinedPluginType<T>*>(type)) continue; @@ -406,7 +406,7 @@ class API_EXPORT PluginManager : public QObject if (!type) return typedPlugins; - foreach (Plugin* plugin, getLoadedPlugins(type)) + for (Plugin* plugin : getLoadedPlugins(type)) typedPlugins << dynamic_cast<T*>(plugin); return typedPlugins; @@ -427,7 +427,7 @@ class API_EXPORT PluginManager : public QObject if (!type) return names; - foreach (Plugin* plugin, getLoadedPlugins(type)) + for (Plugin* plugin : getLoadedPlugins(type)) names << plugin->getName(); return names; diff --git a/SQLiteStudio3/coreSQLiteStudio/services/sqliteextensionmanager.h b/SQLiteStudio3/coreSQLiteStudio/services/sqliteextensionmanager.h new file mode 100644 index 0000000..a135f3b --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/services/sqliteextensionmanager.h @@ -0,0 +1,34 @@ +#ifndef SQLITEEXTENSIONMANAGER_H +#define SQLITEEXTENSIONMANAGER_H + +#include "coreSQLiteStudio_global.h" +#include "sqlitestudio.h" +#include <QSharedPointer> +#include <QObject> + +class API_EXPORT SqliteExtensionManager : public QObject +{ + Q_OBJECT + + public: + struct API_EXPORT Extension + { + QString filePath; + QString initFunc; + QStringList databases; + bool allDatabases = true; + }; + + typedef QSharedPointer<Extension> ExtensionPtr; + + virtual void setExtensions(const QList<ExtensionPtr>& newExtensions) = 0; + virtual QList<ExtensionPtr> getAllExtensions() const = 0; + virtual QList<ExtensionPtr> getExtensionForDatabase(const QString& dbName) const = 0; + + signals: + void extensionListChanged(); +}; + +#define SQLITE_EXTENSIONS SQLITESTUDIO->getSqliteExtensionManager() + +#endif // SQLITEEXTENSIONMANAGER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.cpp b/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.cpp index 3663a1b..87df73b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.cpp @@ -1,461 +1,100 @@ #ifdef PORTABLE_CONFIG #include "updatemanager.h" -#include "services/pluginmanager.h" #include "services/notifymanager.h" #include "common/unused.h" -#include <QTemporaryDir> -#include <QNetworkAccessManager> -#include <QNetworkReply> -#include <QNetworkRequest> -#include <QUrl> -#include <QUrlQuery> #include <QDebug> +#include <QRegularExpression> #include <QCoreApplication> -#include <QJsonDocument> -#include <QJsonObject> -#include <QJsonArray> -#include <QJsonValue> -#include <QProcess> -#include <QThread> -#include <QtConcurrent/QtConcurrent> - -#ifdef Q_OS_WIN32 -#include "JlCompress.h" -#include <windows.h> -#include <shellapi.h> -#endif - -// Note on creating update packages: -// Packages for Linux and MacOSX should be an archive of _contents_ of SQLiteStudio directory, -// while for Windows it should be an archive of SQLiteStudio directory itself. - -QString UpdateManager::staticErrorMessage; -UpdateManager::RetryFunction UpdateManager::retryFunction = nullptr; +#include <QFileInfo> +#include <QtConcurrent/QtConcurrentRun> UpdateManager::UpdateManager(QObject *parent) : QObject(parent) { - networkManager = new QNetworkAccessManager(this); - connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*))); - connect(this, SIGNAL(updatingError(QString)), NOTIFY_MANAGER, SLOT(error(QString))); -} - -UpdateManager::~UpdateManager() -{ - cleanup(); -} + qRegisterMetaType<QList<UpdateManager::UpdateEntry>>(); -void UpdateManager::checkForUpdates(bool force) -{ - getUpdatesMetadata(updatesCheckReply, force); -} - -void UpdateManager::update() -{ - if (updatesGetUrlsReply || updatesInProgress) - return; - - getUpdatesMetadata(updatesGetUrlsReply); -} + connect(this, SIGNAL(updatingError(QString)), NOTIFY_MANAGER, SLOT(error(QString))); -QString UpdateManager::getPlatformForUpdate() const -{ -#if defined(Q_OS_LINUX) - if (QSysInfo::WordSize == 64) - return "linux64"; - else - return "linux32"; -#elif defined(Q_OS_WIN) - return "win32"; + QString updateBinary = +#if defined(Q_OS_WIN) + "UpdateSQLiteStudio.exe"; +#elif defined(Q_OS_LINUX) + "UpdateSQLiteStudio"; #elif defined(Q_OS_OSX) - return "macosx"; + "../../UpdateSQLiteStudio.app/Contents/MacOS/UpdateSQLiteStudio"; #else - return QString(); + ""; #endif -} - -QString UpdateManager::getCurrentVersions() const -{ - QJsonArray versionsArray; - - QJsonObject arrayEntry; - arrayEntry["component"] = "SQLiteStudio"; - arrayEntry["version"] = SQLITESTUDIO->getVersionString(); - versionsArray.append(arrayEntry); - - for (const PluginManager::PluginDetails& details : PLUGINS->getAllPluginDetails()) - { - if (details.builtIn) - continue; - arrayEntry["component"] = details.name; - arrayEntry["version"] = details.versionString; - versionsArray.append(arrayEntry); + if (!updateBinary.isEmpty()) { + updateBinaryAbsolutePath = QFileInfo(QCoreApplication::applicationDirPath() + "/" + updateBinary).absoluteFilePath(); } - - QJsonObject topObj; - topObj["versions"] = versionsArray; - - QJsonDocument doc(topObj); - return QString::fromLatin1(doc.toJson(QJsonDocument::Compact)); -} - -bool UpdateManager::isPlatformEligibleForUpdate() const -{ - return !getPlatformForUpdate().isNull() && getDistributionType() != DistributionType::OS_MANAGED; -} - -#if defined(Q_OS_WIN32) -bool UpdateManager::executePreFinalStepWin(const QString &tempDir, const QString &backupDir, const QString &appDir, bool reqAdmin) -{ - bool res; - if (reqAdmin) - res = executeFinalStepAsRootWin(tempDir, backupDir, appDir); - else - res = executeFinalStep(tempDir, backupDir, appDir); - - if (res) - { - QFileInfo path(qApp->applicationFilePath()); - QProcess::startDetached(appDir + "/" + path.fileName(), {WIN_POST_FINAL_UPDATE_OPTION_NAME, tempDir}); - } - return res; } -#endif -void UpdateManager::handleAvailableUpdatesReply(QNetworkReply* reply) -{ - if (reply->error() != QNetworkReply::NoError) - { - updatingFailed(tr("An error occurred while checking for updates: %1.").arg(reply->errorString())); - reply->deleteLater(); - return; - } - - QJsonParseError err; - QByteArray data = reply->readAll(); - reply->deleteLater(); - - QJsonDocument doc = QJsonDocument::fromJson(data, &err); - if (err.error != QJsonParseError::NoError) - { - qWarning() << "Invalid response from update service:" << err.errorString() << "\n" << "The data was:" << QString::fromLatin1(data); - notifyWarn(tr("Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.")); - return; - } - - QList<UpdateEntry> updates = readMetadata(doc); - if (updates.size() > 0) - emit updatesAvailable(updates); - else - emit noUpdatesAvailable(); -} - -void UpdateManager::getUpdatesMetadata(QNetworkReply*& replyStoragePointer, bool force) +UpdateManager::~UpdateManager() { -#ifdef PORTABLE_CONFIG - if ((!CFG_CORE.General.CheckUpdatesOnStartup.get() && !force) || !isPlatformEligibleForUpdate() || replyStoragePointer) - return; - - QUrlQuery query; - query.addQueryItem("platform", getPlatformForUpdate()); - query.addQueryItem("data", getCurrentVersions()); - QUrl url(QString::fromLatin1(updateServiceUrl) + "?" + query.query(QUrl::FullyEncoded)); - QNetworkRequest request(url); - replyStoragePointer = networkManager->get(request); -#endif } -void UpdateManager::handleUpdatesMetadata(QNetworkReply* reply) +void UpdateManager::checkForUpdates() { - if (reply->error() != QNetworkReply::NoError) - { - updatingFailed(tr("An error occurred while reading updates metadata: %1.").arg(reply->errorString())); - reply->deleteLater(); + if (!CFG_CORE.General.CheckUpdatesOnStartup.get()) return; - } - QJsonParseError err; - QByteArray data = reply->readAll(); - reply->deleteLater(); - - QJsonDocument doc = QJsonDocument::fromJson(data, &err); - if (err.error != QJsonParseError::NoError) - { - qWarning() << "Invalid response from update service for getting metadata:" << err.errorString() << "\n" << "The data was:" << QString::fromLatin1(data); - notifyWarn(tr("Could not download updates, because server responded with invalid message format. " - "You can try again later or download and install updates manually. See <a href=\"%1\">User Manual</a> for details.").arg(manualUpdatesHelpUrl)); + if (updateBinaryAbsolutePath.isEmpty()) { + qDebug() << "Updater binary not defined. Skipping updates checking."; return; } - tempDir = new QTemporaryDir(); - if (!tempDir->isValid()) { - notifyWarn(tr("Could not create temporary directory for downloading the update. Updating aborted.")); + if (!QFileInfo(updateBinaryAbsolutePath).exists()) { + QString errorDetails = tr("Updates installer executable is missing."); + emit updatingError(tr("Unable to check for updates (%1)").arg(errorDetails.trimmed())); + qWarning() << "Error while checking for updates: " << errorDetails; return; } - updatesInProgress = true; - updatesToDownload = readMetadata(doc); - totalDownloadsCount = updatesToDownload.size(); - totalPercent = 0; - - if (totalDownloadsCount == 0) - { - updatingFailed(tr("There was no updates to download. Updating aborted.")); - return; - } - - downloadUpdates(); + QtConcurrent::run(this, &UpdateManager::checkForUpdatesAsync); } -QList<UpdateManager::UpdateEntry> UpdateManager::readMetadata(const QJsonDocument& doc) +void UpdateManager::checkForUpdatesAsync() { - QList<UpdateEntry> updates; - UpdateEntry entry; - QJsonObject obj = doc.object(); - QJsonArray versionsArray = obj["newVersions"].toArray(); - QJsonObject entryObj; - for (const QJsonValue& value : versionsArray) - { - entryObj = value.toObject(); - entry.compontent = entryObj["component"].toString(); - entry.version = entryObj["version"].toString(); - entry.url = entryObj["url"].toString(); - updates << entry; - } - - return updates; -} - -void UpdateManager::downloadUpdates() -{ - if (updatesToDownload.size() == 0) + QProcess proc; + proc.start(updateBinaryAbsolutePath, {"--checkupdates"}); + if (!waitForProcess(proc)) { - QtConcurrent::run(this, &UpdateManager::installUpdates); - return; - } + QString errorDetails = QString::fromLocal8Bit(proc.readAllStandardError()); - UpdateEntry entry = updatesToDownload.takeFirst(); - currentJobTitle = tr("Downloading: %1").arg(entry.compontent); - emit updatingProgress(currentJobTitle, 0, totalPercent); + if (errorDetails.toLower().contains("no updates")) { + emit noUpdatesAvailable(); + return; + } - QStringList parts = entry.url.split("/"); - if (parts.size() < 1) - { - updatingFailed(tr("Could not determinate file name from update URL: %1. Updating aborted.").arg(entry.url)); - return; - } + if (errorDetails.isEmpty()) + errorDetails = tr("details are unknown"); - QString path = tempDir->path() + QLatin1Char('/') + parts.last(); - currentDownloadFile = new QFile(path); - if (!currentDownloadFile->open(QIODevice::WriteOnly)) - { - updatingFailed(tr("Failed to open file '%1' for writting: %2. Updating aborted.").arg(path, currentDownloadFile->errorString())); + emit updatingError(tr("Unable to check for updates (%1)").arg(errorDetails.trimmed())); + qWarning() << "Error while checking for updates: " << errorDetails; return; } - updatesToInstall[entry.compontent] = path; - - QNetworkRequest request(QUrl(entry.url)); - updatesGetReply = networkManager->get(request); - connect(updatesGetReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64))); - connect(updatesGetReply, SIGNAL(readyRead()), this, SLOT(readDownload())); + processCheckResults(proc.readAllStandardOutput()); } -void UpdateManager::updatingFailed(const QString& errMsg) -{ - cleanup(); - updatesInProgress = false; - emit updatingError(errMsg); -} - -void UpdateManager::installUpdates() +void UpdateManager::update() { - currentJobTitle = tr("Installing updates."); - totalPercent = (totalDownloadsCount - updatesToDownload.size()) * 100 / (totalDownloadsCount + 1); - emit updatingProgress(currentJobTitle, 0, totalPercent); - - requireAdmin = doRequireAdminPrivileges(); - - QTemporaryDir installTempDir; - QString appDirName = QDir(getAppDirPath()).dirName(); - QString targetDir = installTempDir.path() + QLatin1Char('/') + appDirName; - if (!copyRecursively(getAppDirPath(), targetDir)) + bool success = QProcess::startDetached(updateBinaryAbsolutePath, {"--updater"}); + if (!success) { - updatingFailed(tr("Could not copy current application directory into %1 directory.").arg(installTempDir.path())); + emit updatingError(tr("Unable to run updater application (%1). Please report this.").arg(updateBinaryAbsolutePath)); return; } - emit updatingProgress(currentJobTitle, 40, totalPercent); - - int i = 0; - int updatesCnt = updatesToInstall.size(); - for (const QString& component : updatesToInstall.keys()) - { - if (!installComponent(component, targetDir)) - { - cleanup(); - updatesInProgress = false; - return; - } - i++; - emit updatingProgress(currentJobTitle, (30 + (50 / updatesCnt * i)), totalPercent); - } - - if (!executeFinalStep(targetDir)) - { - cleanup(); - updatesInProgress = false; - return; - } - - currentJobTitle = QString(); - totalPercent = 100; - emit updatingProgress(currentJobTitle, 100, totalPercent); - cleanup(); - updatesInProgress = false; -#ifdef Q_OS_WIN32 - installTempDir.setAutoRemove(false); -#endif - - SQLITESTUDIO->setImmediateQuit(true); qApp->exit(0); } -bool UpdateManager::executeFinalStep(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ - bool isWin = false; -#ifdef Q_OS_WIN32 - isWin = true; - - // Windows needs to wait for previus process to exit - QThread::sleep(3); - - QDir dir(backupDir); - QString dirName = dir.dirName(); - dir.cdUp(); - if (!dir.mkdir(dirName)) - { - staticUpdatingFailed(tr("Could not create directory %1.").arg(backupDir)); - return false; - } -#endif - while (!moveDir(appDir, backupDir, isWin)) - { - if (!retryFunction) - { - staticUpdatingFailed(tr("Could not rename directory %1 to %2.\nDetails: %3").arg(appDir, backupDir, staticErrorMessage)); - return false; - } - - if (!retryFunction(tr("Cannot not rename directory %1 to %2.\nDetails: %3").arg(appDir, backupDir, staticErrorMessage))) - return false; - } - - if (!moveDir(tempDir, appDir, isWin)) - { - if (!moveDir(backupDir, appDir, isWin)) - { - staticUpdatingFailed(tr("Could not move directory %1 to %2 and also failed to restore original directory, " - "so the original SQLiteStudio directory is now located at: %3").arg(tempDir, appDir, backupDir)); - } - else - { - staticUpdatingFailed(tr("Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.").arg(tempDir, appDir)); - } - deleteDir(backupDir); - return false; - } - - deleteDir(backupDir); - return true; -} - -bool UpdateManager::handleUpdateOptions(const QStringList& argList, int& returnCode) -{ - if (argList.size() == 5 && argList[1] == UPDATE_OPTION_NAME) - { - bool result = UpdateManager::executeFinalStep(argList[2], argList[3], argList[4]); - if (result) - returnCode = 0; - else - returnCode = 1; - - return true; - } - -#ifdef Q_OS_WIN32 - if (argList.size() == 6 && argList[1] == WIN_PRE_FINAL_UPDATE_OPTION_NAME) - { - bool result = UpdateManager::executePreFinalStepWin(argList[2], argList[3], argList[4], (bool)argList[5].toInt()); - if (result) - returnCode = 0; - else - returnCode = -1; - - return true; - } - - if (argList.size() == 3 && argList[1] == WIN_POST_FINAL_UPDATE_OPTION_NAME) - { - QThread::sleep(1); // to make sure that the previous process has quit - returnCode = 0; - UpdateManager::executePostFinalStepWin(argList[2]); - return true; - } -#endif - - return false; -} - -QString UpdateManager::getStaticErrorMessage() -{ - return staticErrorMessage; -} - -bool UpdateManager::executeFinalStep(const QString& tempDir) -{ - QString appDir = getAppDirPath(); - - // Find inexisting dir name next to app dir - QDir backupDir(getBackupDir(appDir)); - -#if defined(Q_OS_WIN32) - return runAnotherInstanceForUpdate(tempDir, backupDir.absolutePath(), qApp->applicationDirPath(), requireAdmin); -#else - bool res; - if (requireAdmin) - res = executeFinalStepAsRoot(tempDir, backupDir.absolutePath(), appDir); - else - res = executeFinalStep(tempDir, backupDir.absolutePath(), appDir); - - if (res) - QProcess::startDetached(qApp->applicationFilePath(), QStringList()); - - return res; -#endif -} - -bool UpdateManager::installComponent(const QString& component, const QString& tempDir) -{ - if (!unpackToDir(updatesToInstall[component], tempDir)) - { - updatingFailed(tr("Could not unpack component %1 into %2 directory.").arg(component, tempDir)); - return false; - } - - // In future here we might also delete/change some files, according to some update script. - return true; -} - -void UpdateManager::cleanup() +bool UpdateManager::isPlatformEligibleForUpdate() const { - safe_delete(currentDownloadFile); - safe_delete(tempDir); - updatesToDownload.clear(); - updatesToInstall.clear(); - requireAdmin = false; + return getDistributionType() != DistributionType::OS_MANAGED; } bool UpdateManager::waitForProcess(QProcess& proc) @@ -481,582 +120,33 @@ bool UpdateManager::waitForProcess(QProcess& proc) return true; } -QString UpdateManager::readError(QProcess& proc, bool reverseOrder) -{ - QString err = QString::fromLocal8Bit(reverseOrder ? proc.readAllStandardOutput() : proc.readAllStandardError()); - if (err.isEmpty()) - err = QString::fromLocal8Bit(reverseOrder ? proc.readAllStandardError() : proc.readAllStandardOutput()); - - QString errStr = proc.errorString(); - if (!errStr.isEmpty()) - err += "\n" + errStr; - - return err; -} - -void UpdateManager::staticUpdatingFailed(const QString& errMsg) +void UpdateManager::processCheckResults(const QByteArray &results) { -#if defined(Q_OS_WIN32) - staticErrorMessage = errMsg; -#else - UPDATES->handleStaticFail(errMsg); -#endif - qCritical() << errMsg; -} - -bool UpdateManager::executeFinalStepAsRoot(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ -#if defined(Q_OS_LINUX) - return executeFinalStepAsRootLinux(tempDir, backupDir, appDir); -#elif defined(Q_OS_WIN32) - return executeFinalStepAsRootWin(tempDir, backupDir, appDir); -#elif defined(Q_OS_MACX) - return executeFinalStepAsRootMac(tempDir, backupDir, appDir); -#else - qCritical() << "Unknown update platform in UpdateManager::executeFinalStepAsRoot() for package" << packagePath; - return false; -#endif -} - -#if defined(Q_OS_LINUX) -bool UpdateManager::executeFinalStepAsRootLinux(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ - QStringList args = {qApp->applicationFilePath(), UPDATE_OPTION_NAME, tempDir, backupDir, appDir}; - - QProcess proc; - LinuxPermElevator elevator = findPermElevatorForLinux(); - switch (elevator) - { - case LinuxPermElevator::KDESU: - proc.setProgram("kdesu"); - args.prepend("-t"); - proc.setArguments(args); - break; - case LinuxPermElevator::GKSU: - proc.setProgram("gksu"); // TODO test gksu updates - proc.setArguments(args); - break; - case LinuxPermElevator::PKEXEC: - { - // We call CLI for doing final step, because pkexec runs cmd completly in root env, so there's no X server. - args[0] += "cli"; - - QStringList newArgs; - for (const QString& arg : args) - newArgs << wrapCmdLineArgument(arg); - - QString cmd = "cd " + wrapCmdLineArgument(qApp->applicationDirPath()) +"; " + newArgs.join(" "); - - proc.setProgram("pkexec"); - proc.setArguments({"sh", "-c", cmd}); - } - break; - case LinuxPermElevator::NONE: - updatingFailed(tr("Could not find permissions elevator application to run update as a root. Looked for: %1").arg("kdesu, gksu, pkexec")); - return false; - } - - proc.start(); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Could not execute final updating steps as root: %1").arg(readError(proc, (elevator == LinuxPermElevator::KDESU)))); - return false; - } - - return true; -} -#endif - -#ifdef Q_OS_MACX -bool UpdateManager::executeFinalStepAsRootMac(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ - // Prepare script for updater - // osascript -e "do shell script \"stufftorunasroot\" with administrator privileges" - QStringList args = {wrapCmdLineArgument(qApp->applicationFilePath() + "cli"), - UPDATE_OPTION_NAME, - wrapCmdLineArgument(tempDir), - wrapCmdLineArgument(backupDir), - wrapCmdLineArgument(appDir)}; - QProcess proc; - - QString innerCmd = wrapCmdLineArgument(args.join(" ")); - - static_qstring(scriptTpl, "do shell script %1 with administrator privileges"); - QString scriptCmd = scriptTpl.arg(innerCmd); - - // Prepare updater temporary directory - QTemporaryDir updaterDir; - if (!updaterDir.isValid()) - { - updatingFailed(tr("Could not execute final updating steps as admin: %1").arg(tr("Cannot create temporary directory for updater."))); - return false; - } - - // Create updater script - QString scriptPath = updaterDir.path() + "/UpdateSQLiteStudio.scpt"; - QFile updaterScript(scriptPath); - if (!updaterScript.open(QIODevice::WriteOnly)) - { - updatingFailed(tr("Could not execute final updating steps as admin: %1").arg(tr("Cannot create updater script file."))); - return false; - } - updaterScript.write(scriptCmd.toLocal8Bit()); - updaterScript.close(); - - // Compile script to updater application - QString updaterApp = updaterDir.path() + "/UpdateSQLiteStudio.app"; - proc.setProgram("osacompile"); - proc.setArguments({"-o", updaterApp, scriptPath}); - proc.start(); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Could not execute final updating steps as admin: %1").arg(readError(proc))); - return false; - } - - // Execute updater - proc.setProgram(updaterApp + "/Contents/MacOS/applet"); - proc.setArguments({}); - proc.start(); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Could not execute final updating steps as admin: %1").arg(readError(proc))); - return false; - } - - // Validating update - // The updater script will not return error if the user canceled the password prompt. - // We need to check if the update was actually made and return true only then. - if (QDir(tempDir).exists()) - { - // Temp dir still exists, so it was not moved by root process - updatingFailed(tr("Updating canceled.")); - return false; - } - - return true; -} -#endif - -#ifdef Q_OS_WIN32 -bool UpdateManager::executeFinalStepAsRootWin(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ - QString updateBin = qApp->applicationDirPath() + "/" + WIN_UPDATER_BINARY; - - QString installFilePath = tempDir + "/" + WIN_INSTALL_FILE; - QFile installFile(installFilePath); - installFile.open(QIODevice::WriteOnly); - QString nl("\n"); - installFile.write(UPDATE_OPTION_NAME); - installFile.write(nl.toLocal8Bit()); - installFile.write(backupDir.toLocal8Bit()); - installFile.write(nl.toLocal8Bit()); - installFile.write(appDir.toLocal8Bit()); - installFile.write(nl.toLocal8Bit()); - installFile.close(); - - int res = (int)::ShellExecuteA(0, "runas", updateBin.toUtf8().constData(), 0, 0, SW_SHOWNORMAL); - if (res < 32) - { - staticUpdatingFailed(tr("Could not execute final updating steps as administrator.")); - return false; - } - - // Since I suck as a developer and I cannot implement a simple synchronous app call under Windows - // (QProcess does it somehow, but I'm too lazy to look it up and probably the solution wouldn't be compatible - // with our "privileges elevation" trick above... so after all I think we're stuck with this solution for now), - // I do the workaround here, which makes this process wait for the other process to create the "done" - // file when it's done, so this process knows when the other has ended. This way we can proceed with this - // process and we will delete some directories later on, which were required by that other process. - if (!waitForFileToDisappear(installFilePath, 10)) - { - staticUpdatingFailed(tr("Could not execute final updating steps as administrator. Updater startup timed out.")); - return false; - } - - if (!waitForFileToAppear(appDir + QLatin1Char('/') + WIN_UPDATE_DONE_FILE, 30)) - { - staticUpdatingFailed(tr("Could not execute final updating steps as administrator. Updater operation timed out.")); - return false; - } - - return true; -} -#endif - -#if defined(Q_OS_WIN32) -bool UpdateManager::executePostFinalStepWin(const QString &tempDir) -{ - QString doneFile = qApp->applicationDirPath() + QLatin1Char('/') + WIN_UPDATE_DONE_FILE; - QFile::remove(doneFile); - - QDir dir(tempDir); - dir.cdUp(); - if (!deleteDir(dir.absolutePath())) - staticUpdatingFailed(tr("Could not clean up temporary directory %1. You can delete it manually at any time.").arg(dir.absolutePath())); - - QProcess::startDetached(qApp->applicationFilePath(), QStringList()); - return true; -} - -bool UpdateManager::waitForFileToDisappear(const QString &filePath, int seconds) -{ - QFile file(filePath); - while (file.exists() && seconds > 0) - { - QThread::sleep(1); - seconds--; - } - - return !file.exists(); -} - -bool UpdateManager::waitForFileToAppear(const QString &filePath, int seconds) -{ - QFile file(filePath); - while (!file.exists() && seconds > 0) - { - QThread::sleep(1); - seconds--; - } - - return file.exists(); -} - -bool UpdateManager::runAnotherInstanceForUpdate(const QString &tempDir, const QString &backupDir, const QString &appDir, bool reqAdmin) -{ - bool res = QProcess::startDetached(tempDir + "/SQLiteStudio.exe", {WIN_PRE_FINAL_UPDATE_OPTION_NAME, tempDir, backupDir, appDir, - QString::number((int)reqAdmin)}); - if (!res) - { - updatingFailed(tr("Could not run new version for continuing update.")); - return false; - } - - return true; -} -#endif - -UpdateManager::LinuxPermElevator UpdateManager::findPermElevatorForLinux() -{ -#if defined(Q_OS_LINUX) - QProcess proc; - proc.setProgram("which"); - - if (!SQLITESTUDIO->getEnv("DISPLAY").isEmpty()) - { - proc.setArguments({"kdesu"}); - proc.start(); - if (waitForProcess(proc)) - return LinuxPermElevator::KDESU; - - proc.setArguments({"gksu"}); - proc.start(); - if (waitForProcess(proc)) - return LinuxPermElevator::GKSU; - } - - proc.setArguments({"pkexec"}); - proc.start(); - if (waitForProcess(proc)) - return LinuxPermElevator::PKEXEC; -#endif - - return LinuxPermElevator::NONE; -} - -QString UpdateManager::wrapCmdLineArgument(const QString& arg) -{ - return "\"" + escapeCmdLineArgument(arg) + "\""; -} - -QString UpdateManager::escapeCmdLineArgument(const QString& arg) -{ - if (!arg.contains("\\") && !arg.contains("\"")) - return arg; - - QString str = arg; - return str.replace("\\", "\\\\").replace("\"", "\\\""); -} - -QString UpdateManager::getBackupDir(const QString &appDir) -{ - static_qstring(bakDirTpl, "%1.old%2"); - QDir backupDir(bakDirTpl.arg(appDir, "")); - int cnt = 1; - while (backupDir.exists()) - backupDir = QDir(bakDirTpl.arg(appDir, QString::number(cnt))); - - return backupDir.absolutePath(); -} - -bool UpdateManager::unpackToDir(const QString& packagePath, const QString& outputDir) -{ -#if defined(Q_OS_LINUX) - return unpackToDirLinux(packagePath, outputDir); -#elif defined(Q_OS_WIN32) - return unpackToDirWin(packagePath, outputDir); -#elif defined(Q_OS_MACX) - return unpackToDirMac(packagePath, outputDir); -#else - qCritical() << "Unknown update platform in UpdateManager::unpackToDir() for package" << packagePath; - return false; -#endif -} - -#if defined(Q_OS_LINUX) -bool UpdateManager::unpackToDirLinux(const QString &packagePath, const QString &outputDir) -{ - QProcess proc; - proc.setWorkingDirectory(outputDir); - proc.setStandardOutputFile(QProcess::nullDevice()); - proc.setStandardErrorFile(QProcess::nullDevice()); - - if (!packagePath.endsWith("tar.gz")) - { - updatingFailed(tr("Package not in tar.gz format, cannot install: %1").arg(packagePath)); - return false; - } - - proc.start("mv", {packagePath, outputDir}); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Package %1 cannot be installed, because cannot move it to directory: %2").arg(packagePath, outputDir)); - return false; - } - - QString fileName = packagePath.split("/").last(); - QString newPath = outputDir + "/" + fileName; - proc.start("tar", {"-xzf", newPath}); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Package %1 cannot be installed, because cannot unpack it: %2").arg(packagePath, readError(proc))); - return false; - } - - QProcess::execute("rm", {"-f", newPath}); - return true; -} -#endif - -#if defined(Q_OS_MACX) -bool UpdateManager::unpackToDirMac(const QString &packagePath, const QString &outputDir) -{ - QProcess proc; - proc.setWorkingDirectory(outputDir); - proc.setStandardOutputFile(QProcess::nullDevice()); - proc.setStandardErrorFile(QProcess::nullDevice()); - - if (!packagePath.endsWith("zip")) - { - updatingFailed(tr("Package not in zip format, cannot install: %1").arg(packagePath)); - return false; - } - - proc.start("unzip", {"-o", "-d", outputDir, packagePath}); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Package %1 cannot be installed, because cannot unzip it to directory %2: %3") - .arg(packagePath, outputDir, readError(proc))); - return false; - } - - return true; -} -#endif - -#if defined(Q_OS_WIN32) -bool UpdateManager::unpackToDirWin(const QString& packagePath, const QString& outputDir) -{ - if (JlCompress::extractDir(packagePath, outputDir + "/..").isEmpty()) - { - updatingFailed(tr("Package %1 cannot be installed, because cannot unzip it to directory: %2").arg(packagePath, outputDir)); - return false; - } - - return true; -} -#endif - -void UpdateManager::handleStaticFail(const QString& errMsg) -{ - emit updatingFailed(errMsg); -} - -QString UpdateManager::getAppDirPath() const -{ - static QString appDir; - if (appDir.isNull()) - { - appDir = qApp->applicationDirPath(); -#ifdef Q_OS_MACX - QDir tmpAppDir(appDir); - tmpAppDir.cdUp(); - tmpAppDir.cdUp(); - appDir = tmpAppDir.absolutePath(); -#endif - } - return appDir; -} - -bool UpdateManager::moveDir(const QString& src, const QString& dst, bool contentsOnly) -{ - // If we're doing a rename in the very same parent directory then we don't want - // the 'move between partitions' to be involved, cause any failure to rename - // is due to permissions or file lock. - QFileInfo srcFi(src); - QFileInfo dstFi(dst); - bool sameParentDir = (srcFi.dir() == dstFi.dir()); - - QDir dir; - if (contentsOnly) - { - QString localSrc; - QString localDst; - QDir srcDir(src); - for (const QFileInfo& entry : srcDir.entryInfoList(QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot|QDir::Hidden|QDir::System)) - { - localSrc = entry.absoluteFilePath(); - localDst = dst + "/" + entry.fileName(); - if (!dir.rename(localSrc, localDst) && (sameParentDir || !renameBetweenPartitions(localSrc, localDst))) - { - staticUpdatingFailed(tr("Could not rename directory %1 to %2.").arg(localSrc, localDst)); - return false; - } - } - } - else - { - if (!dir.rename(src, dst) && (sameParentDir || !renameBetweenPartitions(src, dst))) - { - staticUpdatingFailed(tr("Could not rename directory %1 to %2.").arg(src, dst)); - return false; - } - } - - return true; -} - -bool UpdateManager::deleteDir(const QString& path) -{ - QDir dir(path); - if (!dir.removeRecursively()) - { - staticUpdatingFailed(tr("Could not delete directory %1.").arg(path)); - return false; - } - - return true; -} - -bool UpdateManager::execCmd(const QString& cmd, const QStringList& args, QString* errorMsg) -{ - QProcess proc; - proc.start(cmd, args); - QString cmdString = QString("%1 \"%2\"").arg(cmd, args.join("\\\" \\\"")); - - if (!waitForProcess(proc)) - { - if (errorMsg) - *errorMsg = tr("Error executing update command: %1\nError message: %2").arg(cmdString).arg(readError(proc)); - - return false; - } - - return true; -} - -void UpdateManager::setRetryFunction(const RetryFunction &value) -{ - retryFunction = value; -} - -bool UpdateManager::doRequireAdminPrivileges() -{ - QString appDirPath = getAppDirPath(); - QDir appDir(appDirPath); - bool isWritable = isWritableRecursively(appDir.absolutePath()); - - appDir.cdUp(); - QFileInfo fi(appDir.absolutePath()); - isWritable &= fi.isWritable(); - - if (isWritable) - { - QDir backupDir(getBackupDir(appDirPath)); - QString backupDirName = backupDir.dirName(); - backupDir.cdUp(); - if (backupDir.mkdir(backupDirName)) - backupDir.rmdir(backupDirName); - else - isWritable = false; - } - - return !isWritable; -} - -void UpdateManager::finished(QNetworkReply* reply) -{ - if (reply == updatesCheckReply) - { - updatesCheckReply = nullptr; - handleAvailableUpdatesReply(reply); - return; - } - - if (reply == updatesGetUrlsReply) - { - updatesGetUrlsReply = nullptr; - handleUpdatesMetadata(reply); + if (results.trimmed().isEmpty()) { + emit noUpdatesAvailable(); return; } - if (reply == updatesGetReply) - { - handleDownloadReply(reply); - if (reply == updatesGetReply) // if no new download is requested - updatesGetReply = nullptr; + QRegularExpression re(R"(\<update\s+([^\>]+)\>)"); + QRegularExpression versionRe(R"(version\=\"([\d\.]+)\")"); + QRegularExpression nameRe(R"(name\=\"([^\"]+)\")"); - return; - } -} - -void UpdateManager::handleDownloadReply(QNetworkReply* reply) -{ - if (reply->error() != QNetworkReply::NoError) + QRegularExpressionMatchIterator reIter = re.globalMatch(results); + QString updateNode; + UpdateEntry theUpdate; + QList<UpdateEntry> updates; + while (reIter.hasNext()) { - updatingFailed(tr("An error occurred while downloading updates: %1. Updating aborted.").arg(reply->errorString())); - reply->deleteLater(); - return; + updateNode = reIter.next().captured(1); + theUpdate.version = versionRe.match(updateNode).captured(1); + theUpdate.compontent = nameRe.match(updateNode).captured(1); + updates << theUpdate; } - totalPercent = (totalDownloadsCount - updatesToDownload.size()) * 100 / (totalDownloadsCount + 1); - - readDownload(); - currentDownloadFile->close(); - - safe_delete(currentDownloadFile); - - reply->deleteLater(); - downloadUpdates(); -} - -void UpdateManager::downloadProgress(qint64 bytesReceived, qint64 totalBytes) -{ - int perc; - if (totalBytes < 0) - perc = -1; - else if (totalBytes == 0) - perc = 100; + if (updates.isEmpty()) + emit noUpdatesAvailable(); else - perc = bytesReceived * 100 / totalBytes; - - emit updatingProgress(currentJobTitle, perc, totalPercent); -} - -void UpdateManager::readDownload() -{ - currentDownloadFile->write(updatesGetReply->readAll()); + emit updatesAvailable(updates); } #endif // PORTABLE_CONFIG diff --git a/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.h b/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.h index bb33487..50f4b6b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.h @@ -18,122 +18,34 @@ class API_EXPORT UpdateManager : public QObject { Q_OBJECT public: - typedef std::function<bool(const QString& msg)> RetryFunction; - struct UpdateEntry { QString compontent; QString version; - QString url; }; explicit UpdateManager(QObject *parent = 0); ~UpdateManager(); - void checkForUpdates(bool force = false); + void checkForUpdates(); void update(); bool isPlatformEligibleForUpdate() const; - static bool executeFinalStep(const QString& tempDir, const QString& backupDir, const QString& appDir); - static bool handleUpdateOptions(const QStringList& argList, int& returnCode); - static QString getStaticErrorMessage(); - - static void setRetryFunction(const RetryFunction &value); - - static_char* UPDATE_OPTION_NAME = "--update-final-step"; - static_char* WIN_INSTALL_FILE = "install.dat"; - static_char* WIN_UPDATE_DONE_FILE = "UpdateFinished.lck"; private: - enum class LinuxPermElevator - { - KDESU, - GKSU, - PKEXEC, - NONE - }; + QString updateBinaryAbsolutePath; - QString getPlatformForUpdate() const; - QString getCurrentVersions() const; - void handleAvailableUpdatesReply(QNetworkReply* reply); - void handleDownloadReply(QNetworkReply* reply); - void getUpdatesMetadata(QNetworkReply*& replyStoragePointer, bool force = false); - void handleUpdatesMetadata(QNetworkReply* reply); - QList<UpdateEntry> readMetadata(const QJsonDocument& doc); - void downloadUpdates(); - void updatingFailed(const QString& errMsg); - void installUpdates(); - bool installComponent(const QString& component, const QString& tempDir); - bool executeFinalStep(const QString& tempDir); - bool executeFinalStepAsRoot(const QString& tempDir, const QString& backupDir, const QString& appDir); -#if defined(Q_OS_LINUX) - bool executeFinalStepAsRootLinux(const QString& tempDir, const QString& backupDir, const QString& appDir); - bool unpackToDirLinux(const QString& packagePath, const QString& outputDir); -#elif defined(Q_OS_MACX) - bool unpackToDirMac(const QString& packagePath, const QString& outputDir); - bool executeFinalStepAsRootMac(const QString& tempDir, const QString& backupDir, const QString& appDir); -#elif defined(Q_OS_WIN32) - bool runAnotherInstanceForUpdate(const QString& tempDir, const QString& backupDir, const QString& appDir, bool reqAdmin); - bool unpackToDirWin(const QString& packagePath, const QString& outputDir); -#endif - bool doRequireAdminPrivileges(); - bool unpackToDir(const QString& packagePath, const QString& outputDir); - void handleStaticFail(const QString& errMsg); - QString getAppDirPath() const; - void cleanup(); - - static bool moveDir(const QString& src, const QString& dst, bool contentsOnly = false); - static bool deleteDir(const QString& path); - static bool execCmd(const QString& cmd, const QStringList& args, QString* errorMsg = nullptr); - static bool waitForProcess(QProcess& proc); - static QString readError(QProcess& proc, bool reverseOrder = false); - static void staticUpdatingFailed(const QString& errMsg); - static LinuxPermElevator findPermElevatorForLinux(); - static QString wrapCmdLineArgument(const QString& arg); - static QString escapeCmdLineArgument(const QString& arg); - static QString getBackupDir(const QString& appDir); -#if defined(Q_OS_WIN32) - static bool executePreFinalStepWin(const QString& tempDir, const QString& backupDir, const QString& appDir, bool reqAdmin); - static bool executeFinalStepAsRootWin(const QString& tempDir, const QString& backupDir, const QString& appDir); - static bool executePostFinalStepWin(const QString& tempDir); - static bool waitForFileToDisappear(const QString& filePath, int seconds); - static bool waitForFileToAppear(const QString& filePath, int seconds); -#endif - - QNetworkAccessManager* networkManager = nullptr; - QNetworkReply* updatesCheckReply = nullptr; - QNetworkReply* updatesGetUrlsReply = nullptr; - QNetworkReply* updatesGetReply = nullptr; - bool updatesInProgress = false; - QList<UpdateEntry> updatesToDownload; - QHash<QString,QString> updatesToInstall; - QTemporaryDir* tempDir = nullptr; - QFile* currentDownloadFile = nullptr; - int totalPercent = 0; - int totalDownloadsCount = 0; - QString currentJobTitle; - bool requireAdmin = false; - static RetryFunction retryFunction; - - static QString staticErrorMessage; - static_char* WIN_PRE_FINAL_UPDATE_OPTION_NAME = "--update-pre-final-step"; - static_char* WIN_POST_FINAL_UPDATE_OPTION_NAME = "--update-post-final-step"; - static_char* WIN_UPDATER_BINARY = "UpdateSQLiteStudio.exe"; - static_char* updateServiceUrl = "http://sqlitestudio.pl/updates3.rvt"; - static_char* manualUpdatesHelpUrl = "http://wiki.sqlitestudio.pl/index.php/User_Manual#Manual"; - - private slots: - void finished(QNetworkReply* reply); - void downloadProgress(qint64 bytesReceived, qint64 totalBytes); - void readDownload(); + void checkForUpdatesAsync(); + bool waitForProcess(QProcess& proc); + void processCheckResults(const QByteArray& results); signals: void updatesAvailable(const QList<UpdateManager::UpdateEntry>& updates); void noUpdatesAvailable(); - void updatingProgress(const QString& jobTitle, int jobPercent, int totalPercent); - void updatingFinished(); void updatingError(const QString& errorMessage); }; +Q_DECLARE_METATYPE(QList<UpdateManager::UpdateEntry>) + #define UPDATES SQLITESTUDIO->getUpdateManager() #endif // PORTABLE_CONFIG diff --git a/SQLiteStudio3/coreSQLiteStudio/sqlhistorymodel.cpp b/SQLiteStudio3/coreSQLiteStudio/sqlhistorymodel.cpp index 201dc8b..26e2d41 100644 --- a/SQLiteStudio3/coreSQLiteStudio/sqlhistorymodel.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/sqlhistorymodel.cpp @@ -5,7 +5,7 @@ SqlHistoryModel::SqlHistoryModel(Db* db, QObject *parent) : QueryModel(db, parent) { - static_char* query = "SELECT dbname, datetime(date, 'unixepoch'), (time_spent / 1000.0)||'s', rows, sql " + static_char* query = "SELECT id, dbname, datetime(date, 'unixepoch', 'localtime'), (time_spent / 1000.0)||'s', rows, sql " "FROM sqleditor_history ORDER BY date DESC"; setQuery(query); @@ -16,6 +16,8 @@ QVariant SqlHistoryModel::data(const QModelIndex& index, int role) const if (role == Qt::TextAlignmentRole && (index.column() == 2 || index.column() == 3)) return (int)(Qt::AlignRight|Qt::AlignVCenter); + QVariant d = QueryModel::data(index, role); + return QueryModel::data(index, role); } @@ -27,14 +29,16 @@ QVariant SqlHistoryModel::headerData(int section, Qt::Orientation orientation, i switch (section) { case 0: - return tr("Database", "sql history header"); + return ""; case 1: - return tr("Execution date", "sql history header"); + return tr("Database", "sql history header"); case 2: - return tr("Time spent", "sql history header"); + return tr("Execution date", "sql history header"); case 3: - return tr("Rows affected", "sql history header"); + return tr("Time spent", "sql history header"); case 4: + return tr("Rows affected", "sql history header"); + case 5: return tr("SQL", "sql history header"); } diff --git a/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp b/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp index 1e7863b..136ba03 100644 --- a/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp @@ -22,6 +22,7 @@ #include "services/impl/functionmanagerimpl.h" #include "services/impl/collationmanagerimpl.h" #include "services/impl/pluginmanagerimpl.h" +#include "services/impl/sqliteextensionmanagerimpl.h" #include "services/updatemanager.h" #include "impl/dbattacherimpl.h" #include "services/exportmanager.h" @@ -30,8 +31,8 @@ #include "plugins/scriptingsql.h" #include "plugins/importplugin.h" #include "plugins/populateplugin.h" -#include "services/bugreporter.h" #include "services/extralicensemanager.h" +#include "services/sqliteextensionmanager.h" #include "translations.h" #include <QProcessEnvironment> #include <QThreadPool> @@ -39,7 +40,7 @@ DEFINE_SINGLETON(SQLiteStudio) -static const int sqlitestudioVersion = 30101; +static const int sqlitestudioVersion = 30201; SQLiteStudio::SQLiteStudio() { @@ -99,16 +100,6 @@ void SQLiteStudio::setUpdateManager(UpdateManager* value) } #endif -BugReporter* SQLiteStudio::getBugReporter() const -{ - return bugReporter; -} - -void SQLiteStudio::setBugReporter(BugReporter* value) -{ - bugReporter = value; -} - PopulateManager* SQLiteStudio::getPopulateManager() const { return populateManager; @@ -131,25 +122,37 @@ void SQLiteStudio::setCodeFormatter(CodeFormatter* codeFormatter) QString SQLiteStudio::getHomePage() const { - static const QString url = QStringLiteral("http://sqlitestudio.pl"); + static_qstring(url, "https://sqlitestudio.pl"); return url; } QString SQLiteStudio::getForumPage() const { - static const QString url = QStringLiteral("http://forum.sqlitestudio.pl"); + static_qstring(url, "https://forum.sqlitestudio.pl"); return url; } QString SQLiteStudio::getUserManualPage() const { - static const QString url = QStringLiteral("http://wiki.sqlitestudio.pl/index.php/User_Manual"); + static_qstring(url, "https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual"); return url; } QString SQLiteStudio::getSqliteDocsPage() const { - static const QString url = QStringLiteral("http://sqlite.org/lang.html"); + static_qstring(url, "http://sqlite.org/lang.html"); + return url; +} + +QString SQLiteStudio::getIssuesPage() const +{ + static_qstring(url, "https://github.com/pawelsalawa/sqlitestudio/issues"); + return url; +} + +QString SQLiteStudio::getNewIssuePage() const +{ + static_qstring(url, "https://github.com/pawelsalawa/sqlitestudio/issues/new"); return url; } @@ -198,6 +201,17 @@ void SQLiteStudio::setCollationManager(CollationManager* value) collationManager = value; } +SqliteExtensionManager* SQLiteStudio::getSqliteExtensionManager() const +{ + return extensionManager; +} + +void SQLiteStudio::setSqliteExtensionManager(SqliteExtensionManager* value) +{ + safe_delete(extensionManager); + extensionManager = value; +} + DbAttacherFactory* SQLiteStudio::getDbAttacherFactory() const { return dbAttacherFactory; @@ -305,6 +319,7 @@ void SQLiteStudio::init(const QStringList& cmdListArguments, bool guiAvailable) functionManager = new FunctionManagerImpl(); collationManager = new CollationManagerImpl(); + extensionManager = new SqliteExtensionManagerImpl(); cmdLineArgs = cmdListArguments; @@ -320,7 +335,6 @@ void SQLiteStudio::init(const QStringList& cmdListArguments, bool guiAvailable) exportManager = new ExportManager(); importManager = new ImportManager(); populateManager = new PopulateManager(); - bugReporter = new BugReporter(); #ifdef PORTABLE_CONFIG updateManager = new UpdateManager(); #endif @@ -331,7 +345,7 @@ void SQLiteStudio::init(const QStringList& cmdListArguments, bool guiAvailable) extraLicenseManager->addLicense("Qt, QHexEdit (LGPL v2.1)", ":/docs/licenses/lgpl.txt"); extraLicenseManager->addLicense("diff_match (Apache License v2.0)", ":/docs/licenses/diff_match.txt"); extraLicenseManager->addLicense("RSA library (GPL v3)", ":/docs/licenses/gpl.txt"); - + extraLicenseManager->addLicense("SingleApplication (The MIT License)", ":/docs/licenses/mit.txt"); } void SQLiteStudio::initPlugins() @@ -345,6 +359,7 @@ void SQLiteStudio::initPlugins() void SQLiteStudio::cleanUp() { + emit aboutToQuit(); disconnect(pluginManager, SIGNAL(aboutToUnload(Plugin*,PluginType*)), this, SLOT(pluginToBeUnloaded(Plugin*,PluginType*))); disconnect(pluginManager, SIGNAL(unloaded(QString,PluginType*)), this, SLOT(pluginUnloaded(QString,PluginType*))); if (!immediateQuit) @@ -356,7 +371,6 @@ void SQLiteStudio::cleanUp() #ifdef PORTABLE_CONFIG safe_delete(updateManager); #endif - safe_delete(bugReporter); safe_delete(populateManager); safe_delete(importManager); safe_delete(exportManager); diff --git a/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.h b/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.h index 0b58b17..5cd3118 100644 --- a/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.h +++ b/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.h @@ -24,11 +24,11 @@ class ExportManager; class ImportManager; class PopulateManager; class PluginLoadingHandler; -class BugReporter; #ifdef PORTABLE_CONFIG class UpdateManager; #endif class ExtraLicenseManager; +class SqliteExtensionManager; /** @file */ @@ -117,6 +117,9 @@ class API_EXPORT SQLiteStudio : public QObject CollationManager* getCollationManager() const; void setCollationManager(CollationManager* value); + SqliteExtensionManager* getSqliteExtensionManager() const; + void setSqliteExtensionManager(SqliteExtensionManager* value); + ExportManager* getExportManager() const; void setExportManager(ExportManager* value); @@ -132,13 +135,12 @@ class API_EXPORT SQLiteStudio : public QObject CodeFormatter* getCodeFormatter() const; void setCodeFormatter(CodeFormatter* codeFormatter); - BugReporter* getBugReporter() const; - void setBugReporter(BugReporter* value); - QString getHomePage() const; QString getForumPage() const; QString getUserManualPage() const; QString getSqliteDocsPage() const; + QString getIssuesPage() const; + QString getNewIssuePage() const; #ifdef PORTABLE_CONFIG UpdateManager* getUpdateManager() const; @@ -200,10 +202,10 @@ class API_EXPORT SQLiteStudio : public QObject PluginManager* pluginManager = nullptr; DbAttacherFactory* dbAttacherFactory = nullptr; CollationManager* collationManager = nullptr; + SqliteExtensionManager* extensionManager = nullptr; ExportManager* exportManager = nullptr; ImportManager* importManager = nullptr; PopulateManager* populateManager = nullptr; - BugReporter* bugReporter = nullptr; #ifdef PORTABLE_CONFIG UpdateManager* updateManager = nullptr; #endif @@ -238,6 +240,9 @@ class API_EXPORT SQLiteStudio : public QObject * Doesn't change list of available formatters, but reads new selected formatters from config. */ void updateCurrentCodeFormatter(); + + signals: + void aboutToQuit(); }; /** @@ -259,7 +264,7 @@ class API_EXPORT SQLiteStudio : public QObject void someFunction() { QList<Db*> dblist = SQLITESTUDIO->getDbManager()->getDbList(); - foreach (Db* db, dblist) + for (Db* db : dblist) { qOut << db->getName(); } diff --git a/SQLiteStudio3/coreSQLiteStudio/tablemodifier.cpp b/SQLiteStudio3/coreSQLiteStudio/tablemodifier.cpp index 9c14f63..3558ec1 100644 --- a/SQLiteStudio3/coreSQLiteStudio/tablemodifier.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/tablemodifier.cpp @@ -89,7 +89,7 @@ void TableModifier::copyDataTo(const QString& targetTable) SchemaResolver resolver(db); QStringList targetColumns = resolver.getTableColumns(targetTable); QStringList colsToCopy; - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) if (targetColumns.contains(column->name, Qt::CaseInsensitive)) colsToCopy << wrapObjIfNeeded(column->name, dialect); @@ -299,30 +299,79 @@ bool TableModifier::handleUpdateColumns(SqliteUpdate* update) { bool modified = false; QString lowerName; + QVariant colName; + QString newName; + QStringList newNames; QMutableListIterator<SqliteUpdate::ColumnAndValue> it(update->keyValueMap); while (it.hasNext()) { it.next(); - // If column was modified, assign new name - lowerName = it.value().first.toLower(); - if (tableColMap.contains(lowerName)) + colName = it.value().first; + if (colName.type() == QVariant::StringList) { - it.value().first = tableColMap[lowerName]; - modified = true; + // List of columns set to a single value + newNames = handleUpdateColumns(colName.toStringList(), modified); + if (!modified) + continue; + + if (newNames.isEmpty()) + { + it.remove(); + continue; + } + + // If any column was modified, assign new list + it.value().first = newNames; continue; } - // It wasn't modified, but it's not on existing columns list? Remove it. - if (indexOf(existingColumns, it.value().first, Qt::CaseInsensitive) == -1) + // Single column case + newName = handleUpdateColumn(colName.toString(), modified); + if (!modified) + continue; + + if (newName.isNull()) { it.remove(); - modified = true; + continue; } + + // If column was modified, assign new name + it.value().first = newName; } return modified; } +QStringList TableModifier::handleUpdateColumns(const QStringList& colNames, bool& modified) +{ + QStringList newNames; + for (const QString& colName : colNames) + newNames << handleUpdateColumn(colName, modified); + + return newNames; +} + +QString TableModifier::handleUpdateColumn(const QString& colName, bool& modified) +{ + // If column was modified, assign new name + QString lowerName = colName.toLower(); + if (tableColMap.contains(lowerName)) + { + modified = true; + return tableColMap[lowerName]; + } + + // It wasn't modified, but it's not on existing columns list? Remove it. + if (indexOf(existingColumns, colName, Qt::CaseInsensitive) == -1) + { + modified = true; + return QString(); + } + + return colName; +} + QStringList TableModifier::getModifiedViews() const { return modifiedViews; @@ -354,7 +403,7 @@ void TableModifier::copyDataTo(SqliteCreateTablePtr newCreateTable) QStringList srcCols; QStringList dstCols; - foreach (SqliteCreateTable::Column* column, newCreateTable->columns) + for (SqliteCreateTable::Column* column : newCreateTable->columns) { if (!existingColumns.contains(column->originalName)) continue; // not copying columns that didn't exist before @@ -370,7 +419,7 @@ void TableModifier::handleIndexes() { SchemaResolver resolver(db); QList<SqliteCreateIndexPtr> parsedIndexesForTable = resolver.getParsedIndexesForTable(originalTable); - foreach (SqliteCreateIndexPtr index, parsedIndexesForTable) + for (SqliteCreateIndexPtr index : parsedIndexesForTable) handleIndex(index); } @@ -396,14 +445,18 @@ void TableModifier::handleTriggers() { SchemaResolver resolver(db); QList<SqliteCreateTriggerPtr> parsedTriggersForTable = resolver.getParsedTriggersForTable(originalTable, true); - foreach (SqliteCreateTriggerPtr trig, parsedTriggersForTable) + for (SqliteCreateTriggerPtr trig : parsedTriggersForTable) handleTrigger(trig); } void TableModifier::handleTrigger(SqliteCreateTriggerPtr trigger) { - trigger->rebuildTokens(); - QString originalQueryString = trigger->detokenize(); + // Cloning trigger (to avoid overwritting tokensMap when rebuilding tokens) + // and determining query string before it's modified by this method. + SqliteCreateTrigger* triggerClone = dynamic_cast<SqliteCreateTrigger*>(trigger->clone()); + triggerClone->rebuildTokens(); + QString originalQueryString = triggerClone->detokenize(); + delete triggerClone; bool forThisTable = (originalTable.compare(trigger->table, Qt::CaseInsensitive) == 0); bool alreadyProcessedOnce = modifiedTriggers.contains(trigger->trigger, Qt::CaseInsensitive); @@ -465,7 +518,7 @@ void TableModifier::handleTriggerQueries(SqliteCreateTriggerPtr trigger) { SqliteQuery* newQuery = nullptr; QList<SqliteQuery*> newQueries; - foreach (SqliteQuery* query, trigger->queries) + for (SqliteQuery* query : trigger->queries) { // The handleTriggerQuery() may delete the input query object. Don't refer to it later. newQuery = handleTriggerQuery(query, trigger->trigger, trigger->table); @@ -481,7 +534,7 @@ void TableModifier::handleViews() { SchemaResolver resolver(db); QList<SqliteCreateViewPtr> parsedViewsForTable = resolver.getParsedViewsForTable(originalTable); - foreach (SqliteCreateViewPtr view, parsedViewsForTable) + for (SqliteCreateViewPtr view : parsedViewsForTable) handleView(view); } @@ -550,7 +603,7 @@ SqliteSelect* TableModifier::handleSelect(SqliteSelect* select, const QString& t resolvedTables = tablesAsNameHash(selectResolver.resolveTables(core)); tableTokens = core->getContextTableTokens(false); - foreach (TokenPtr token, tableTokens) + for (TokenPtr token : tableTokens) { if (token->value.compare(originalTable, Qt::CaseInsensitive) != 0) continue; @@ -623,7 +676,7 @@ bool TableModifier::isTableAliasUsedForColumn(const TokenPtr &token, const StrHa if (table.tableAlias.isNull()) return false; - if (table.tableAlias.compare(token->value), Qt::CaseInsensitive != 0) + if (table.tableAlias.compare(token->value, Qt::CaseInsensitive) != 0) return false; // If the table token is mentioned in FROM clause, it's not a subject for aliased usage, cuase it defines alias, not uses it. @@ -708,7 +761,7 @@ bool TableModifier::handleSubSelects(SqliteStatement* stmt, const QString& trigT bool embedSelectsOk = true; QList<SqliteSelect*> selects = stmt->getAllTypedStatements<SqliteSelect>(); SqliteExpr* expr = nullptr; - foreach (SqliteSelect* select, selects) + for (SqliteSelect* select : selects) { if (select->coreSelects.size() >= 1 && select->coreSelects.first()->valuesMode) { @@ -842,7 +895,7 @@ void TableModifier::simpleHandleIndexes() { SchemaResolver resolver(db); QList<SqliteCreateIndexPtr> parsedIndexesForTable = resolver.getParsedIndexesForTable(originalTable); - foreach (SqliteCreateIndexPtr index, parsedIndexesForTable) + for (SqliteCreateIndexPtr index : parsedIndexesForTable) sqls << index->detokenize(); } @@ -855,7 +908,7 @@ void TableModifier::simpleHandleTriggers(const QString& view) else parsedTriggers = resolver.getParsedTriggersForTable(originalTable); - foreach (SqliteCreateTriggerPtr trig, parsedTriggers) + for (SqliteCreateTriggerPtr trig : parsedTriggers) sqls << trig->detokenize(); } diff --git a/SQLiteStudio3/coreSQLiteStudio/tablemodifier.h b/SQLiteStudio3/coreSQLiteStudio/tablemodifier.h index cba27ed..7be5a2a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/tablemodifier.h +++ b/SQLiteStudio3/coreSQLiteStudio/tablemodifier.h @@ -82,6 +82,8 @@ class API_EXPORT TableModifier bool handleColumnNames(QStringList& columnsToUpdate); bool handleColumnTokens(TokenList& columnsToUpdate); bool handleUpdateColumns(SqliteUpdate* update); + QStringList handleUpdateColumns(const QStringList& colNames, bool& modified); + QString handleUpdateColumn(const QString& colName, bool& modified); template <class T> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.qm Binary files differindex 2c10fb5..29cc169 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.qm +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.qm diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.ts index 7467fa1..803f815 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.ts @@ -4,13 +4,13 @@ <context> <name>AbstractDb</name> <message> - <location filename="../db/abstractdb.cpp" line="306"/> - <location filename="../db/abstractdb.cpp" line="323"/> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> <source>Cannot execute query on closed database.</source> <translation>Die Abfrage kann nicht auf einer ungeöffneten Datenbank ausgeführt werden.</translation> </message> <message> - <location filename="../db/abstractdb.cpp" line="603"/> + <location filename="../db/abstractdb.cpp" line="643"/> <source>Error attaching database %1: %2</source> <translation>Fehler beim Anhängen der Datenbank %1: %2</translation> </message> @@ -18,9 +18,8 @@ <context> <name>BugReporter</name> <message> - <location filename="../services/bugreporter.cpp" line="46"/> <source>Invalid login or password</source> - <translation>Ungültiger Nutzername oder Passwort</translation> + <translation type="vanished">Ungültiger Nutzername oder Passwort</translation> </message> </context> <context> @@ -147,37 +146,50 @@ </message> </context> <context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>DbManagerImpl</name> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="63"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> <source>Could not add database %1: %2</source> <translation>Die Datenbank %1 kann nicht hinzugefügt werden: %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="138"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> <source>Database %1 could not be updated, because of an error: %2</source> <translation>Die Datenbank %1 kann nicht aktualisiert werden. Grund: %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="350"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="379"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> <source>Database file doesn't exist.</source> <translation>Die Datenbankdatei existiert nicht.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="352"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="381"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="604"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> <source>No supporting plugin loaded.</source> <translation>Es wurde kein passendes plugin geladen.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="522"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> <source>Database could not be initialized.</source> <translation>Die Datenbank kann nicht initialisiert werden.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="532"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> <source>No suitable database driver plugin found.</source> <translation>Es wurde kein passender Datenbanktreiber (plugin) gefunden.</translation> </message> @@ -245,17 +257,17 @@ Tabellen, Indizes, Trigger und Views die in Datenbank %3 kopiert wurden, werden <context> <name>DbVersionConverter</name> <message> - <location filename="../dbversionconverter.cpp" line="916"/> + <location filename="../dbversionconverter.cpp" line="932"/> <source>Target file exists, but could not be overwritten.</source> <translation>Die Zieldatei existiert zwar, konnte aber nicht überschrieben werden.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="935"/> + <location filename="../dbversionconverter.cpp" line="951"/> <source>Could not find proper database plugin to create target database.</source> <translation>Es konnte kein geeignetes Datenbankplugin gefunden werden, um die Zieldatenbank zu erzeugen.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="1169"/> + <location filename="../dbversionconverter.cpp" line="1185"/> <source>Error while converting database: %1</source> <translation>Fehler beim Konvertieren der Datenbank: %1</translation> </message> @@ -459,20 +471,20 @@ Tabellen, Indizes, Trigger und Views die in Datenbank %3 kopiert wurden, werden </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="180"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> <source>Error while importing data: %1</source> <translation>Fehler beim Import der Daten: %1</translation> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="184"/> <source>Interrupted.</source> <comment>import process status update</comment> <translation>Abgebrochen.</translation> </message> <message> - <location filename="../importworker.cpp" line="175"/> + <location filename="../importworker.cpp" line="172"/> <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> <translation>Datenzeile %1 konnte nicht importiert werden. Die Zeile wurde ignoriert. Problembeschreibung: %2</translation> </message> @@ -768,12 +780,12 @@ Tabellen, Indizes, Trigger und Views die in Datenbank %3 kopiert wurden, werden <translation>Es kann keine Transaktion zum Füllen der Tabelle gestartet werden. Problembeschreibung: %1</translation> </message> <message> - <location filename="../populateworker.cpp" line="63"/> + <location filename="../populateworker.cpp" line="70"/> <source>Error while populating table: %1</source> <translation>Fehler beim Füllen der Tabelle: %1</translation> </message> <message> - <location filename="../populateworker.cpp" line="74"/> + <location filename="../populateworker.cpp" line="81"/> <source>Could not commit transaction after table populating. Error details: %1</source> <translation>Die Transaktion zum Füllen der Tabelle kann nicht 'committet' werden. Problembeschreibung: %1</translation> </message> @@ -781,72 +793,78 @@ Tabellen, Indizes, Trigger und Views die in Datenbank %3 kopiert wurden, werden <context> <name>QObject</name> <message> - <location filename="../db/abstractdb2.h" line="199"/> - <location filename="../db/abstractdb3.h" line="356"/> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> <source>Could not open database: %1</source> <translation>Die Datenbank %1 kann nicht geöffnet werden.</translation> </message> <message> - <location filename="../db/abstractdb2.h" line="805"/> - <location filename="../db/abstractdb3.h" line="1100"/> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> <source>Result set expired or no row available.</source> <translation>Das Abfrageergebniss ist ungültig oder es ist keine Datenzeile verfügbar.</translation> </message> <message> - <location filename="../db/abstractdb3.h" line="376"/> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> <source>Could not close database: %1</source> <translation>Die Datenbank %1 kann nicht geschlossen werden.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="137"/> - <location filename="../dbversionconverter.cpp" line="142"/> - <location filename="../dbversionconverter.cpp" line="195"/> - <location filename="../dbversionconverter.cpp" line="240"/> - <location filename="../dbversionconverter.cpp" line="245"/> - <location filename="../dbversionconverter.cpp" line="253"/> - <location filename="../dbversionconverter.cpp" line="331"/> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> <source>SQLite %1 does not support '%2' statement.</source> <translation>SQLite %1 unterstützt keine '%2' Abfrage.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="201"/> + <location filename="../dbversionconverter.cpp" line="202"/> <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> <translation>SQLite %1 unterstützt keine '%2' Abfrage, aber die normale Tabelle kann stattdessen erzeugt werden, wenn Sie fortfahren.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="424"/> + <location filename="../dbversionconverter.cpp" line="429"/> <source>Could not parse statement: %1 Error details: %2</source> <translation>Die Abfrage kann nicht verarbeitet werden: %1 Problembeschreibung: %2</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="435"/> - <location filename="../dbversionconverter.cpp" line="461"/> - <location filename="../dbversionconverter.cpp" line="482"/> - <location filename="../dbversionconverter.cpp" line="515"/> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> <translation>SQLite %1 unterstützt keine '%2' Klausel. Die %3 Abfrage kann mit dieser Klausel nicht konvertiert werden.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="488"/> + <location filename="../dbversionconverter.cpp" line="497"/> <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> <translation>SQLite %1 unterstützt keine '%2' Klausel in der %3 Abfrage.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="756"/> + <location filename="../dbversionconverter.cpp" line="772"/> <source>SQLite %1 does not support current date or time clauses in expressions.</source> <translation>SQLite %1 unterstützt keine current date' oder 'time' Klauseln in Ausdrücken.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="759"/> + <location filename="../dbversionconverter.cpp" line="775"/> <source>SQLite %1 does not support row value clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="770"/> - <location filename="../dbversionconverter.cpp" line="773"/> - <location filename="../dbversionconverter.cpp" line="784"/> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> <source>SQLite %1 does not support '%2' clause in expressions.</source> <translation>SQLite %1 unterstützt keine '%2' Klausel Ausdrücken.</translation> </message> @@ -864,13 +882,13 @@ Problembeschreibung: %2</translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="1904"/> - <location filename="../parser/sqlite3_parse.cpp" line="2169"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> <source>Parser stack overflow</source> <translation>Stacküberlauf bei Verarbeitung</translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="4465"/> - <location filename="../parser/sqlite3_parse.cpp" line="5088"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> <source>Syntax error</source> <translation>Syntaxfehler</translation> </message> @@ -925,59 +943,59 @@ Problembeschreibung: %2</translation> <translation>Der Implementationscode darf nicht leer sein.</translation> </message> <message> - <location filename="../selectresolver.cpp" line="352"/> + <location filename="../selectresolver.cpp" line="359"/> <source>Could not resolve data source for column: %1</source> <translation>Die Datenquelle für Spalte %1 kann nicht aufgelöst werden.</translation> </message> <message> - <location filename="../selectresolver.cpp" line="424"/> + <location filename="../selectresolver.cpp" line="431"/> <source>Could not resolve table for column '%1'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/configimpl.cpp" line="614"/> + <location filename="../services/impl/configimpl.cpp" line="768"/> <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> <translatorcomment>Ich hoffe, dass ich "to initialize" hier richtig mit "erstellt" übersetzt habe.</translatorcomment> <translation>Die Konfigurationsdatei kann nicht erstellt werden. Alle Änderungen an der Konfiguration sowie die Abfragehistorie sind nach einem Programmneustart verloren. Es wurde versucht die Konfigurationsdatei in folgendem Verzeichnis zu erstellen: %1</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="291"/> + <location filename="../sqlitestudio.cpp" line="305"/> <source>General purpose</source> <comment>plugin category name</comment> <translation>Allgemeine Verwendung</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="292"/> + <location filename="../sqlitestudio.cpp" line="306"/> <source>Database support</source> <comment>plugin category name</comment> <translation>Datenbankunterstützung</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="293"/> + <location filename="../sqlitestudio.cpp" line="307"/> <source>Code formatter</source> <comment>plugin category name</comment> <translation>Codeformatierer</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="294"/> + <location filename="../sqlitestudio.cpp" line="308"/> <source>Scripting languages</source> <comment>plugin category name</comment> <translation>Skriptsprachen</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="295"/> + <location filename="../sqlitestudio.cpp" line="309"/> <source>Exporting</source> <comment>plugin category name</comment> <translation>Exportieren</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="296"/> + <location filename="../sqlitestudio.cpp" line="310"/> <source>Importing</source> <comment>plugin category name</comment> <translation>Importieren</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="297"/> + <location filename="../sqlitestudio.cpp" line="311"/> <source>Table populating</source> <comment>plugin category name</comment> <translation>Tabellen füllen</translation> @@ -988,34 +1006,34 @@ Problembeschreibung: %2</translation> <translation>Tabelle %1 referenziert Tabelle %2, jedoch wird die 'foreign key'-Definition für die neue Tabellendefinition nicht aktualisiert, da es Probleme bei der DDL-Analyse von Tabelle %3 gibt.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="389"/> + <location filename="../tablemodifier.cpp" line="438"/> <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> <translation>Alle Spalten, die von Index %1 indiziert wurden, sind verloren. Der Index wird nach der Tabellenmodifikation nicht neu erstellt.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="428"/> + <location filename="../tablemodifier.cpp" line="481"/> <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> <translation>Es ist ein Problem bei der korrekten Verarbeitung des Triggers %1 aufgetreten. Er wird möglicherweise nicht vollständig aktualisert werden und sollte geprüft werden.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="475"/> + <location filename="../tablemodifier.cpp" line="528"/> <source>Cannot not update trigger %1 according to table %2 modification.</source> <translation>Die Aktualisierung des Triggers %1, resultierend aus der Änderung der Tabelle %2, kann nicht ausgeführt werden.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="655"/> - <location filename="../tablemodifier.cpp" line="679"/> - <location filename="../tablemodifier.cpp" line="698"/> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> <translation>Es ist ein Problem beim Aktualisieren einer %1 Abfrage innerhalb eines %2 Triggers aufgetreten. Eine der %1 Unterabfragen, welche möglicherweise die Tabelle %3 referenziert, kann nicht geändert werden. Eine manuelle Anpassung des Triggers wird nötig sein.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="443"/> + <location filename="../tablemodifier.cpp" line="496"/> <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> <translation>Alle Spalten, die durch den Trigger %1 abgedeckt wurden, sind verloren. Der Trigger wird nach der Änderung nicht wiederhergestellt.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="493"/> + <location filename="../tablemodifier.cpp" line="546"/> <source>Cannot not update view %1 according to table %2 modifications. The view will remain as it is.</source> <translation>Die Aktualisierung des Views %1, resultierend aus der Änderung der Tabelle %2, kann nicht ausgeführt werden. Der View wird daher nicht geändert.</translation> @@ -1035,33 +1053,38 @@ The view will remain as it is.</source> <source>SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process.</source> <translation>SQLiteStudio konnte die vom View zurückgegebenen Spalten nicht auflösen, daher kann nicht ermittelt werden, welcher Trigger beim Wiederherstelllungsprozess einen Fehler verusracht haben könnte.</translation> </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>QueryExecutor</name> <message> - <location filename="../db/queryexecutor.cpp" line="142"/> + <location filename="../db/queryexecutor.cpp" line="186"/> <source>Execution interrupted.</source> <translation>Ausführung abgebrochen.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="183"/> + <location filename="../db/queryexecutor.cpp" line="227"/> <source>Database is not open.</source> <translation>Die Datenbank ist nicht geöffnet.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="191"/> + <location filename="../db/queryexecutor.cpp" line="235"/> <source>Only one query can be executed simultaneously.</source> <translation>Es kann nur eine Abfrage gleichzeitig ausgeführt werden.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="294"/> - <location filename="../db/queryexecutor.cpp" line="568"/> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> <translatorcomment>Hier muss ggf. noch das 'data paging' korrekt übersetzt werden.</translatorcomment> <translation>Beim Ausführen der count(*) Abfrage ist ein Fehler aufgetreten, daher wird das data paging abgeschaltet. Problemdetails der Datenbank: %1</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="479"/> + <location filename="../db/queryexecutor.cpp" line="529"/> <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> <translation>SQLiteStudio konnte keine Metadaten aus der Abfrage extrahieren. Die Ergebnismenge kann daher nicht editiert werden.</translation> </message> @@ -1082,31 +1105,31 @@ The view will remain as it is.</source> <context> <name>SqlHistoryModel</name> <message> - <location filename="../sqlhistorymodel.cpp" line="30"/> + <location filename="../sqlhistorymodel.cpp" line="34"/> <source>Database</source> <comment>sql history header</comment> <translation>Datenbank</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="32"/> + <location filename="../sqlhistorymodel.cpp" line="36"/> <source>Execution date</source> <comment>sql history header</comment> <translation>Ausführungsdatum</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="34"/> + <location filename="../sqlhistorymodel.cpp" line="38"/> <source>Time spent</source> <comment>sql history header</comment> <translation>Dauer</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="36"/> + <location filename="../sqlhistorymodel.cpp" line="40"/> <source>Rows affected</source> <comment>sql history header</comment> <translation>Anzahl Zeilen</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="38"/> + <location filename="../sqlhistorymodel.cpp" line="42"/> <source>SQL</source> <comment>sql history header</comment> <translation>SQL</translation> @@ -1115,204 +1138,183 @@ The view will remain as it is.</source> <context> <name>UpdateManager</name> <message> - <location filename="../services/updatemanager.cpp" line="131"/> <source>An error occurred while checking for updates: %1.</source> - <translation>Beim Prüfen auf Updates trat folgender Fehler auf: %1.</translation> + <translation type="vanished">Beim Prüfen auf Updates trat folgender Fehler auf: %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="144"/> <source>Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.</source> - <translation>Es konnte nicht auf neue Updates geprüft werden, da der Updateserver in einem ungültigen Nachrichtenformat antwortet. Diese Meldung kann gefahrlos ignoriert werden.</translation> + <translation type="vanished">Es konnte nicht auf neue Updates geprüft werden, da der Updateserver in einem ungültigen Nachrichtenformat antwortet. Diese Meldung kann gefahrlos ignoriert werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="175"/> <source>An error occurred while reading updates metadata: %1.</source> - <translation>Beim Lesen der Update-Metadaten ist ein Fehler aufgetreten: %1.</translation> + <translation type="vanished">Beim Lesen der Update-Metadaten ist ein Fehler aufgetreten: %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="188"/> <source>Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details.</source> - <translation>Das Update konnte nicht heruntergeladen werden, da der Updateserver in einem ungültigen Nachrichtenformat antwortet. Sie können es später noch einmal versuchen oder das Update und die Installation manuell ausführen. Weitere Infoamtionen hierzu finden Sie in der <a href="%1">Programmdokumentation</a>.</translation> + <translation type="vanished">Das Update konnte nicht heruntergeladen werden, da der Updateserver in einem ungültigen Nachrichtenformat antwortet. Sie können es später noch einmal versuchen oder das Update und die Installation manuell ausführen. Weitere Infoamtionen hierzu finden Sie in der <a href="%1">Programmdokumentation</a>.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="195"/> <source>Could not create temporary directory for downloading the update. Updating aborted.</source> - <translation>Das temporäre Verzeichnis zum Herunterladen des Updates konnte nicht erstellt werden. Der Updatevorgang wird abgebrochen.</translation> + <translation type="vanished">Das temporäre Verzeichnis zum Herunterladen des Updates konnte nicht erstellt werden. Der Updatevorgang wird abgebrochen.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="206"/> <source>There was no updates to download. Updating aborted.</source> - <translation>Keine neuen Updates vorhanden. Der Updatevorgang wird beendet.</translation> + <translation type="vanished">Keine neuen Updates vorhanden. Der Updatevorgang wird beendet.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="241"/> <source>Downloading: %1</source> - <translation>Herunterladen von: %1</translation> + <translation type="vanished">Herunterladen von: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="247"/> <source>Could not determinate file name from update URL: %1. Updating aborted.</source> - <translation>Der Dateiname der Update-URL %1 konnte nicht ermittelt werden. Der Updatevorgang wird abgebrochen.</translation> + <translation type="vanished">Der Dateiname der Update-URL %1 konnte nicht ermittelt werden. Der Updatevorgang wird abgebrochen.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="255"/> <source>Failed to open file '%1' for writting: %2. Updating aborted.</source> - <translation>Beim Schreiben in die Datei '%1' trat folgender Fehler auf: %2. Der Updatevorgang wird abgebrochen.</translation> + <translation type="vanished">Beim Schreiben in die Datei '%1' trat folgender Fehler auf: %2. Der Updatevorgang wird abgebrochen.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="276"/> <source>Installing updates.</source> - <translation>Update wird installiert.</translation> + <translation type="vanished">Update wird installiert.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="287"/> <source>Could not copy current application directory into %1 directory.</source> - <translation>Das aktuelle Programmverzeichnis konnte nicht in das Verzeichnis %1 kopiert werden.</translation> + <translation type="vanished">Das aktuelle Programmverzeichnis konnte nicht in das Verzeichnis %1 kopiert werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="340"/> <source>Could not create directory %1.</source> - <translation>Das Verzeichnis %1 konnte nicht erstellt werden.</translation> + <translation type="vanished">Das Verzeichnis %1 konnte nicht erstellt werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="348"/> <source>Could not rename directory %1 to %2. Details: %3</source> - <translation>Das Verzeichnis %1 konnte nicht in %2 umbenannt werden. + <translation type="vanished">Das Verzeichnis %1 konnte nicht in %2 umbenannt werden. Details: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="352"/> <source>Cannot not rename directory %1 to %2. Details: %3</source> - <translation>Das Verzeichnis %1 kann nicht in %2 umbenannt werden. + <translation type="vanished">Das Verzeichnis %1 kann nicht in %2 umbenannt werden. Details: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="360"/> <source>Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3</source> - <translation>Das Verzeichnis %1 konnte nicht nach %2 verschoben werden. Ebenso schlug das Wiederherstellen des originalen Verzeichnissses fehlt, daher befindet sich das SQLiteStudio Verzeichnis nun hier: %3</translation> + <translation type="vanished">Das Verzeichnis %1 konnte nicht nach %2 verschoben werden. Ebenso schlug das Wiederherstellen des originalen Verzeichnissses fehlt, daher befindet sich das SQLiteStudio Verzeichnis nun hier: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="365"/> <source>Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.</source> - <translation>Das Das Verzeichnis %1 konnte nicht nach %2 umbenannt werden.SQLiteStudio wird auf den Ursprungszustand zurückgesetzt.</translation> + <translation type="vanished">Das Das Verzeichnis %1 konnte nicht nach %2 umbenannt werden.SQLiteStudio wird auf den Ursprungszustand zurückgesetzt.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="444"/> <source>Could not unpack component %1 into %2 directory.</source> - <translation>Die Komponente %1 konnte nicht in das Verzeichnis %2 extrahiert werden.</translation> + <translation type="vanished">Die Komponente %1 konnte nicht in das Verzeichnis %2 extrahiert werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="555"/> <source>Could not find permissions elevator application to run update as a root. Looked for: %1</source> - <translation>Die Rechteerweiterung zum Ausführen des Updates als 'root' konnte nicht gefunden werden. Es wurde gesucht nach: %1</translation> + <translation type="vanished">Die Rechteerweiterung zum Ausführen des Updates als 'root' konnte nicht gefunden werden. Es wurde gesucht nach: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="562"/> <source>Could not execute final updating steps as root: %1</source> - <translation>Die abschließenden Aktualisierungsschritte konnten nicht als 'root' ausgeführt werden: %1</translation> + <translation type="vanished">Die abschließenden Aktualisierungsschritte konnten nicht als 'root' ausgeführt werden: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <location filename="../services/updatemanager.cpp" line="600"/> - <location filename="../services/updatemanager.cpp" line="613"/> - <location filename="../services/updatemanager.cpp" line="623"/> <source>Could not execute final updating steps as admin: %1</source> - <translation>Die abschließenden Aktualisierungsschritte konnten nicht als 'admin' ausgeführt werden: %1</translation> + <translation type="vanished">Die abschließenden Aktualisierungsschritte konnten nicht als 'admin' ausgeführt werden: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="591"/> <source>Cannot create temporary directory for updater.</source> - <translation>Das temporäre Verzeichnis für den Updater konnte nicht erstellt werden.</translation> + <translation type="vanished">Das temporäre Verzeichnis für den Updater konnte nicht erstellt werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="600"/> <source>Cannot create updater script file.</source> - <translation>Die Skriptdatei für den Updater konnte nicht erstellt werden.</translation> + <translation type="vanished">Die Skriptdatei für den Updater konnte nicht erstellt werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="633"/> <source>Updating canceled.</source> - <translation>Updatevorgang abgebrochen.</translation> + <translation type="vanished">Updatevorgang abgebrochen.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="661"/> <source>Could not execute final updating steps as administrator.</source> - <translation>Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden.</translation> + <translation type="vanished">Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="673"/> <source>Could not execute final updating steps as administrator. Updater startup timed out.</source> - <translation>Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. Die Updatevorbereitungen liefen auf Zeitüberschreitung.</translation> + <translation type="vanished">Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. Die Updatevorbereitungen liefen auf Zeitüberschreitung.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="679"/> <source>Could not execute final updating steps as administrator. Updater operation timed out.</source> - <translation>Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. Der Updatevorgang lief auf Zeitüberschreitung.</translation> + <translation type="vanished">Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. Der Updatevorgang lief auf Zeitüberschreitung.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="696"/> <source>Could not clean up temporary directory %1. You can delete it manually at any time.</source> - <translation>Das temporäre Verzeichnis %1 konnte nicht aufgeräumt werden. Sie können es später manuell löschen.</translation> + <translation type="vanished">Das temporäre Verzeichnis %1 konnte nicht aufgeräumt werden. Sie können es später manuell löschen.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="732"/> <source>Could not run new version for continuing update.</source> - <translation>Die neue Version zum Fortführen des Updates kann nicht gestartet werden.</translation> + <translation type="vanished">Die neue Version zum Fortführen des Updates kann nicht gestartet werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="817"/> <source>Package not in tar.gz format, cannot install: %1</source> - <translation>Das Paket liegt nicht im tar.gz Format vor. %1 kann nicht installiert werden.</translation> + <translation type="vanished">Das Paket liegt nicht im tar.gz Format vor. %1 kann nicht installiert werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="824"/> <source>Package %1 cannot be installed, because cannot move it to directory: %2</source> - <translation>Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2 verschoben werden kann.</translation> + <translation type="vanished">Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2 verschoben werden kann.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="833"/> <source>Package %1 cannot be installed, because cannot unpack it: %2</source> - <translation>Das Paket %1 kann nicht installiert werden, weil es nicht extrahiert werden kann: %2</translation> + <translation type="vanished">Das Paket %1 kann nicht installiert werden, weil es nicht extrahiert werden kann: %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="852"/> <source>Package not in zip format, cannot install: %1</source> - <translation>Das Paket liegt nicht im zip Format vor. %1 kann nicht installiert werden.</translation> + <translation type="vanished">Das Paket liegt nicht im zip Format vor. %1 kann nicht installiert werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="859"/> <source>Package %1 cannot be installed, because cannot unzip it to directory %2: %3</source> - <translation>Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2: %3 extrahiert werden kann.</translation> + <translation type="vanished">Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2: %3 extrahiert werden kann.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="873"/> <source>Package %1 cannot be installed, because cannot unzip it to directory: %2</source> - <translation>Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2 entzippt werden kann.</translation> + <translation type="vanished">Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2 entzippt werden kann.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="923"/> - <location filename="../services/updatemanager.cpp" line="932"/> <source>Could not rename directory %1 to %2.</source> - <translation>Das Verzeichnis %1 konnte nicht in %2 umbenannt werden.</translation> + <translation type="vanished">Das Verzeichnis %1 konnte nicht in %2 umbenannt werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="945"/> <source>Could not delete directory %1.</source> - <translation>Das Verzeichnis %1 konnte nicht gelöscht werden.</translation> + <translation type="vanished">Das Verzeichnis %1 konnte nicht gelöscht werden.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="961"/> <source>Error executing update command: %1 Error message: %2</source> - <translation>Fehler beim Ausführen des Updatekommandos %1. + <translation type="vanished">Fehler beim Ausführen des Updatekommandos %1. Fehlerbeschreibung: %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="1028"/> <source>An error occurred while downloading updates: %1. Updating aborted.</source> - <translation>Beim Herunterladen des Updates %1 ist ein fehelr aufgetreten. Der Updatevorgang wurde abgebrochen.</translation> + <translation type="vanished">Beim Herunterladen des Updates %1 ist ein fehelr aufgetreten. Der Updatevorgang wurde abgebrochen.</translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> + <translation type="unfinished"></translation> </message> </context> </TS> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_es.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_es.ts index 007c39b..f0c170b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_es.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_es.ts @@ -4,26 +4,18 @@ <context> <name>AbstractDb</name> <message> - <location filename="../db/abstractdb.cpp" line="306"/> - <location filename="../db/abstractdb.cpp" line="323"/> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> <source>Cannot execute query on closed database.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb.cpp" line="603"/> + <location filename="../db/abstractdb.cpp" line="643"/> <source>Error attaching database %1: %2</source> <translation type="unfinished"></translation> </message> </context> <context> - <name>BugReporter</name> - <message> - <location filename="../services/bugreporter.cpp" line="46"/> - <source>Invalid login or password</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> <name>ChainExecutor</name> <message> <location filename="../db/chainexecutor.cpp" line="37"/> @@ -146,37 +138,50 @@ </message> </context> <context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>DbManagerImpl</name> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="63"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> <source>Could not add database %1: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="138"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> <source>Database %1 could not be updated, because of an error: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="350"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="379"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> <source>Database file doesn't exist.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="352"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="381"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="604"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> <source>No supporting plugin loaded.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="522"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> <source>Database could not be initialized.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="532"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> <source>No suitable database driver plugin found.</source> <translation type="unfinished"></translation> </message> @@ -243,17 +248,17 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>DbVersionConverter</name> <message> - <location filename="../dbversionconverter.cpp" line="916"/> + <location filename="../dbversionconverter.cpp" line="932"/> <source>Target file exists, but could not be overwritten.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="935"/> + <location filename="../dbversionconverter.cpp" line="951"/> <source>Could not find proper database plugin to create target database.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="1169"/> + <location filename="../dbversionconverter.cpp" line="1185"/> <source>Error while converting database: %1</source> <translation type="unfinished"></translation> </message> @@ -456,20 +461,20 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="180"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> <source>Error while importing data: %1</source> <translation type="unfinished"></translation> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="184"/> <source>Interrupted.</source> <comment>import process status update</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../importworker.cpp" line="175"/> + <location filename="../importworker.cpp" line="172"/> <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> <translation type="unfinished"></translation> </message> @@ -763,12 +768,12 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../populateworker.cpp" line="63"/> + <location filename="../populateworker.cpp" line="70"/> <source>Error while populating table: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../populateworker.cpp" line="74"/> + <location filename="../populateworker.cpp" line="81"/> <source>Could not commit transaction after table populating. Error details: %1</source> <translation type="unfinished"></translation> </message> @@ -776,71 +781,77 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>QObject</name> <message> - <location filename="../db/abstractdb2.h" line="199"/> - <location filename="../db/abstractdb3.h" line="356"/> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> <source>Could not open database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb2.h" line="805"/> - <location filename="../db/abstractdb3.h" line="1100"/> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> <source>Result set expired or no row available.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb3.h" line="376"/> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> <source>Could not close database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="137"/> - <location filename="../dbversionconverter.cpp" line="142"/> - <location filename="../dbversionconverter.cpp" line="195"/> - <location filename="../dbversionconverter.cpp" line="240"/> - <location filename="../dbversionconverter.cpp" line="245"/> - <location filename="../dbversionconverter.cpp" line="253"/> - <location filename="../dbversionconverter.cpp" line="331"/> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> <source>SQLite %1 does not support '%2' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="201"/> + <location filename="../dbversionconverter.cpp" line="202"/> <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="424"/> + <location filename="../dbversionconverter.cpp" line="429"/> <source>Could not parse statement: %1 Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="435"/> - <location filename="../dbversionconverter.cpp" line="461"/> - <location filename="../dbversionconverter.cpp" line="482"/> - <location filename="../dbversionconverter.cpp" line="515"/> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="488"/> + <location filename="../dbversionconverter.cpp" line="497"/> <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="756"/> + <location filename="../dbversionconverter.cpp" line="772"/> <source>SQLite %1 does not support current date or time clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="759"/> + <location filename="../dbversionconverter.cpp" line="775"/> <source>SQLite %1 does not support row value clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="770"/> - <location filename="../dbversionconverter.cpp" line="773"/> - <location filename="../dbversionconverter.cpp" line="784"/> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> <source>SQLite %1 does not support '%2' clause in expressions.</source> <translation type="unfinished"></translation> </message> @@ -857,13 +868,13 @@ Error details: %2</source> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="1904"/> - <location filename="../parser/sqlite3_parse.cpp" line="2169"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> <source>Parser stack overflow</source> <translation type="unfinished"></translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="4465"/> - <location filename="../parser/sqlite3_parse.cpp" line="5088"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> <source>Syntax error</source> <translation type="unfinished"></translation> </message> @@ -918,58 +929,58 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="352"/> + <location filename="../selectresolver.cpp" line="359"/> <source>Could not resolve data source for column: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="424"/> + <location filename="../selectresolver.cpp" line="431"/> <source>Could not resolve table for column '%1'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/configimpl.cpp" line="614"/> + <location filename="../services/impl/configimpl.cpp" line="768"/> <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="291"/> + <location filename="../sqlitestudio.cpp" line="305"/> <source>General purpose</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="292"/> + <location filename="../sqlitestudio.cpp" line="306"/> <source>Database support</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="293"/> + <location filename="../sqlitestudio.cpp" line="307"/> <source>Code formatter</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="294"/> + <location filename="../sqlitestudio.cpp" line="308"/> <source>Scripting languages</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="295"/> + <location filename="../sqlitestudio.cpp" line="309"/> <source>Exporting</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="296"/> + <location filename="../sqlitestudio.cpp" line="310"/> <source>Importing</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="297"/> + <location filename="../sqlitestudio.cpp" line="311"/> <source>Table populating</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> @@ -980,34 +991,34 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="389"/> + <location filename="../tablemodifier.cpp" line="438"/> <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="428"/> + <location filename="../tablemodifier.cpp" line="481"/> <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="475"/> + <location filename="../tablemodifier.cpp" line="528"/> <source>Cannot not update trigger %1 according to table %2 modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="655"/> - <location filename="../tablemodifier.cpp" line="679"/> - <location filename="../tablemodifier.cpp" line="698"/> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="443"/> + <location filename="../tablemodifier.cpp" line="496"/> <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="493"/> + <location filename="../tablemodifier.cpp" line="546"/> <source>Cannot not update view %1 according to table %2 modifications. The view will remain as it is.</source> <translation type="unfinished"></translation> @@ -1027,32 +1038,37 @@ The view will remain as it is.</source> <source>SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process.</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>QueryExecutor</name> <message> - <location filename="../db/queryexecutor.cpp" line="142"/> + <location filename="../db/queryexecutor.cpp" line="186"/> <source>Execution interrupted.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="183"/> + <location filename="../db/queryexecutor.cpp" line="227"/> <source>Database is not open.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="191"/> + <location filename="../db/queryexecutor.cpp" line="235"/> <source>Only one query can be executed simultaneously.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="294"/> - <location filename="../db/queryexecutor.cpp" line="568"/> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="479"/> + <location filename="../db/queryexecutor.cpp" line="529"/> <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> <translation type="unfinished"></translation> </message> @@ -1073,31 +1089,31 @@ The view will remain as it is.</source> <context> <name>SqlHistoryModel</name> <message> - <location filename="../sqlhistorymodel.cpp" line="30"/> + <location filename="../sqlhistorymodel.cpp" line="34"/> <source>Database</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="32"/> + <location filename="../sqlhistorymodel.cpp" line="36"/> <source>Execution date</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="34"/> + <location filename="../sqlhistorymodel.cpp" line="38"/> <source>Time spent</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="36"/> + <location filename="../sqlhistorymodel.cpp" line="40"/> <source>Rows affected</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="38"/> + <location filename="../sqlhistorymodel.cpp" line="42"/> <source>SQL</source> <comment>sql history header</comment> <translation type="unfinished"></translation> @@ -1106,200 +1122,24 @@ The view will remain as it is.</source> <context> <name>UpdateManager</name> <message> - <location filename="../services/updatemanager.cpp" line="131"/> - <source>An error occurred while checking for updates: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="144"/> - <source>Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="175"/> - <source>An error occurred while reading updates metadata: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="188"/> - <source>Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="195"/> - <source>Could not create temporary directory for downloading the update. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="206"/> - <source>There was no updates to download. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="241"/> - <source>Downloading: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="247"/> - <source>Could not determinate file name from update URL: %1. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="255"/> - <source>Failed to open file '%1' for writting: %2. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="276"/> - <source>Installing updates.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="287"/> - <source>Could not copy current application directory into %1 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="340"/> - <source>Could not create directory %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="348"/> - <source>Could not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="352"/> - <source>Cannot not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="360"/> - <source>Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="365"/> - <source>Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="444"/> - <source>Could not unpack component %1 into %2 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="555"/> - <source>Could not find permissions elevator application to run update as a root. Looked for: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="562"/> - <source>Could not execute final updating steps as root: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <location filename="../services/updatemanager.cpp" line="600"/> - <location filename="../services/updatemanager.cpp" line="613"/> - <location filename="../services/updatemanager.cpp" line="623"/> - <source>Could not execute final updating steps as admin: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <source>Cannot create temporary directory for updater.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="600"/> - <source>Cannot create updater script file.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="633"/> - <source>Updating canceled.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="661"/> - <source>Could not execute final updating steps as administrator.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="673"/> - <source>Could not execute final updating steps as administrator. Updater startup timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="679"/> - <source>Could not execute final updating steps as administrator. Updater operation timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="696"/> - <source>Could not clean up temporary directory %1. You can delete it manually at any time.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="732"/> - <source>Could not run new version for continuing update.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="817"/> - <source>Package not in tar.gz format, cannot install: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="824"/> - <source>Package %1 cannot be installed, because cannot move it to directory: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="833"/> - <source>Package %1 cannot be installed, because cannot unpack it: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="852"/> - <source>Package not in zip format, cannot install: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="859"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory %2: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="873"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="923"/> - <location filename="../services/updatemanager.cpp" line="932"/> - <source>Could not rename directory %1 to %2.</source> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="945"/> - <source>Could not delete directory %1.</source> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="961"/> - <source>Error executing update command: %1 -Error message: %2</source> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="1028"/> - <source>An error occurred while downloading updates: %1. Updating aborted.</source> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> <translation type="unfinished"></translation> </message> </context> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.qm Binary files differindex fccc28a..552d0cf 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.qm +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.qm diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.ts index bac1096..15f6cf7 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.ts @@ -4,13 +4,13 @@ <context> <name>AbstractDb</name> <message> - <location filename="../db/abstractdb.cpp" line="306"/> - <location filename="../db/abstractdb.cpp" line="323"/> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> <source>Cannot execute query on closed database.</source> <translation>Impossible d’exécuter la requête sur une base de données fermée.</translation> </message> <message> - <location filename="../db/abstractdb.cpp" line="603"/> + <location filename="../db/abstractdb.cpp" line="643"/> <source>Error attaching database %1: %2</source> <translation>Erreur base de données attachée %1 : %2</translation> </message> @@ -18,9 +18,8 @@ <context> <name>BugReporter</name> <message> - <location filename="../services/bugreporter.cpp" line="46"/> <source>Invalid login or password</source> - <translation>Identifiant ou mot de passe incorrect</translation> + <translation type="vanished">Identifiant ou mot de passe incorrect</translation> </message> </context> <context> @@ -146,37 +145,50 @@ </message> </context> <context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>DbManagerImpl</name> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="63"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> <source>Could not add database %1: %2</source> <translation>Impossible d’ajouter une base de données %1 : %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="138"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> <source>Database %1 could not be updated, because of an error: %2</source> <translation>La base de données %1 ne peut ëtre mise à jour à cause de l’erreur : %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="350"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="379"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> <source>Database file doesn't exist.</source> <translation>Le fichier de la base de données n’existe pas.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="352"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="381"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="604"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> <source>No supporting plugin loaded.</source> <translation>Aucun plugin supporté chargé.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="522"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> <source>Database could not be initialized.</source> <translation>La base de données ne peut être initialisée.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="532"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> <source>No suitable database driver plugin found.</source> <translation>Aucun pilote de base de données approprié trouvé.</translation> </message> @@ -244,17 +256,17 @@ Tables, index, déclencheurs et vues copiés de la base de données %3 seront ma <context> <name>DbVersionConverter</name> <message> - <location filename="../dbversionconverter.cpp" line="916"/> + <location filename="../dbversionconverter.cpp" line="932"/> <source>Target file exists, but could not be overwritten.</source> <translation>Le fichier cible existe, mais ne peut être remplacé.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="935"/> + <location filename="../dbversionconverter.cpp" line="951"/> <source>Could not find proper database plugin to create target database.</source> <translation>Impossible de trouver le plugin correct pour créer la base de données cible.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="1169"/> + <location filename="../dbversionconverter.cpp" line="1185"/> <source>Error while converting database: %1</source> <translation>Erreur lors de la conversion de la base de données : %1</translation> </message> @@ -457,20 +469,20 @@ Tables, index, déclencheurs et vues copiés de la base de données %3 seront ma </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="180"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> <source>Error while importing data: %1</source> <translation>Erreur lors de l’import des données : %1</translation> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="184"/> <source>Interrupted.</source> <comment>import process status update</comment> <translation>Transaction interrompue.</translation> </message> <message> - <location filename="../importworker.cpp" line="175"/> + <location filename="../importworker.cpp" line="172"/> <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> <translation type="unfinished"></translation> </message> @@ -764,12 +776,12 @@ Tables, index, déclencheurs et vues copiés de la base de données %3 seront ma <translation>Impossible d’initialiser la transaction pour remplir la table.Détails de l’erreur %1</translation> </message> <message> - <location filename="../populateworker.cpp" line="63"/> + <location filename="../populateworker.cpp" line="70"/> <source>Error while populating table: %1</source> <translation>Erreur lors du remplissage de la table : %1</translation> </message> <message> - <location filename="../populateworker.cpp" line="74"/> + <location filename="../populateworker.cpp" line="81"/> <source>Could not commit transaction after table populating. Error details: %1</source> <translation>Impossible d’enregistrer la transaction après le remplissage de la table. Erreur %1</translation> </message> @@ -777,72 +789,78 @@ Tables, index, déclencheurs et vues copiés de la base de données %3 seront ma <context> <name>QObject</name> <message> - <location filename="../db/abstractdb2.h" line="199"/> - <location filename="../db/abstractdb3.h" line="356"/> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> <source>Could not open database: %1</source> <translation>Impossible d’ouvrir la base de données : %1</translation> </message> <message> - <location filename="../db/abstractdb2.h" line="805"/> - <location filename="../db/abstractdb3.h" line="1100"/> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> <source>Result set expired or no row available.</source> <translation>Terminé ou aucune ligne valide.</translation> </message> <message> - <location filename="../db/abstractdb3.h" line="376"/> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> <source>Could not close database: %1</source> <translation>Impossible de clore la base de bonnées : %1</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="137"/> - <location filename="../dbversionconverter.cpp" line="142"/> - <location filename="../dbversionconverter.cpp" line="195"/> - <location filename="../dbversionconverter.cpp" line="240"/> - <location filename="../dbversionconverter.cpp" line="245"/> - <location filename="../dbversionconverter.cpp" line="253"/> - <location filename="../dbversionconverter.cpp" line="331"/> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> <source>SQLite %1 does not support '%2' statement.</source> <translation>SQLite %1 ne supporte pas l’instruction « %2 ».</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="201"/> + <location filename="../dbversionconverter.cpp" line="202"/> <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> <translation>SQLite %1 ne supporte pas l’instruction « %2 », mais la table normale peut être créée à la place si vous confirmez.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="424"/> + <location filename="../dbversionconverter.cpp" line="429"/> <source>Could not parse statement: %1 Error details: %2</source> <translation>Impossible d’analyser l’instruction : %1 Détails erreur: %2</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="435"/> - <location filename="../dbversionconverter.cpp" line="461"/> - <location filename="../dbversionconverter.cpp" line="482"/> - <location filename="../dbversionconverter.cpp" line="515"/> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> <translation>SQLite %1 ne supporte pas la clause « %2 ». Impossible de convertir l’instruction « %3 » avec cette clause.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="488"/> + <location filename="../dbversionconverter.cpp" line="497"/> <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> <translation>SQLite %1 ne supporte pas la clause « %2 » de l’instruction « %3 ».</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="756"/> + <location filename="../dbversionconverter.cpp" line="772"/> <source>SQLite %1 does not support current date or time clauses in expressions.</source> <translation>SQLite %1 ne supporte pas la clause date ou l’heure actuelle dans l’expression.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="759"/> + <location filename="../dbversionconverter.cpp" line="775"/> <source>SQLite %1 does not support row value clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="770"/> - <location filename="../dbversionconverter.cpp" line="773"/> - <location filename="../dbversionconverter.cpp" line="784"/> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> <source>SQLite %1 does not support '%2' clause in expressions.</source> <translation>SQLite %1 ne supporte pas la clause « %2 » dans l’expression.</translation> </message> @@ -859,13 +877,13 @@ Détails erreur: %2</translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="1904"/> - <location filename="../parser/sqlite3_parse.cpp" line="2169"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> <source>Parser stack overflow</source> <translation>Analyse dépassement pile</translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="4465"/> - <location filename="../parser/sqlite3_parse.cpp" line="5088"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> <source>Syntax error</source> <translation>Erreur de syntaxe</translation> </message> @@ -920,60 +938,60 @@ Détails erreur: %2</translation> <translation>L’application de code ne peut être vide.</translation> </message> <message> - <location filename="../selectresolver.cpp" line="352"/> + <location filename="../selectresolver.cpp" line="359"/> <source>Could not resolve data source for column: %1</source> <translation>Impossible de résoudre la source de données pour la colonnes : %1</translation> </message> <message> - <location filename="../selectresolver.cpp" line="424"/> + <location filename="../selectresolver.cpp" line="431"/> <source>Could not resolve table for column '%1'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/configimpl.cpp" line="614"/> + <location filename="../services/impl/configimpl.cpp" line="768"/> <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> <translation>Impossible d’initialiser le fichier de configuration. Aucune modification et les requêtes seront perdues après redémarrage. Essayez d’initialiser le fichier avec cette localisation : %1.</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="291"/> + <location filename="../sqlitestudio.cpp" line="305"/> <source>General purpose</source> <comment>plugin category name</comment> <translation>Objectif général</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="292"/> + <location filename="../sqlitestudio.cpp" line="306"/> <source>Database support</source> <comment>plugin category name</comment> <translation>Support base de données</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="293"/> + <location filename="../sqlitestudio.cpp" line="307"/> <source>Code formatter</source> <comment>plugin category name</comment> <translation>Format code</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="294"/> + <location filename="../sqlitestudio.cpp" line="308"/> <source>Scripting languages</source> <comment>plugin category name</comment> <translation>Langages script</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="295"/> + <location filename="../sqlitestudio.cpp" line="309"/> <source>Exporting</source> <comment>plugin category name</comment> <translation>Export</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="296"/> + <location filename="../sqlitestudio.cpp" line="310"/> <source>Importing</source> <comment>plugin category name</comment> <translation>Import</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="297"/> + <location filename="../sqlitestudio.cpp" line="311"/> <source>Table populating</source> <comment>plugin category name</comment> <translation>Peuplement de la table</translation> @@ -984,34 +1002,34 @@ Détails erreur: %2</translation> <translation>La table %1 référence la table %2, mais la clef étrangère ne pourra être mise à jour pour la nouvelle table à cause de problèmes lors de l’analyse DDL de la table %3.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="389"/> + <location filename="../tablemodifier.cpp" line="438"/> <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> <translation>Toutes les colonnes indéxées par l’index %1 sont traitées. L’index ne sera pas recréé après la modification de la table.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="428"/> + <location filename="../tablemodifier.cpp" line="481"/> <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="475"/> + <location filename="../tablemodifier.cpp" line="528"/> <source>Cannot not update trigger %1 according to table %2 modification.</source> <translation>Impossible de mettre à jour le déclencheur %1 selon la modification de la table %2.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="655"/> - <location filename="../tablemodifier.cpp" line="679"/> - <location filename="../tablemodifier.cpp" line="698"/> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="443"/> + <location filename="../tablemodifier.cpp" line="496"/> <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> <translation>Toutes les colonnes couvertes par le déclencheur %1 sont faites. Le déclencheur ne sera pas recréé après la modification de la table.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="493"/> + <location filename="../tablemodifier.cpp" line="546"/> <source>Cannot not update view %1 according to table %2 modifications. The view will remain as it is.</source> <translation>Impossible de mettre à jour les modifications de la vue %1 issue de la table %2 @@ -1036,32 +1054,37 @@ La vue restera telque.</translation> <source>SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process.</source> <translation>SQLiteStudio ne peut résoudre les colonnes résultant de la nouvelle vue, d’où le déclencheur en cause ne pourra être indiqué pendant le process.</translation> </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>QueryExecutor</name> <message> - <location filename="../db/queryexecutor.cpp" line="142"/> + <location filename="../db/queryexecutor.cpp" line="186"/> <source>Execution interrupted.</source> <translation>Exécution interrompue.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="183"/> + <location filename="../db/queryexecutor.cpp" line="227"/> <source>Database is not open.</source> <translation>La base de données n’est ouverte.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="191"/> + <location filename="../db/queryexecutor.cpp" line="235"/> <source>Only one query can be executed simultaneously.</source> <translation>Une seule requête peut être exécutée à la fois.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="294"/> - <location filename="../db/queryexecutor.cpp" line="568"/> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> <translation>Une erreur s’est produite à l’exécution de la requête count(*), la recherche des données est arrêtée. Erreur de la base de données : %1</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="479"/> + <location filename="../db/queryexecutor.cpp" line="529"/> <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> <translation>SQLiteStudio ne peut extraire des métadonnées d’une requête. Les résultats ne peut être affichés.</translation> </message> @@ -1082,31 +1105,31 @@ La vue restera telque.</translation> <context> <name>SqlHistoryModel</name> <message> - <location filename="../sqlhistorymodel.cpp" line="30"/> + <location filename="../sqlhistorymodel.cpp" line="34"/> <source>Database</source> <comment>sql history header</comment> <translation>Base de données</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="32"/> + <location filename="../sqlhistorymodel.cpp" line="36"/> <source>Execution date</source> <comment>sql history header</comment> <translation>Date d’exécution</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="34"/> + <location filename="../sqlhistorymodel.cpp" line="38"/> <source>Time spent</source> <comment>sql history header</comment> <translation>Temps passé</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="36"/> + <location filename="../sqlhistorymodel.cpp" line="40"/> <source>Rows affected</source> <comment>sql history header</comment> <translation>Lignes affectées</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="38"/> + <location filename="../sqlhistorymodel.cpp" line="42"/> <source>SQL</source> <comment>sql history header</comment> <translation>SQL</translation> @@ -1115,203 +1138,182 @@ La vue restera telque.</translation> <context> <name>UpdateManager</name> <message> - <location filename="../services/updatemanager.cpp" line="131"/> <source>An error occurred while checking for updates: %1.</source> - <translation>Une erreur est apparue lors du contrôle pour la mise à jour : %1. + <translation type="vanished">Une erreur est apparue lors du contrôle pour la mise à jour : %1. </translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="144"/> <source>Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.</source> - <translation>Impossible de vérifier la mise à jour, car le serveur a répondu avec un message invalide. Il est possible d’ignorer le warning.</translation> + <translation type="vanished">Impossible de vérifier la mise à jour, car le serveur a répondu avec un message invalide. Il est possible d’ignorer le warning.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="175"/> <source>An error occurred while reading updates metadata: %1.</source> - <translation>Erreur lors de la lecture de mise des méta données : %1.</translation> + <translation type="vanished">Erreur lors de la lecture de mise des méta données : %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="188"/> <source>Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details.</source> - <translation>Impossibles de télécharger les mises à jour, car le serveur répond avec un format de message invalide. Vous pover essayer plus tard ou télécharger et mettre à jour manuellement. Voir <a href="%1">User Manual</a> for details.</translation> + <translation type="vanished">Impossibles de télécharger les mises à jour, car le serveur répond avec un format de message invalide. Vous pover essayer plus tard ou télécharger et mettre à jour manuellement. Voir <a href="%1">User Manual</a> for details.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="195"/> <source>Could not create temporary directory for downloading the update. Updating aborted.</source> - <translation>Impossible de créer un répertoire temporaire pour télécharger la mise à jour. Mise à jour abandonnée.</translation> + <translation type="vanished">Impossible de créer un répertoire temporaire pour télécharger la mise à jour. Mise à jour abandonnée.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="206"/> <source>There was no updates to download. Updating aborted.</source> - <translation>Il n’y a aucune mise à jour à télécharger. Mise à jour abandonnée.</translation> + <translation type="vanished">Il n’y a aucune mise à jour à télécharger. Mise à jour abandonnée.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="241"/> <source>Downloading: %1</source> - <translation>Téléchargement : %1</translation> + <translation type="vanished">Téléchargement : %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="247"/> <source>Could not determinate file name from update URL: %1. Updating aborted.</source> - <translation>Impossible de déterminer le fichier de mise à jour URL : %1.Mise à jour abandonnée.</translation> + <translation type="vanished">Impossible de déterminer le fichier de mise à jour URL : %1.Mise à jour abandonnée.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="255"/> <source>Failed to open file '%1' for writting: %2. Updating aborted.</source> - <translation>Erreur à l’ouverture du fichier « %1 » pour l’écriture : %2. Mise à jour abandonnée.</translation> + <translation type="vanished">Erreur à l’ouverture du fichier « %1 » pour l’écriture : %2. Mise à jour abandonnée.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="276"/> <source>Installing updates.</source> - <translation>Installation des mises jour.</translation> + <translation type="vanished">Installation des mises jour.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="287"/> <source>Could not copy current application directory into %1 directory.</source> - <translation>Impossible de copier le répertoire de l’application courante dans %1.</translation> + <translation type="vanished">Impossible de copier le répertoire de l’application courante dans %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="340"/> <source>Could not create directory %1.</source> - <translation>Impossible de créer le répertoire : %1.</translation> + <translation type="vanished">Impossible de créer le répertoire : %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="348"/> <source>Could not rename directory %1 to %2. Details: %3</source> - <translation>Impossible de renommer le répertoire %1 en %2. Détails : %3</translation> + <translation type="vanished">Impossible de renommer le répertoire %1 en %2. Détails : %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="352"/> <source>Cannot not rename directory %1 to %2. Details: %3</source> - <translation>Impossible de renommer le répertoire %1 en %2.Détails : %3</translation> + <translation type="vanished">Impossible de renommer le répertoire %1 en %2.Détails : %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="360"/> <source>Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3</source> - <translation>Impossible de déplacer le répertoire %1 vers %2 d’où l’impossibilité de restaurer le répertoire original. SQLiteStudio est maintenant localisé : %3</translation> + <translation type="vanished">Impossible de déplacer le répertoire %1 vers %2 d’où l’impossibilité de restaurer le répertoire original. SQLiteStudio est maintenant localisé : %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="365"/> <source>Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.</source> - <translation>Impossible de renommer le répertoire %1 en %2, retour vers la version originale SQLiteStudio.</translation> + <translation type="vanished">Impossible de renommer le répertoire %1 en %2, retour vers la version originale SQLiteStudio.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="444"/> <source>Could not unpack component %1 into %2 directory.</source> - <translation>Impossible d’extraire le composant %1 dans le répertoire %2.</translation> + <translation type="vanished">Impossible d’extraire le composant %1 dans le répertoire %2.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="555"/> <source>Could not find permissions elevator application to run update as a root. Looked for: %1</source> - <translation>Impossible d’élever les autorisations pour lancer la mise à jour en tantque root. Bloqué : %1</translation> + <translation type="vanished">Impossible d’élever les autorisations pour lancer la mise à jour en tantque root. Bloqué : %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="562"/> <source>Could not execute final updating steps as root: %1</source> - <translation>Impossible de finaliser la mis à jour en tant que root : %1</translation> + <translation type="vanished">Impossible de finaliser la mis à jour en tant que root : %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <location filename="../services/updatemanager.cpp" line="600"/> - <location filename="../services/updatemanager.cpp" line="613"/> - <location filename="../services/updatemanager.cpp" line="623"/> <source>Could not execute final updating steps as admin: %1</source> - <translation>Impossible de finaliser la mis à jour en tant que admin : %1</translation> + <translation type="vanished">Impossible de finaliser la mis à jour en tant que admin : %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="591"/> <source>Cannot create temporary directory for updater.</source> - <translation>Impossible de créer un répertoire temporaire pour la mise à jour.</translation> + <translation type="vanished">Impossible de créer un répertoire temporaire pour la mise à jour.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="600"/> <source>Cannot create updater script file.</source> - <translation>impossible de créer le fichier du scripte de mise à jour.</translation> + <translation type="vanished">impossible de créer le fichier du scripte de mise à jour.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="633"/> <source>Updating canceled.</source> - <translation>Mise à jour suspendue.</translation> + <translation type="vanished">Mise à jour suspendue.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="661"/> <source>Could not execute final updating steps as administrator.</source> - <translation>Impossible de finaliser la mis à jour en tant qu’administrateur.</translation> + <translation type="vanished">Impossible de finaliser la mis à jour en tant qu’administrateur.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="673"/> <source>Could not execute final updating steps as administrator. Updater startup timed out.</source> - <translation>Impossible de finaliser la mis à jour en tant qu’administrateur. Délai d’attente de lancement dépassé.</translation> + <translation type="vanished">Impossible de finaliser la mis à jour en tant qu’administrateur. Délai d’attente de lancement dépassé.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="679"/> <source>Could not execute final updating steps as administrator. Updater operation timed out.</source> - <translation>Impossible de finaliser la mis à jour en tant qu’administrateur. Délai d’attente d’opération dépassé.</translation> + <translation type="vanished">Impossible de finaliser la mis à jour en tant qu’administrateur. Délai d’attente d’opération dépassé.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="696"/> <source>Could not clean up temporary directory %1. You can delete it manually at any time.</source> - <translation>Impossible de nettoyer le répertoire temporaire %1. Vous pouver le supprimer manuellement plutard.</translation> + <translation type="vanished">Impossible de nettoyer le répertoire temporaire %1. Vous pouver le supprimer manuellement plutard.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="732"/> <source>Could not run new version for continuing update.</source> - <translation>Impossible de lancer la nouvelle version afin de continuer la mise à jour.</translation> + <translation type="vanished">Impossible de lancer la nouvelle version afin de continuer la mise à jour.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="817"/> <source>Package not in tar.gz format, cannot install: %1</source> - <translation>Installation impossible un paquet n’est pas au format tar.zg : %1</translation> + <translation type="vanished">Installation impossible un paquet n’est pas au format tar.zg : %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="824"/> <source>Package %1 cannot be installed, because cannot move it to directory: %2</source> - <translation>Le paquet %1 ne peut être installé, celui-ci ne pouvant déplacé dans le répertoire : %2</translation> + <translation type="vanished">Le paquet %1 ne peut être installé, celui-ci ne pouvant déplacé dans le répertoire : %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="833"/> <source>Package %1 cannot be installed, because cannot unpack it: %2</source> - <translation>Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé : %2</translation> + <translation type="vanished">Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé : %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="852"/> <source>Package not in zip format, cannot install: %1</source> - <translation>Installation impossible, un paquet est manquant : %1</translation> + <translation type="vanished">Installation impossible, un paquet est manquant : %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="859"/> <source>Package %1 cannot be installed, because cannot unzip it to directory %2: %3</source> - <translation>Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé dans le répertoire %2 : %3</translation> + <translation type="vanished">Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé dans le répertoire %2 : %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="873"/> <source>Package %1 cannot be installed, because cannot unzip it to directory: %2</source> - <translation>Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé dans le répertoire : %2</translation> + <translation type="vanished">Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé dans le répertoire : %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="923"/> - <location filename="../services/updatemanager.cpp" line="932"/> <source>Could not rename directory %1 to %2.</source> - <translation>Impossible de renommer le répertoire %1 en %2.</translation> + <translation type="vanished">Impossible de renommer le répertoire %1 en %2.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="945"/> <source>Could not delete directory %1.</source> - <translation>Impossible de supprimer le répertoire %1.</translation> + <translation type="vanished">Impossible de supprimer le répertoire %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="961"/> <source>Error executing update command: %1 Error message: %2</source> - <translation>Erreur d’exécution de la commande de mise à jour : %1 + <translation type="vanished">Erreur d’exécution de la commande de mise à jour : %1 Message d’erreur : %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="1028"/> <source>An error occurred while downloading updates: %1. Updating aborted.</source> - <translation>Erreur lors du téléchargement de la mise à jour : %1. Mise à jour abandonnée.</translation> + <translation type="vanished">Erreur lors du téléchargement de la mise à jour : %1. Mise à jour abandonnée.</translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> + <translation type="unfinished"></translation> </message> </context> </TS> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_it.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_it.ts index beed03d..461461f 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_it.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_it.ts @@ -4,26 +4,18 @@ <context> <name>AbstractDb</name> <message> - <location filename="../db/abstractdb.cpp" line="306"/> - <location filename="../db/abstractdb.cpp" line="323"/> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> <source>Cannot execute query on closed database.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb.cpp" line="603"/> + <location filename="../db/abstractdb.cpp" line="643"/> <source>Error attaching database %1: %2</source> <translation type="unfinished"></translation> </message> </context> <context> - <name>BugReporter</name> - <message> - <location filename="../services/bugreporter.cpp" line="46"/> - <source>Invalid login or password</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> <name>ChainExecutor</name> <message> <location filename="../db/chainexecutor.cpp" line="37"/> @@ -146,37 +138,50 @@ </message> </context> <context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>DbManagerImpl</name> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="63"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> <source>Could not add database %1: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="138"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> <source>Database %1 could not be updated, because of an error: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="350"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="379"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> <source>Database file doesn't exist.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="352"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="381"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="604"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> <source>No supporting plugin loaded.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="522"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> <source>Database could not be initialized.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="532"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> <source>No suitable database driver plugin found.</source> <translation type="unfinished"></translation> </message> @@ -243,17 +248,17 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>DbVersionConverter</name> <message> - <location filename="../dbversionconverter.cpp" line="916"/> + <location filename="../dbversionconverter.cpp" line="932"/> <source>Target file exists, but could not be overwritten.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="935"/> + <location filename="../dbversionconverter.cpp" line="951"/> <source>Could not find proper database plugin to create target database.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="1169"/> + <location filename="../dbversionconverter.cpp" line="1185"/> <source>Error while converting database: %1</source> <translation type="unfinished"></translation> </message> @@ -456,20 +461,20 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="180"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> <source>Error while importing data: %1</source> <translation type="unfinished"></translation> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="184"/> <source>Interrupted.</source> <comment>import process status update</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../importworker.cpp" line="175"/> + <location filename="../importworker.cpp" line="172"/> <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> <translation type="unfinished"></translation> </message> @@ -763,12 +768,12 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../populateworker.cpp" line="63"/> + <location filename="../populateworker.cpp" line="70"/> <source>Error while populating table: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../populateworker.cpp" line="74"/> + <location filename="../populateworker.cpp" line="81"/> <source>Could not commit transaction after table populating. Error details: %1</source> <translation type="unfinished"></translation> </message> @@ -776,71 +781,77 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>QObject</name> <message> - <location filename="../db/abstractdb2.h" line="199"/> - <location filename="../db/abstractdb3.h" line="356"/> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> <source>Could not open database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb2.h" line="805"/> - <location filename="../db/abstractdb3.h" line="1100"/> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> <source>Result set expired or no row available.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb3.h" line="376"/> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> <source>Could not close database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="137"/> - <location filename="../dbversionconverter.cpp" line="142"/> - <location filename="../dbversionconverter.cpp" line="195"/> - <location filename="../dbversionconverter.cpp" line="240"/> - <location filename="../dbversionconverter.cpp" line="245"/> - <location filename="../dbversionconverter.cpp" line="253"/> - <location filename="../dbversionconverter.cpp" line="331"/> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> <source>SQLite %1 does not support '%2' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="201"/> + <location filename="../dbversionconverter.cpp" line="202"/> <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="424"/> + <location filename="../dbversionconverter.cpp" line="429"/> <source>Could not parse statement: %1 Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="435"/> - <location filename="../dbversionconverter.cpp" line="461"/> - <location filename="../dbversionconverter.cpp" line="482"/> - <location filename="../dbversionconverter.cpp" line="515"/> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="488"/> + <location filename="../dbversionconverter.cpp" line="497"/> <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="756"/> + <location filename="../dbversionconverter.cpp" line="772"/> <source>SQLite %1 does not support current date or time clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="759"/> + <location filename="../dbversionconverter.cpp" line="775"/> <source>SQLite %1 does not support row value clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="770"/> - <location filename="../dbversionconverter.cpp" line="773"/> - <location filename="../dbversionconverter.cpp" line="784"/> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> <source>SQLite %1 does not support '%2' clause in expressions.</source> <translation type="unfinished"></translation> </message> @@ -857,13 +868,13 @@ Error details: %2</source> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="1904"/> - <location filename="../parser/sqlite3_parse.cpp" line="2169"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> <source>Parser stack overflow</source> <translation type="unfinished"></translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="4465"/> - <location filename="../parser/sqlite3_parse.cpp" line="5088"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> <source>Syntax error</source> <translation type="unfinished"></translation> </message> @@ -918,58 +929,58 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="352"/> + <location filename="../selectresolver.cpp" line="359"/> <source>Could not resolve data source for column: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="424"/> + <location filename="../selectresolver.cpp" line="431"/> <source>Could not resolve table for column '%1'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/configimpl.cpp" line="614"/> + <location filename="../services/impl/configimpl.cpp" line="768"/> <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="291"/> + <location filename="../sqlitestudio.cpp" line="305"/> <source>General purpose</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="292"/> + <location filename="../sqlitestudio.cpp" line="306"/> <source>Database support</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="293"/> + <location filename="../sqlitestudio.cpp" line="307"/> <source>Code formatter</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="294"/> + <location filename="../sqlitestudio.cpp" line="308"/> <source>Scripting languages</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="295"/> + <location filename="../sqlitestudio.cpp" line="309"/> <source>Exporting</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="296"/> + <location filename="../sqlitestudio.cpp" line="310"/> <source>Importing</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="297"/> + <location filename="../sqlitestudio.cpp" line="311"/> <source>Table populating</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> @@ -980,35 +991,35 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="389"/> + <location filename="../tablemodifier.cpp" line="438"/> <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="428"/> + <location filename="../tablemodifier.cpp" line="481"/> <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="443"/> + <location filename="../tablemodifier.cpp" line="496"/> <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="475"/> + <location filename="../tablemodifier.cpp" line="528"/> <source>Cannot not update trigger %1 according to table %2 modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="493"/> + <location filename="../tablemodifier.cpp" line="546"/> <source>Cannot not update view %1 according to table %2 modifications. The view will remain as it is.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="655"/> - <location filename="../tablemodifier.cpp" line="679"/> - <location filename="../tablemodifier.cpp" line="698"/> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> <translation type="unfinished"></translation> </message> @@ -1027,32 +1038,37 @@ The view will remain as it is.</source> <source>SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process.</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>QueryExecutor</name> <message> - <location filename="../db/queryexecutor.cpp" line="142"/> + <location filename="../db/queryexecutor.cpp" line="186"/> <source>Execution interrupted.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="183"/> + <location filename="../db/queryexecutor.cpp" line="227"/> <source>Database is not open.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="191"/> + <location filename="../db/queryexecutor.cpp" line="235"/> <source>Only one query can be executed simultaneously.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="294"/> - <location filename="../db/queryexecutor.cpp" line="568"/> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="479"/> + <location filename="../db/queryexecutor.cpp" line="529"/> <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> <translation type="unfinished"></translation> </message> @@ -1073,31 +1089,31 @@ The view will remain as it is.</source> <context> <name>SqlHistoryModel</name> <message> - <location filename="../sqlhistorymodel.cpp" line="30"/> + <location filename="../sqlhistorymodel.cpp" line="34"/> <source>Database</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="32"/> + <location filename="../sqlhistorymodel.cpp" line="36"/> <source>Execution date</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="34"/> + <location filename="../sqlhistorymodel.cpp" line="38"/> <source>Time spent</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="36"/> + <location filename="../sqlhistorymodel.cpp" line="40"/> <source>Rows affected</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="38"/> + <location filename="../sqlhistorymodel.cpp" line="42"/> <source>SQL</source> <comment>sql history header</comment> <translation type="unfinished"></translation> @@ -1106,200 +1122,24 @@ The view will remain as it is.</source> <context> <name>UpdateManager</name> <message> - <location filename="../services/updatemanager.cpp" line="131"/> - <source>An error occurred while checking for updates: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="144"/> - <source>Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="175"/> - <source>An error occurred while reading updates metadata: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="188"/> - <source>Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="195"/> - <source>Could not create temporary directory for downloading the update. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="206"/> - <source>There was no updates to download. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="241"/> - <source>Downloading: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="247"/> - <source>Could not determinate file name from update URL: %1. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="255"/> - <source>Failed to open file '%1' for writting: %2. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="276"/> - <source>Installing updates.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="287"/> - <source>Could not copy current application directory into %1 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="340"/> - <source>Could not create directory %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="348"/> - <source>Could not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="352"/> - <source>Cannot not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="360"/> - <source>Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="365"/> - <source>Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="444"/> - <source>Could not unpack component %1 into %2 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="555"/> - <source>Could not find permissions elevator application to run update as a root. Looked for: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="562"/> - <source>Could not execute final updating steps as root: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <location filename="../services/updatemanager.cpp" line="600"/> - <location filename="../services/updatemanager.cpp" line="613"/> - <location filename="../services/updatemanager.cpp" line="623"/> - <source>Could not execute final updating steps as admin: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <source>Cannot create temporary directory for updater.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="600"/> - <source>Cannot create updater script file.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="633"/> - <source>Updating canceled.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="661"/> - <source>Could not execute final updating steps as administrator.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="673"/> - <source>Could not execute final updating steps as administrator. Updater startup timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="679"/> - <source>Could not execute final updating steps as administrator. Updater operation timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="696"/> - <source>Could not clean up temporary directory %1. You can delete it manually at any time.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="732"/> - <source>Could not run new version for continuing update.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="817"/> - <source>Package not in tar.gz format, cannot install: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="824"/> - <source>Package %1 cannot be installed, because cannot move it to directory: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="833"/> - <source>Package %1 cannot be installed, because cannot unpack it: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="852"/> - <source>Package not in zip format, cannot install: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="859"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory %2: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="873"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="923"/> - <location filename="../services/updatemanager.cpp" line="932"/> - <source>Could not rename directory %1 to %2.</source> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="945"/> - <source>Could not delete directory %1.</source> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="961"/> - <source>Error executing update command: %1 -Error message: %2</source> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="1028"/> - <source>An error occurred while downloading updates: %1. Updating aborted.</source> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> <translation type="unfinished"></translation> </message> </context> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.qm Binary files differindex 76565a1..d8a2202 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.qm +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.qm diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.ts index 843aebe..6a1e7aa 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.ts @@ -4,13 +4,13 @@ <context> <name>AbstractDb</name> <message> - <location filename="../db/abstractdb.cpp" line="306"/> - <location filename="../db/abstractdb.cpp" line="323"/> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> <source>Cannot execute query on closed database.</source> <translation>Nie można wykonać zapytania na zamkniętej bazie danych.</translation> </message> <message> - <location filename="../db/abstractdb.cpp" line="603"/> + <location filename="../db/abstractdb.cpp" line="643"/> <source>Error attaching database %1: %2</source> <translation>Błąd podczas dołączania bazy danych %1: %2</translation> </message> @@ -18,9 +18,8 @@ <context> <name>BugReporter</name> <message> - <location filename="../services/bugreporter.cpp" line="46"/> <source>Invalid login or password</source> - <translation>Niepoprawny login lub hasło</translation> + <translation type="vanished">Niepoprawny login lub hasło</translation> </message> </context> <context> @@ -146,37 +145,50 @@ </message> </context> <context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation>Nie można rozpocząć transakcji dla usuwania historii SQL, więc nie można usunąć historii.</translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation>Nie można zatwierdzić transakcji dla usuwania historii SQL, więc nie można usunąć historii.</translation> + </message> +</context> +<context> <name>DbManagerImpl</name> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="63"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> <source>Could not add database %1: %2</source> <translation>Nie udało się dodać bazę danych %1: %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="138"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> <source>Database %1 could not be updated, because of an error: %2</source> <translation>Nie udało się zaktualizować baza danych %1 z powodu błędu: %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="350"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="379"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> <source>Database file doesn't exist.</source> <translation>Plik bazy danych nie istnieje.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="352"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="381"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="604"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> <source>No supporting plugin loaded.</source> <translation>Nie załadowano obsługującej wtyczki.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="522"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> <source>Database could not be initialized.</source> <translation>Nie udało się zainicjalizować bazy danych.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="532"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> <source>No suitable database driver plugin found.</source> <translation>Nie znaleziono odpowiedniej wtyczki sterownika.</translation> </message> @@ -244,17 +256,17 @@ Tabele, indeksy, wyzwalacze i widoki skopiowane do bazy danych %3 pozostaną na <context> <name>DbVersionConverter</name> <message> - <location filename="../dbversionconverter.cpp" line="916"/> + <location filename="../dbversionconverter.cpp" line="932"/> <source>Target file exists, but could not be overwritten.</source> <translation>Plik docelowy istnieje, ale nie może być nadpisany.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="935"/> + <location filename="../dbversionconverter.cpp" line="951"/> <source>Could not find proper database plugin to create target database.</source> <translation>Nie znaleziono odpowiedniej wtyczki bazy danych, aby utworzyć docelową bazę danych.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="1169"/> + <location filename="../dbversionconverter.cpp" line="1185"/> <source>Error while converting database: %1</source> <translation>Błąd podczas konwersji bazy danych: %1</translation> </message> @@ -465,20 +477,20 @@ Tabele, indeksy, wyzwalacze i widoki skopiowane do bazy danych %3 pozostaną na </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="180"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> <source>Error while importing data: %1</source> <translation>Błąd podczas importowania danych: %1</translation> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="184"/> <source>Interrupted.</source> <comment>import process status update</comment> <translation>Przerwano.</translation> </message> <message> - <location filename="../importworker.cpp" line="175"/> + <location filename="../importworker.cpp" line="172"/> <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> <translation>Nie udało się zaimportować wiersza danych numer %1. Wiersz ten został zignorowany. Szczegóły problemu: %2</translation> </message> @@ -772,12 +784,12 @@ Tabele, indeksy, wyzwalacze i widoki skopiowane do bazy danych %3 pozostaną na <translation>Nie udało się rozpocząć transakcji w celu zaludnienia tabeli. Szczegóły błędu: %1</translation> </message> <message> - <location filename="../populateworker.cpp" line="63"/> + <location filename="../populateworker.cpp" line="70"/> <source>Error while populating table: %1</source> <translation>Błąd podczas zaludniania tabeli: %2</translation> </message> <message> - <location filename="../populateworker.cpp" line="74"/> + <location filename="../populateworker.cpp" line="81"/> <source>Could not commit transaction after table populating. Error details: %1</source> <translation>Nie udało się zatwierdzić transakcji po zaludnieniu tabeli. Szczegóły błędy: %1</translation> </message> @@ -785,38 +797,38 @@ Tabele, indeksy, wyzwalacze i widoki skopiowane do bazy danych %3 pozostaną na <context> <name>QObject</name> <message> - <location filename="../dbversionconverter.cpp" line="137"/> - <location filename="../dbversionconverter.cpp" line="142"/> - <location filename="../dbversionconverter.cpp" line="195"/> - <location filename="../dbversionconverter.cpp" line="240"/> - <location filename="../dbversionconverter.cpp" line="245"/> - <location filename="../dbversionconverter.cpp" line="253"/> - <location filename="../dbversionconverter.cpp" line="331"/> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> <source>SQLite %1 does not support '%2' statement.</source> <translation>SQLite %1 nie obsługuje zapytania '%2'.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="201"/> + <location filename="../dbversionconverter.cpp" line="202"/> <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> <translation>SQLite %1 nie obsługuje zapytania '%2', ale stworzona zostanie zwykła tabela, jeśli będziesz kontynuować.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="424"/> + <location filename="../dbversionconverter.cpp" line="429"/> <source>Could not parse statement: %1 Error details: %2</source> <translation>Nie udało się przeanalizować zapytania: %1 Szczegóły błędu: %2</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="435"/> - <location filename="../dbversionconverter.cpp" line="461"/> - <location filename="../dbversionconverter.cpp" line="482"/> - <location filename="../dbversionconverter.cpp" line="515"/> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> <translation>SQLite %1 nie obsługuje klauzuli '%2'. Nie można przekonwertować zapytania '%3' z tą klauzulą.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="488"/> + <location filename="../dbversionconverter.cpp" line="497"/> <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> <translation>SQLite %1 nie obsługuje klauzuli '%2' w zapytaniu '%3'.</translation> </message> @@ -825,19 +837,19 @@ Szczegóły błędu: %2</translation> <translation type="obsolete">SQLite %1 nie obsługuje klauzuli '%2'. Nie można przekonwertować zapytania '%3' z tą klauzulą. {1 ?} {2'?} {1'?}</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="756"/> + <location filename="../dbversionconverter.cpp" line="772"/> <source>SQLite %1 does not support current date or time clauses in expressions.</source> <translation>SQLite %1 nie obsługuje aktualnej daty lub klauzul czasowu w wyrażeniach.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="759"/> + <location filename="../dbversionconverter.cpp" line="775"/> <source>SQLite %1 does not support row value clauses in expressions.</source> <translation>SQLite %1 nie obsługuje klauzuli wartości wierszowej w wyrażeniach.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="770"/> - <location filename="../dbversionconverter.cpp" line="773"/> - <location filename="../dbversionconverter.cpp" line="784"/> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> <source>SQLite %1 does not support '%2' clause in expressions.</source> <translation>SQLite %1 nie obsługuje klauzuli '%2' w wyrażeniach.</translation> </message> @@ -854,13 +866,13 @@ Szczegóły błędu: %2</translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="1904"/> - <location filename="../parser/sqlite3_parse.cpp" line="2169"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> <source>Parser stack overflow</source> <translation>Przeciążenie stosu analizatora.</translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="4465"/> - <location filename="../parser/sqlite3_parse.cpp" line="5088"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> <source>Syntax error</source> <translation>Błąd składni</translation> </message> @@ -915,58 +927,58 @@ Szczegóły błędu: %2</translation> <translation>Kod implementacji nie może być pusty.</translation> </message> <message> - <location filename="../selectresolver.cpp" line="352"/> + <location filename="../selectresolver.cpp" line="359"/> <source>Could not resolve data source for column: %1</source> <translation>Nie znaleziono źródła danych dla kolumny: %1</translation> </message> <message> - <location filename="../selectresolver.cpp" line="424"/> + <location filename="../selectresolver.cpp" line="431"/> <source>Could not resolve table for column '%1'.</source> <translation>Nie można ustalić tabeli lub kolumny '%1'.</translation> </message> <message> - <location filename="../services/impl/configimpl.cpp" line="614"/> + <location filename="../services/impl/configimpl.cpp" line="768"/> <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> <translation>Nie udało się zainicjalizować pliku konfiguracyjnego. Jakiekolwiek zmiany w konfiguracji i historia zapytań będą utracone po zrestartowaniu aplikacji. Próbowano zainicjalizować plik konfiguracyjny w następujących lokalizacjach: %1.</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="291"/> + <location filename="../sqlitestudio.cpp" line="305"/> <source>General purpose</source> <comment>plugin category name</comment> <translation>Ogólne</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="292"/> + <location filename="../sqlitestudio.cpp" line="306"/> <source>Database support</source> <comment>plugin category name</comment> <translation>Wsparcie baz danych</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="293"/> + <location filename="../sqlitestudio.cpp" line="307"/> <source>Code formatter</source> <comment>plugin category name</comment> <translation>Formatowanie kodu</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="294"/> + <location filename="../sqlitestudio.cpp" line="308"/> <source>Scripting languages</source> <comment>plugin category name</comment> <translation>Języki skryptowe</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="295"/> + <location filename="../sqlitestudio.cpp" line="309"/> <source>Exporting</source> <comment>plugin category name</comment> <translation>Eksportowanie</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="296"/> + <location filename="../sqlitestudio.cpp" line="310"/> <source>Importing</source> <comment>plugin category name</comment> <translation>Importowanie</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="297"/> + <location filename="../sqlitestudio.cpp" line="311"/> <source>Table populating</source> <comment>plugin category name</comment> <translation>Zaludnianie tabel</translation> @@ -977,34 +989,34 @@ Szczegóły błędu: %2</translation> <translation>Tabela %1 odwołuje się do tabeli %2, ale definicja klucza obcego nie zostanie zaktualizowane dla definicji nowej tabeli w związku z problemami przy analizowaniu DDL tabeli %3.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="389"/> + <location filename="../tablemodifier.cpp" line="438"/> <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> <translation>Wszystkie kolumny indeksowane przez indeks %1 już nie istnieją. Indeks ten nie będzie odtworzony po modyfikacji tabeli.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="428"/> + <location filename="../tablemodifier.cpp" line="481"/> <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> <translation>Wystąpił problem z poprawnym przetworzeniem wyzwalacza %1. Może on zostać zaktualizowany tylko częściowo i będzie wymagał twojej uwagi.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="475"/> + <location filename="../tablemodifier.cpp" line="528"/> <source>Cannot not update trigger %1 according to table %2 modification.</source> <translation>Nie można zaktualizować wyzwalacza %1 zgodnie z modyfikacjami tabeli %2.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="655"/> - <location filename="../tablemodifier.cpp" line="679"/> - <location filename="../tablemodifier.cpp" line="698"/> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> <translation>Jest problem ze zaktualizowaniem zapytania %1 w wyzwalaczu %2. Jedeno z podzapytań %1, które może odwoływać się do tabeli %3 nie może być poprawnie zmodyfikowane. Ręczna aktualizacja tego wyzwalacza może być niezbędna.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="443"/> + <location filename="../tablemodifier.cpp" line="496"/> <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> <translation>Wszystkie kolumny obsługiwane przez wyzwalacz %1 już nie istnieją. Wyzwalacz ten nie będzie odtworzony po modyfikacji tabeli.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="493"/> + <location filename="../tablemodifier.cpp" line="546"/> <source>Cannot not update view %1 according to table %2 modifications. The view will remain as it is.</source> <translation>Nie można zaktualizować widoku %1 w związku z modyfikacjami tabeli %2. @@ -1030,22 +1042,33 @@ Widok pozostanie nienaruszony.</translation> <translation>SQLiteStudio nie było w stanie określić kolumn zwracanych przez nowy widok, w związku z czym nie może określić które wyzwalacze mogą się nie powieść podczas procesu odtwarzania.</translation> </message> <message> - <location filename="../db/abstractdb2.h" line="199"/> - <location filename="../db/abstractdb3.h" line="356"/> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> <source>Could not open database: %1</source> <translation>Nie udało się otworzyć bazy danych: %1</translation> </message> <message> - <location filename="../db/abstractdb3.h" line="376"/> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation>Nie udało się załadować rozszerzenia %1: %2</translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> <source>Could not close database: %1</source> <translation>Nie udało się zamknąć bazy danych: %1</translation> </message> <message> - <location filename="../db/abstractdb2.h" line="805"/> - <location filename="../db/abstractdb3.h" line="1100"/> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> <source>Result set expired or no row available.</source> <translation>Wyniki zapytania są nieaktualne, lub nie ma dostępnych wierszy.</translation> </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation>Nie można otworzyż pliku '%1' do odczytu: %2</translation> + </message> </context> <context> <name>Query</name> @@ -1057,28 +1080,28 @@ Widok pozostanie nienaruszony.</translation> <context> <name>QueryExecutor</name> <message> - <location filename="../db/queryexecutor.cpp" line="142"/> + <location filename="../db/queryexecutor.cpp" line="186"/> <source>Execution interrupted.</source> <translation>Wykonywanie przerwane.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="183"/> + <location filename="../db/queryexecutor.cpp" line="227"/> <source>Database is not open.</source> <translation>Baza danych nie jest otwarta.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="191"/> + <location filename="../db/queryexecutor.cpp" line="235"/> <source>Only one query can be executed simultaneously.</source> <translation>Tylko jedno zapytanie może być wykonywane w danym momencie.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="294"/> - <location filename="../db/queryexecutor.cpp" line="568"/> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> <translation>Wystąpił błąd podczas wykonywania zapytania count(*), przez co stronicowanie danych będzie wyłączone. Szczegóły błędy z bazy danych: %1</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="479"/> + <location filename="../db/queryexecutor.cpp" line="529"/> <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> <translation>SQLiteStudio nie mogło uzyskać metadanych z zapytania. Nie będzie można edytować wyników zapytania.</translation> </message> @@ -1099,31 +1122,31 @@ Widok pozostanie nienaruszony.</translation> <context> <name>SqlHistoryModel</name> <message> - <location filename="../sqlhistorymodel.cpp" line="30"/> + <location filename="../sqlhistorymodel.cpp" line="34"/> <source>Database</source> <comment>sql history header</comment> <translation>Baza danych</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="32"/> + <location filename="../sqlhistorymodel.cpp" line="36"/> <source>Execution date</source> <comment>sql history header</comment> <translation>Data wykonania</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="34"/> + <location filename="../sqlhistorymodel.cpp" line="38"/> <source>Time spent</source> <comment>sql history header</comment> <translation>Czas trwania</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="36"/> + <location filename="../sqlhistorymodel.cpp" line="40"/> <source>Rows affected</source> <comment>sql history header</comment> <translation>Liczba wierszy</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="38"/> + <location filename="../sqlhistorymodel.cpp" line="42"/> <source>SQL</source> <comment>sql history header</comment> <translation>SQL</translation> @@ -1132,204 +1155,183 @@ Widok pozostanie nienaruszony.</translation> <context> <name>UpdateManager</name> <message> - <location filename="../services/updatemanager.cpp" line="131"/> <source>An error occurred while checking for updates: %1.</source> - <translation>Wystąpił błąd podczas sprawdzania aktualizacji: %1</translation> + <translation type="vanished">Wystąpił błąd podczas sprawdzania aktualizacji: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="144"/> <source>Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.</source> - <translation>Nie udało się sprawdzić aktualizacji, ponieważ serwer odpowiedział wiadomością w niepoprawnym formacie. Możesz spokojnie zignorować tą informację.</translation> + <translation type="vanished">Nie udało się sprawdzić aktualizacji, ponieważ serwer odpowiedział wiadomością w niepoprawnym formacie. Możesz spokojnie zignorować tą informację.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="175"/> <source>An error occurred while reading updates metadata: %1.</source> - <translation>Wystąpił błąd podczas odczytu metadanych aktualizacji: %1</translation> + <translation type="vanished">Wystąpił błąd podczas odczytu metadanych aktualizacji: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="188"/> <source>Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details.</source> - <translation>Nie udało się ściągnąć aktualizacji, ponieważ serwer odpowiedział wiadomością w niepoprawnym formacie. Możesz spróbować jeszcze raz później, lub ściągnąć i stainstalować aktualizację ręcznie. Szczegóły: <a href="%1">Podręcznik użytkownika</a>.</translation> + <translation type="vanished">Nie udało się ściągnąć aktualizacji, ponieważ serwer odpowiedział wiadomością w niepoprawnym formacie. Możesz spróbować jeszcze raz później, lub ściągnąć i stainstalować aktualizację ręcznie. Szczegóły: <a href="%1">Podręcznik użytkownika</a>.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="195"/> <source>Could not create temporary directory for downloading the update. Updating aborted.</source> - <translation>Nie udało się stworzyć katalogu tymczasowego w celu pobrania aktualizacji. Aktualizacja została przerwana.</translation> + <translation type="vanished">Nie udało się stworzyć katalogu tymczasowego w celu pobrania aktualizacji. Aktualizacja została przerwana.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="206"/> <source>There was no updates to download. Updating aborted.</source> - <translation>Nie znaleziono aktualizacji do pobrania. Aktualizacja przerwana.</translation> + <translation type="vanished">Nie znaleziono aktualizacji do pobrania. Aktualizacja przerwana.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="241"/> <source>Downloading: %1</source> - <translation>Pobieranie: %1</translation> + <translation type="vanished">Pobieranie: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="247"/> <source>Could not determinate file name from update URL: %1. Updating aborted.</source> - <translation>Nie udało się określić nazwy pliku z URL aktualizacji: %1. Aktualizacja przerwana.</translation> + <translation type="vanished">Nie udało się określić nazwy pliku z URL aktualizacji: %1. Aktualizacja przerwana.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="255"/> <source>Failed to open file '%1' for writting: %2. Updating aborted.</source> - <translation>Nie udało się otworzyć pliku '%1' do zapisu: %2. Aktualizacja przerwana.</translation> + <translation type="vanished">Nie udało się otworzyć pliku '%1' do zapisu: %2. Aktualizacja przerwana.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="276"/> <source>Installing updates.</source> - <translation>Instalowanie aktualizacji.</translation> + <translation type="vanished">Instalowanie aktualizacji.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="287"/> <source>Could not copy current application directory into %1 directory.</source> - <translation>Nie udało się skopiować bieżącego katalogu aplikacji do katalogu %1.</translation> + <translation type="vanished">Nie udało się skopiować bieżącego katalogu aplikacji do katalogu %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="340"/> <source>Could not create directory %1.</source> - <translation>Nie udało się stworzyć katalogu %1.</translation> + <translation type="vanished">Nie udało się stworzyć katalogu %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="348"/> <source>Could not rename directory %1 to %2. Details: %3</source> - <translation>Nie udało się zmienić nazwy katalogu %1 na %2. + <translation type="vanished">Nie udało się zmienić nazwy katalogu %1 na %2. Szczegóły: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="352"/> <source>Cannot not rename directory %1 to %2. Details: %3</source> - <translation>Nie można zmienić nazwy katalogu %1 na %2. + <translation type="vanished">Nie można zmienić nazwy katalogu %1 na %2. Szczegóły: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="360"/> <source>Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3</source> - <translation>Nie udało się przenieść katalogu %1 do %2, oraz nie udało się przywrócić originalnego katalog, więc originalny katalog SQLiteStudio jest mieści się teraz w: %3</translation> + <translation type="vanished">Nie udało się przenieść katalogu %1 do %2, oraz nie udało się przywrócić originalnego katalog, więc originalny katalog SQLiteStudio jest mieści się teraz w: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="365"/> <source>Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.</source> - <translation>Nie udało się zmienić nazwy katalogu %1 na %2. Przywrócono originalną wersję SQLiteStudio.</translation> + <translation type="vanished">Nie udało się zmienić nazwy katalogu %1 na %2. Przywrócono originalną wersję SQLiteStudio.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="444"/> <source>Could not unpack component %1 into %2 directory.</source> - <translation>Nie udało się rozpakować komponentu %1 do katalogu %2.</translation> + <translation type="vanished">Nie udało się rozpakować komponentu %1 do katalogu %2.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="555"/> <source>Could not find permissions elevator application to run update as a root. Looked for: %1</source> - <translation>Nie udało się znaleźć narzędzia do podnoszenia uprawnień aplikacji, aby uruchomić aktualizację jako administrator. Szukano następujących: %1</translation> + <translation type="vanished">Nie udało się znaleźć narzędzia do podnoszenia uprawnień aplikacji, aby uruchomić aktualizację jako administrator. Szukano następujących: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="562"/> <source>Could not execute final updating steps as root: %1</source> - <translation>Nie udało się wykonać ostatnich kroków jako administrator: %1</translation> + <translation type="vanished">Nie udało się wykonać ostatnich kroków jako administrator: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <location filename="../services/updatemanager.cpp" line="600"/> - <location filename="../services/updatemanager.cpp" line="613"/> - <location filename="../services/updatemanager.cpp" line="623"/> <source>Could not execute final updating steps as admin: %1</source> - <translation>Nie udało się wykonać ostatnich kroków jako administrator: %1</translation> + <translation type="vanished">Nie udało się wykonać ostatnich kroków jako administrator: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="591"/> <source>Cannot create temporary directory for updater.</source> - <translation>Nie można stworzyć tymczasowego katalogu dla aktualizacji.</translation> + <translation type="vanished">Nie można stworzyć tymczasowego katalogu dla aktualizacji.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="600"/> <source>Cannot create updater script file.</source> - <translation>Nie można utworzyć skryptu aktualizacji.</translation> + <translation type="vanished">Nie można utworzyć skryptu aktualizacji.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="633"/> <source>Updating canceled.</source> - <translation>Aktualizacja wycofana.</translation> + <translation type="vanished">Aktualizacja wycofana.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="661"/> <source>Could not execute final updating steps as administrator.</source> - <translation>Nie udało się wykonać ostatich kroków aktualizacji jako administrator.</translation> + <translation type="vanished">Nie udało się wykonać ostatich kroków aktualizacji jako administrator.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="673"/> <source>Could not execute final updating steps as administrator. Updater startup timed out.</source> - <translation>Nie udało się wykonać ostatich kroków aktualizacji jako administrator. Przekroczono limit czasu oczekiwania.</translation> + <translation type="vanished">Nie udało się wykonać ostatich kroków aktualizacji jako administrator. Przekroczono limit czasu oczekiwania.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="679"/> <source>Could not execute final updating steps as administrator. Updater operation timed out.</source> - <translation>Nie udało się wykonać ostatich kroków aktualizacji jako administrator. Przekroczono limit czasu oczekiwania.</translation> + <translation type="vanished">Nie udało się wykonać ostatich kroków aktualizacji jako administrator. Przekroczono limit czasu oczekiwania.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="696"/> <source>Could not clean up temporary directory %1. You can delete it manually at any time.</source> - <translation>Nie udało się wyczyścić katalogu tymczasowego %1. Możesz go usunąć ręcznie w dowolnym momencie.</translation> + <translation type="vanished">Nie udało się wyczyścić katalogu tymczasowego %1. Możesz go usunąć ręcznie w dowolnym momencie.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="732"/> <source>Could not run new version for continuing update.</source> - <translation>Nie udało się uruchomić nowej wersji w celu kontynuowania aktualizacji.</translation> + <translation type="vanished">Nie udało się uruchomić nowej wersji w celu kontynuowania aktualizacji.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="817"/> <source>Package not in tar.gz format, cannot install: %1</source> - <translation>Paczka nie jest w formacie tar.gz, nie można zainstalować: %1</translation> + <translation type="vanished">Paczka nie jest w formacie tar.gz, nie można zainstalować: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="824"/> <source>Package %1 cannot be installed, because cannot move it to directory: %2</source> - <translation>Paczka %1 nie może być zainstalowana, ponieważ nie można przenieść jej do katalogu: %2</translation> + <translation type="vanished">Paczka %1 nie może być zainstalowana, ponieważ nie można przenieść jej do katalogu: %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="833"/> <source>Package %1 cannot be installed, because cannot unpack it: %2</source> - <translation>Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować: %2</translation> + <translation type="vanished">Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować: %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="852"/> <source>Package not in zip format, cannot install: %1</source> - <translation>Paczka nie jest w formacie zip, nie można zainstalować: %1</translation> + <translation type="vanished">Paczka nie jest w formacie zip, nie można zainstalować: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="859"/> <source>Package %1 cannot be installed, because cannot unzip it to directory %2: %3</source> - <translation>Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować do katalogu %2: %3</translation> + <translation type="vanished">Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować do katalogu %2: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="873"/> <source>Package %1 cannot be installed, because cannot unzip it to directory: %2</source> - <translation>Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować do katalogu %2</translation> + <translation type="vanished">Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować do katalogu %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="923"/> - <location filename="../services/updatemanager.cpp" line="932"/> <source>Could not rename directory %1 to %2.</source> - <translation>Nie udało się zmienić nazwy katalogu %1 na %2.</translation> + <translation type="vanished">Nie udało się zmienić nazwy katalogu %1 na %2.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="945"/> <source>Could not delete directory %1.</source> - <translation>Nie udało się skasować katalogu %1.</translation> + <translation type="vanished">Nie udało się skasować katalogu %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="961"/> <source>Error executing update command: %1 Error message: %2</source> - <translation>Błąd podczas wykonywania polecenia aktualizacji: %1 + <translation type="vanished">Błąd podczas wykonywania polecenia aktualizacji: %1 Treść błędu: %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="1028"/> <source>An error occurred while downloading updates: %1. Updating aborted.</source> - <translation>Wystąpił błąd podczas pobierania aktualizacji: %1. Aktualizacja przerwana.</translation> + <translation type="vanished">Wystąpił błąd podczas pobierania aktualizacji: %1. Aktualizacja przerwana.</translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> + <translation>Nie można znaleźć pliku wykonywalnego instalatora aktualizacji.</translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> + <translation>Nie można sprawdzić dostępnych aktualizacji (%1)</translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> + <translation>szczegóły nieznane</translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> + <translation>Nie można uruchomić aplikacji aktualizującej (%1). Proszę to zgłosić.</translation> </message> </context> </TS> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.qm Binary files differindex 8d72a0b..95d8136 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.qm +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.qm diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.ts index 82a5283..8f3404e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.ts @@ -4,13 +4,13 @@ <context> <name>AbstractDb</name> <message> - <location filename="../db/abstractdb.cpp" line="306"/> - <location filename="../db/abstractdb.cpp" line="323"/> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> <source>Cannot execute query on closed database.</source> <translation type="unfinished">Não é possível executar query em banco de dados fechado.</translation> </message> <message> - <location filename="../db/abstractdb.cpp" line="603"/> + <location filename="../db/abstractdb.cpp" line="643"/> <source>Error attaching database %1: %2</source> <translation type="unfinished"> </translation> </message> @@ -18,9 +18,8 @@ <context> <name>BugReporter</name> <message> - <location filename="../services/bugreporter.cpp" line="46"/> <source>Invalid login or password</source> - <translation>login ou senha inválido</translation> + <translation type="vanished">login ou senha inválido</translation> </message> </context> <context> @@ -146,37 +145,50 @@ </message> </context> <context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>DbManagerImpl</name> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="63"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> <source>Could not add database %1: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="138"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> <source>Database %1 could not be updated, because of an error: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="350"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="379"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> <source>Database file doesn't exist.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="352"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="381"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="604"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> <source>No supporting plugin loaded.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="522"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> <source>Database could not be initialized.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="532"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> <source>No suitable database driver plugin found.</source> <translation type="unfinished"></translation> </message> @@ -243,17 +255,17 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>DbVersionConverter</name> <message> - <location filename="../dbversionconverter.cpp" line="916"/> + <location filename="../dbversionconverter.cpp" line="932"/> <source>Target file exists, but could not be overwritten.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="935"/> + <location filename="../dbversionconverter.cpp" line="951"/> <source>Could not find proper database plugin to create target database.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="1169"/> + <location filename="../dbversionconverter.cpp" line="1185"/> <source>Error while converting database: %1</source> <translation type="unfinished"></translation> </message> @@ -456,20 +468,20 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="180"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> <source>Error while importing data: %1</source> <translation type="unfinished"></translation> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="184"/> <source>Interrupted.</source> <comment>import process status update</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../importworker.cpp" line="175"/> + <location filename="../importworker.cpp" line="172"/> <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> <translation type="unfinished"></translation> </message> @@ -763,12 +775,12 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../populateworker.cpp" line="63"/> + <location filename="../populateworker.cpp" line="70"/> <source>Error while populating table: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../populateworker.cpp" line="74"/> + <location filename="../populateworker.cpp" line="81"/> <source>Could not commit transaction after table populating. Error details: %1</source> <translation type="unfinished"></translation> </message> @@ -776,71 +788,77 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>QObject</name> <message> - <location filename="../db/abstractdb2.h" line="199"/> - <location filename="../db/abstractdb3.h" line="356"/> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> <source>Could not open database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb2.h" line="805"/> - <location filename="../db/abstractdb3.h" line="1100"/> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> <source>Result set expired or no row available.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb3.h" line="376"/> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> <source>Could not close database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="137"/> - <location filename="../dbversionconverter.cpp" line="142"/> - <location filename="../dbversionconverter.cpp" line="195"/> - <location filename="../dbversionconverter.cpp" line="240"/> - <location filename="../dbversionconverter.cpp" line="245"/> - <location filename="../dbversionconverter.cpp" line="253"/> - <location filename="../dbversionconverter.cpp" line="331"/> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> <source>SQLite %1 does not support '%2' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="201"/> + <location filename="../dbversionconverter.cpp" line="202"/> <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="424"/> + <location filename="../dbversionconverter.cpp" line="429"/> <source>Could not parse statement: %1 Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="435"/> - <location filename="../dbversionconverter.cpp" line="461"/> - <location filename="../dbversionconverter.cpp" line="482"/> - <location filename="../dbversionconverter.cpp" line="515"/> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="488"/> + <location filename="../dbversionconverter.cpp" line="497"/> <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="756"/> + <location filename="../dbversionconverter.cpp" line="772"/> <source>SQLite %1 does not support current date or time clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="759"/> + <location filename="../dbversionconverter.cpp" line="775"/> <source>SQLite %1 does not support row value clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="770"/> - <location filename="../dbversionconverter.cpp" line="773"/> - <location filename="../dbversionconverter.cpp" line="784"/> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> <source>SQLite %1 does not support '%2' clause in expressions.</source> <translation type="unfinished"></translation> </message> @@ -857,13 +875,13 @@ Error details: %2</source> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="1904"/> - <location filename="../parser/sqlite3_parse.cpp" line="2169"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> <source>Parser stack overflow</source> <translation type="unfinished"></translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="4465"/> - <location filename="../parser/sqlite3_parse.cpp" line="5088"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> <source>Syntax error</source> <translation type="unfinished"></translation> </message> @@ -918,58 +936,58 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="352"/> + <location filename="../selectresolver.cpp" line="359"/> <source>Could not resolve data source for column: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="424"/> + <location filename="../selectresolver.cpp" line="431"/> <source>Could not resolve table for column '%1'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/configimpl.cpp" line="614"/> + <location filename="../services/impl/configimpl.cpp" line="768"/> <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="291"/> + <location filename="../sqlitestudio.cpp" line="305"/> <source>General purpose</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="292"/> + <location filename="../sqlitestudio.cpp" line="306"/> <source>Database support</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="293"/> + <location filename="../sqlitestudio.cpp" line="307"/> <source>Code formatter</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="294"/> + <location filename="../sqlitestudio.cpp" line="308"/> <source>Scripting languages</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="295"/> + <location filename="../sqlitestudio.cpp" line="309"/> <source>Exporting</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="296"/> + <location filename="../sqlitestudio.cpp" line="310"/> <source>Importing</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="297"/> + <location filename="../sqlitestudio.cpp" line="311"/> <source>Table populating</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> @@ -980,34 +998,34 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="389"/> + <location filename="../tablemodifier.cpp" line="438"/> <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="428"/> + <location filename="../tablemodifier.cpp" line="481"/> <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="475"/> + <location filename="../tablemodifier.cpp" line="528"/> <source>Cannot not update trigger %1 according to table %2 modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="655"/> - <location filename="../tablemodifier.cpp" line="679"/> - <location filename="../tablemodifier.cpp" line="698"/> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="443"/> + <location filename="../tablemodifier.cpp" line="496"/> <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="493"/> + <location filename="../tablemodifier.cpp" line="546"/> <source>Cannot not update view %1 according to table %2 modifications. The view will remain as it is.</source> <translation type="unfinished"></translation> @@ -1027,32 +1045,37 @@ The view will remain as it is.</source> <source>SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process.</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>QueryExecutor</name> <message> - <location filename="../db/queryexecutor.cpp" line="142"/> + <location filename="../db/queryexecutor.cpp" line="186"/> <source>Execution interrupted.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="183"/> + <location filename="../db/queryexecutor.cpp" line="227"/> <source>Database is not open.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="191"/> + <location filename="../db/queryexecutor.cpp" line="235"/> <source>Only one query can be executed simultaneously.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="294"/> - <location filename="../db/queryexecutor.cpp" line="568"/> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="479"/> + <location filename="../db/queryexecutor.cpp" line="529"/> <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> <translation type="unfinished"></translation> </message> @@ -1073,31 +1096,31 @@ The view will remain as it is.</source> <context> <name>SqlHistoryModel</name> <message> - <location filename="../sqlhistorymodel.cpp" line="30"/> + <location filename="../sqlhistorymodel.cpp" line="34"/> <source>Database</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="32"/> + <location filename="../sqlhistorymodel.cpp" line="36"/> <source>Execution date</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="34"/> + <location filename="../sqlhistorymodel.cpp" line="38"/> <source>Time spent</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="36"/> + <location filename="../sqlhistorymodel.cpp" line="40"/> <source>Rows affected</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="38"/> + <location filename="../sqlhistorymodel.cpp" line="42"/> <source>SQL</source> <comment>sql history header</comment> <translation type="unfinished"></translation> @@ -1106,200 +1129,24 @@ The view will remain as it is.</source> <context> <name>UpdateManager</name> <message> - <location filename="../services/updatemanager.cpp" line="131"/> - <source>An error occurred while checking for updates: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="144"/> - <source>Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="175"/> - <source>An error occurred while reading updates metadata: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="188"/> - <source>Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="195"/> - <source>Could not create temporary directory for downloading the update. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="206"/> - <source>There was no updates to download. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="241"/> - <source>Downloading: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="247"/> - <source>Could not determinate file name from update URL: %1. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="255"/> - <source>Failed to open file '%1' for writting: %2. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="276"/> - <source>Installing updates.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="287"/> - <source>Could not copy current application directory into %1 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="340"/> - <source>Could not create directory %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="348"/> - <source>Could not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="352"/> - <source>Cannot not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="360"/> - <source>Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="365"/> - <source>Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="444"/> - <source>Could not unpack component %1 into %2 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="555"/> - <source>Could not find permissions elevator application to run update as a root. Looked for: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="562"/> - <source>Could not execute final updating steps as root: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <location filename="../services/updatemanager.cpp" line="600"/> - <location filename="../services/updatemanager.cpp" line="613"/> - <location filename="../services/updatemanager.cpp" line="623"/> - <source>Could not execute final updating steps as admin: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <source>Cannot create temporary directory for updater.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="600"/> - <source>Cannot create updater script file.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="633"/> - <source>Updating canceled.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="661"/> - <source>Could not execute final updating steps as administrator.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="673"/> - <source>Could not execute final updating steps as administrator. Updater startup timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="679"/> - <source>Could not execute final updating steps as administrator. Updater operation timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="696"/> - <source>Could not clean up temporary directory %1. You can delete it manually at any time.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="732"/> - <source>Could not run new version for continuing update.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="817"/> - <source>Package not in tar.gz format, cannot install: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="824"/> - <source>Package %1 cannot be installed, because cannot move it to directory: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="833"/> - <source>Package %1 cannot be installed, because cannot unpack it: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="852"/> - <source>Package not in zip format, cannot install: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="859"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory %2: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="873"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="923"/> - <location filename="../services/updatemanager.cpp" line="932"/> - <source>Could not rename directory %1 to %2.</source> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="945"/> - <source>Could not delete directory %1.</source> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="961"/> - <source>Error executing update command: %1 -Error message: %2</source> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="1028"/> - <source>An error occurred while downloading updates: %1. Updating aborted.</source> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> <translation type="unfinished"></translation> </message> </context> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.qm Binary files differnew file mode 100644 index 0000000..2856eb9 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.qm diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.ts new file mode 100644 index 0000000..744cb0c --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.ts @@ -0,0 +1,1146 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="ro_RO"> +<context> + <name>AbstractDb</name> + <message> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> + <source>Cannot execute query on closed database.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb.cpp" line="643"/> + <source>Error attaching database %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ChainExecutor</name> + <message> + <location filename="../db/chainexecutor.cpp" line="37"/> + <source>The database for executing queries was not defined.</source> + <comment>chain executor</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/chainexecutor.cpp" line="44"/> + <source>The database for executing queries was not open.</source> + <comment>chain executor</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/chainexecutor.cpp" line="54"/> + <source>Could not disable foreign keys in the database. Details: %1</source> + <comment>chain executor</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/chainexecutor.cpp" line="62"/> + <source>Could not start a database transaction. Details: %1</source> + <comment>chain executor</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/chainexecutor.cpp" line="89"/> + <source>Interrupted</source> + <comment>chain executor</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/chainexecutor.cpp" line="151"/> + <source>Could not commit a database transaction. Details: %1</source> + <comment>chain executor</comment> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CompletionHelper</name> + <message> + <location filename="../completionhelper.cpp" line="196"/> + <source>New row reference</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="203"/> + <source>Old row reference</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="208"/> + <source>New table name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="211"/> + <source>New index name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="214"/> + <source>New view name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="217"/> + <source>New trigger name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="220"/> + <source>Table or column alias</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="223"/> + <source>transaction name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="226"/> + <source>New column name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="229"/> + <source>Column data type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="232"/> + <source>Constraint name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="245"/> + <source>Error message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="289"/> + <source>Collation name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="304"/> + <source>Any word</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="485"/> + <source>Default database</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../completionhelper.cpp" line="486"/> + <source>Temporary objects database</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DbManagerImpl</name> + <message> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> + <source>Could not add database %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> + <source>Database %1 could not be updated, because of an error: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> + <source>Database file doesn't exist.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> + <source>No supporting plugin loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> + <source>Database could not be initialized.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> + <source>No suitable database driver plugin found.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DbObjectOrganizer</name> + <message> + <location filename="../dbobjectorganizer.cpp" line="380"/> + <location filename="../dbobjectorganizer.cpp" line="412"/> + <source>Error while creating table in target database: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbobjectorganizer.cpp" line="380"/> + <source>Could not parse table.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbobjectorganizer.cpp" line="426"/> + <source>Database %1 could not be attached to database %2, so the data of table %3 will be copied with SQLiteStudio as a mediator. This method can be slow for huge tables, so please be patient.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbobjectorganizer.cpp" line="447"/> + <source>Error while copying data for table %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbobjectorganizer.cpp" line="466"/> + <location filename="../dbobjectorganizer.cpp" line="473"/> + <location filename="../dbobjectorganizer.cpp" line="496"/> + <source>Error while copying data to table %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbobjectorganizer.cpp" line="535"/> + <source>Error while dropping source view %1: %2 +Tables, indexes, triggers and views copied to database %3 will remain.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbobjectorganizer.cpp" line="542"/> + <source>Error while creating view in target database: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbobjectorganizer.cpp" line="547"/> + <source>Error while creating index in target database: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbobjectorganizer.cpp" line="552"/> + <source>Error while creating trigger in target database: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbobjectorganizer.cpp" line="773"/> + <location filename="../dbobjectorganizer.cpp" line="780"/> + <location filename="../dbobjectorganizer.cpp" line="789"/> + <source>Could not parse object '%1' in order to move or copy it.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DbVersionConverter</name> + <message> + <location filename="../dbversionconverter.cpp" line="932"/> + <source>Target file exists, but could not be overwritten.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="951"/> + <source>Could not find proper database plugin to create target database.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="1185"/> + <source>Error while converting database: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DdlHistoryModel</name> + <message> + <location filename="../ddlhistorymodel.cpp" line="65"/> + <source>Database name</source> + <comment>ddl history header</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ddlhistorymodel.cpp" line="67"/> + <source>Database file</source> + <comment>ddl history header</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ddlhistorymodel.cpp" line="69"/> + <source>Date of execution</source> + <comment>ddl history header</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../ddlhistorymodel.cpp" line="71"/> + <source>Changes</source> + <comment>ddl history header</comment> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ExportManager</name> + <message> + <location filename="../services/exportmanager.cpp" line="72"/> + <source>Export plugin %1 doesn't support exporing query results.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/exportmanager.cpp" line="98"/> + <source>Export plugin %1 doesn't support exporing tables.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/exportmanager.cpp" line="122"/> + <source>Export plugin %1 doesn't support exporing databases.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/exportmanager.cpp" line="155"/> + <source>Export format '%1' is not supported. Supported formats are: %2.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/exportmanager.cpp" line="218"/> + <source>Export to the clipboard was successful.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/exportmanager.cpp" line="222"/> + <source>Export to the file '%1' was successful.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/exportmanager.cpp" line="224"/> + <source>Export was successful.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/exportmanager.cpp" line="266"/> + <source>Could not export to file %1. File cannot be open for writting.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ExportWorker</name> + <message> + <location filename="../exportworker.cpp" line="122"/> + <source>Error while exporting query results: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../exportworker.cpp" line="202"/> + <source>Error while counting data column width to export from query results: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../exportworker.cpp" line="346"/> + <location filename="../exportworker.cpp" line="404"/> + <source>Could not parse %1 in order to export it. It will be excluded from the export output.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../exportworker.cpp" line="608"/> + <source>Error while reading data to export from table %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../exportworker.cpp" line="616"/> + <source>Error while counting data to export from table %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../exportworker.cpp" line="632"/> + <source>Error while counting data column width to export from table %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FunctionManagerImpl</name> + <message> + <location filename="../services/impl/functionmanagerimpl.cpp" line="234"/> + <source>Invalid number of arguments to function '%1'. Expected %2, but got %3.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/functionmanagerimpl.cpp" line="347"/> + <source>No such function registered in SQLiteStudio: %1(%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/functionmanagerimpl.cpp" line="353"/> + <source>Function %1(%2) was registered with language %3, but the plugin supporting that language is not currently loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/functionmanagerimpl.cpp" line="371"/> + <source>Invalid regular expression pattern: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/functionmanagerimpl.cpp" line="390"/> + <location filename="../services/impl/functionmanagerimpl.cpp" line="423"/> + <source>Could not open file %1 for reading: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/functionmanagerimpl.cpp" line="445"/> + <source>Could not open file %1 for writting: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/functionmanagerimpl.cpp" line="465"/> + <source>Error while writting to file %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/functionmanagerimpl.cpp" line="483"/> + <source>Unsupported scripting language: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>GenericExportPlugin</name> + <message> + <location filename="../plugins/genericexportplugin.cpp" line="20"/> + <source>Could not initialize text codec for exporting. Using default codec: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ImportManager</name> + <message> + <location filename="../services/importmanager.cpp" line="96"/> + <source>Imported data to the table '%1' successfully.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ImportWorker</name> + <message> + <location filename="../importworker.cpp" line="24"/> + <source>No columns provided by the import plugin.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../importworker.cpp" line="30"/> + <source>Could not start transaction in order to import a data: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../importworker.cpp" line="52"/> + <source>Could not commit transaction for imported data: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../importworker.cpp" line="100"/> + <source>Table '%1' has less columns than there are columns in the data to be imported. Excessive data columns will be ignored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../importworker.cpp" line="105"/> + <source>Table '%1' has more columns than there are columns in the data to be imported. Some columns in the table will be left empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../importworker.cpp" line="124"/> + <source>Could not create table to import to: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../importworker.cpp" line="133"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> + <source>Error while importing data: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../importworker.cpp" line="133"/> + <location filename="../importworker.cpp" line="184"/> + <source>Interrupted.</source> + <comment>import process status update</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../importworker.cpp" line="172"/> + <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PluginManagerImpl</name> + <message> + <location filename="../services/impl/pluginmanagerimpl.cpp" line="543"/> + <source>Cannot load plugin %1, because it's in conflict with plugin %2.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/pluginmanagerimpl.cpp" line="554"/> + <source>Cannot load plugin %1, because its dependency was not loaded: %2.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/pluginmanagerimpl.cpp" line="563"/> + <source>Cannot load plugin %1. Error details: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/pluginmanagerimpl.cpp" line="579"/> + <source>Cannot load plugin %1 (error while initializing plugin).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/pluginmanagerimpl.cpp" line="731"/> + <source>min: %1</source> + <comment>plugin dependency version</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/pluginmanagerimpl.cpp" line="732"/> + <source>max: %1</source> + <comment>plugin dependency version</comment> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateConstant</name> + <message> + <location filename="../plugins/populateconstant.cpp" line="10"/> + <source>Constant</source> + <comment>populate constant plugin name</comment> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateConstantConfig</name> + <message> + <location filename="../plugins/populateconstant.ui" line="20"/> + <source>Constant value:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateDictionary</name> + <message> + <location filename="../plugins/populatedictionary.cpp" line="15"/> + <source>Dictionary</source> + <comment>dictionary populating plugin name</comment> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateDictionaryConfig</name> + <message> + <location filename="../plugins/populatedictionary.ui" line="20"/> + <source>Dictionary file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatedictionary.ui" line="29"/> + <source>Pick dictionary file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatedictionary.ui" line="39"/> + <source>Word separator</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatedictionary.ui" line="45"/> + <source>Whitespace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatedictionary.ui" line="58"/> + <source>Line break</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatedictionary.ui" line="74"/> + <source>Method of using words</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatedictionary.ui" line="80"/> + <source>Ordered</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatedictionary.ui" line="93"/> + <source>Randomly</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateManager</name> + <message> + <location filename="../services/populatemanager.cpp" line="89"/> + <source>Table '%1' populated successfully.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateRandom</name> + <message> + <location filename="../plugins/populaterandom.cpp" line="12"/> + <source>Random number</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateRandomConfig</name> + <message> + <location filename="../plugins/populaterandom.ui" line="20"/> + <source>Constant prefix</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandom.ui" line="26"/> + <source>No prefix</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandom.ui" line="39"/> + <source>Minimum value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandom.ui" line="61"/> + <source>Maximum value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandom.ui" line="86"/> + <source>Constant suffix</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandom.ui" line="92"/> + <source>No suffix</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateRandomText</name> + <message> + <location filename="../plugins/populaterandomtext.cpp" line="12"/> + <source>Random text</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateRandomTextConfig</name> + <message> + <location filename="../plugins/populaterandomtext.ui" line="20"/> + <source>Use characters from common sets:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="36"/> + <source>Minimum length</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="64"/> + <source>Letters from a to z.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="67"/> + <source>Alpha</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="77"/> + <source>Numbers from 0 to 9.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="80"/> + <source>Numeric</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="90"/> + <source>A whitespace, a tab and a new line character.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="93"/> + <source>Whitespace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="103"/> + <source>Includes all above and all others.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="106"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="119"/> + <source>Use characters from my custom set:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="132"/> + <source>Maximum length</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.ui" line="160"/> + <source>If you type some character multiple times, it's more likely to be used.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateScript</name> + <message> + <location filename="../plugins/populatescript.cpp" line="13"/> + <source>Script</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateScriptConfig</name> + <message> + <location filename="../plugins/populatescript.ui" line="26"/> + <source>Initialization code (optional)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatescript.ui" line="45"/> + <source>Per step code</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatescript.ui" line="70"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatescript.ui" line="89"/> + <source>Help</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateSequence</name> + <message> + <location filename="../plugins/populatesequence.cpp" line="13"/> + <source>Sequence</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateSequenceConfig</name> + <message> + <location filename="../plugins/populatesequence.ui" line="33"/> + <source>Start value:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatesequence.ui" line="56"/> + <source>Step:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PopulateWorker</name> + <message> + <location filename="../populateworker.cpp" line="23"/> + <source>Could not start transaction in order to perform table populating. Error details: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../populateworker.cpp" line="70"/> + <source>Error while populating table: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../populateworker.cpp" line="81"/> + <source>Could not commit transaction after table populating. Error details: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> + <source>Could not open database: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> + <source>Result set expired or no row available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> + <source>Could not close database: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> + <source>SQLite %1 does not support '%2' statement.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="202"/> + <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="429"/> + <source>Could not parse statement: %1 +Error details: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> + <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="497"/> + <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="772"/> + <source>SQLite %1 does not support current date or time clauses in expressions.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="775"/> + <source>SQLite %1 does not support row value clauses in expressions.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> + <source>SQLite %1 does not support '%2' clause in expressions.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../impl/dbattacherimpl.cpp" line="115"/> + <source>Could not attach database %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../parser/parsercontext.cpp" line="108"/> + <location filename="../parser/parsercontext.cpp" line="110"/> + <source>Incomplete query.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../parser/sqlite2_parse.cpp" line="1904"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> + <source>Parser stack overflow</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../parser/sqlite2_parse.cpp" line="4465"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> + <source>Syntax error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatedictionary.cpp" line="30"/> + <source>Could not open dictionary file %1 for reading.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatedictionary.cpp" line="91"/> + <source>Dictionary file must exist and be readable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandom.cpp" line="53"/> + <source>Maximum value cannot be less than minimum value.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.cpp" line="77"/> + <source>Maximum length cannot be less than minimum length.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populaterandomtext.cpp" line="88"/> + <source>Custom character set cannot be empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatescript.cpp" line="40"/> + <source>Could not find plugin to support scripting language: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatescript.cpp" line="58"/> + <source>Error while executing populating initial code: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatescript.cpp" line="80"/> + <source>Error while executing populating code: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatescript.cpp" line="112"/> + <source>Select implementation language.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/populatescript.cpp" line="113"/> + <source>Implementation code cannot be empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../selectresolver.cpp" line="359"/> + <source>Could not resolve data source for column: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../selectresolver.cpp" line="431"/> + <source>Could not resolve table for column '%1'.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="768"/> + <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlitestudio.cpp" line="305"/> + <source>General purpose</source> + <comment>plugin category name</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlitestudio.cpp" line="306"/> + <source>Database support</source> + <comment>plugin category name</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlitestudio.cpp" line="307"/> + <source>Code formatter</source> + <comment>plugin category name</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlitestudio.cpp" line="308"/> + <source>Scripting languages</source> + <comment>plugin category name</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlitestudio.cpp" line="309"/> + <source>Exporting</source> + <comment>plugin category name</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlitestudio.cpp" line="310"/> + <source>Importing</source> + <comment>plugin category name</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlitestudio.cpp" line="311"/> + <source>Table populating</source> + <comment>plugin category name</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../tablemodifier.cpp" line="115"/> + <source>Table %1 is referencing table %2, but the foreign key definition will not be updated for new table definition due to problems while parsing DDL of the table %3.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../tablemodifier.cpp" line="438"/> + <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../tablemodifier.cpp" line="481"/> + <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../tablemodifier.cpp" line="496"/> + <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../tablemodifier.cpp" line="528"/> + <source>Cannot not update trigger %1 according to table %2 modification.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../tablemodifier.cpp" line="546"/> + <source>Cannot not update view %1 according to table %2 modifications. +The view will remain as it is.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> + <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../viewmodifier.cpp" line="25"/> + <source>Could not parse DDL of the view to be created. Details: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../viewmodifier.cpp" line="34"/> + <source>Parsed query is not CREATE VIEW. It's: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../viewmodifier.cpp" line="82"/> + <source>SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QueryExecutor</name> + <message> + <location filename="../db/queryexecutor.cpp" line="186"/> + <source>Execution interrupted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/queryexecutor.cpp" line="227"/> + <source>Database is not open.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/queryexecutor.cpp" line="235"/> + <source>Only one query can be executed simultaneously.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> + <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/queryexecutor.cpp" line="529"/> + <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ScriptingQtDbProxy</name> + <message> + <location filename="../plugins/scriptingqtdbproxy.cpp" line="48"/> + <source>No database available in current context, while called QtScript's %1 command.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../plugins/scriptingqtdbproxy.cpp" line="65"/> + <source>Error from %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SqlHistoryModel</name> + <message> + <location filename="../sqlhistorymodel.cpp" line="34"/> + <source>Database</source> + <comment>sql history header</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlhistorymodel.cpp" line="36"/> + <source>Execution date</source> + <comment>sql history header</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlhistorymodel.cpp" line="38"/> + <source>Time spent</source> + <comment>sql history header</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlhistorymodel.cpp" line="40"/> + <source>Rows affected</source> + <comment>sql history header</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../sqlhistorymodel.cpp" line="42"/> + <source>SQL</source> + <comment>sql history header</comment> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>UpdateManager</name> + <message> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.qm Binary files differindex c638942..55d59ab 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.qm +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.qm diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.ts index 4716a1d..702c2f2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.ts @@ -4,13 +4,13 @@ <context> <name>AbstractDb</name> <message> - <location filename="../db/abstractdb.cpp" line="306"/> - <location filename="../db/abstractdb.cpp" line="323"/> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> <source>Cannot execute query on closed database.</source> <translation>Невозможно выполнить запрос при закрытой базе данных.</translation> </message> <message> - <location filename="../db/abstractdb.cpp" line="603"/> + <location filename="../db/abstractdb.cpp" line="643"/> <source>Error attaching database %1: %2</source> <translation>Ошибка во время присоединения базы данных %1: %2</translation> </message> @@ -18,9 +18,8 @@ <context> <name>BugReporter</name> <message> - <location filename="../services/bugreporter.cpp" line="46"/> <source>Invalid login or password</source> - <translation>Неправильный логин или пароль</translation> + <translation type="vanished">Неправильный логин или пароль</translation> </message> </context> <context> @@ -146,38 +145,51 @@ </message> </context> <context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>DbManagerImpl</name> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="63"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> <source>Could not add database %1: %2</source> <translation>Не удалось добавить базу данных %1: %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="138"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> <source>Database %1 could not be updated, because of an error: %2</source> <translation>Невозможно обновить базу данных %1 из-за ошибки: %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="350"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="379"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> <source>Database file doesn't exist.</source> <translation>Файл базы данных не существует.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="352"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="381"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="604"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> <source>No supporting plugin loaded.</source> <translatorcomment>Unclear error string. Checking the source didn't help.</translatorcomment> <translation>Модуль поддержки не загружен.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="522"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> <source>Database could not be initialized.</source> <translation>Невозможно инициализировать базу данных.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="532"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> <source>No suitable database driver plugin found.</source> <translation>Не найден подходящий драйвер базы данных.</translation> </message> @@ -245,17 +257,17 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>DbVersionConverter</name> <message> - <location filename="../dbversionconverter.cpp" line="916"/> + <location filename="../dbversionconverter.cpp" line="932"/> <source>Target file exists, but could not be overwritten.</source> <translation>Целевой файл существует, но не может быть перезаписан.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="935"/> + <location filename="../dbversionconverter.cpp" line="951"/> <source>Could not find proper database plugin to create target database.</source> <translation>Невозможно найти подходящий модуль для создания целевой базы данных.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="1169"/> + <location filename="../dbversionconverter.cpp" line="1185"/> <source>Error while converting database: %1</source> <translation>Ошибка при конвертации базы данных: %1</translation> </message> @@ -458,20 +470,20 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="180"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> <source>Error while importing data: %1</source> <translation>Ошибка при импорте данных: %1</translation> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="184"/> <source>Interrupted.</source> <comment>import process status update</comment> <translation>Прервано.</translation> </message> <message> - <location filename="../importworker.cpp" line="175"/> + <location filename="../importworker.cpp" line="172"/> <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> <translation>Невозможно импортировать строку данных № %1. Строка пропущена. Подробности проблемы: %2</translation> </message> @@ -765,12 +777,12 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <translation>Невозможно начать транзакцию для заполнения таблицы. Подробности ошибки: %1</translation> </message> <message> - <location filename="../populateworker.cpp" line="63"/> + <location filename="../populateworker.cpp" line="70"/> <source>Error while populating table: %1</source> <translation>Ошибка при заполнении таблицы: %1</translation> </message> <message> - <location filename="../populateworker.cpp" line="74"/> + <location filename="../populateworker.cpp" line="81"/> <source>Could not commit transaction after table populating. Error details: %1</source> <translation>Невозможно завершить транзакцию после заполнения таблицы. Подробности ошибки: %1</translation> </message> @@ -778,71 +790,77 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>QObject</name> <message> - <location filename="../db/abstractdb2.h" line="199"/> - <location filename="../db/abstractdb3.h" line="356"/> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> <source>Could not open database: %1</source> <translation>Невозможно открыть базу данных: %1</translation> </message> <message> - <location filename="../db/abstractdb2.h" line="805"/> - <location filename="../db/abstractdb3.h" line="1100"/> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> <source>Result set expired or no row available.</source> <translation>Результирующая выборка устарела или ни одна строка не доступна.</translation> </message> <message> - <location filename="../db/abstractdb3.h" line="376"/> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> <source>Could not close database: %1</source> <translation>Невозможно закрыть базу данных: %1</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="137"/> - <location filename="../dbversionconverter.cpp" line="142"/> - <location filename="../dbversionconverter.cpp" line="195"/> - <location filename="../dbversionconverter.cpp" line="240"/> - <location filename="../dbversionconverter.cpp" line="245"/> - <location filename="../dbversionconverter.cpp" line="253"/> - <location filename="../dbversionconverter.cpp" line="331"/> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> <source>SQLite %1 does not support '%2' statement.</source> <translation>SQLite %1 не поддерживает конструкцию '%2'.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="201"/> + <location filename="../dbversionconverter.cpp" line="202"/> <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> <translation>SQLite %1 не поддерживает конструкцию '%2', однако можно создать обычную таблицу, если вы продолжите.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="424"/> + <location filename="../dbversionconverter.cpp" line="429"/> <source>Could not parse statement: %1 Error details: %2</source> <translation>Невозможно проанализировать структуру конструкции: %1 Подробности ошибки: %2</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="435"/> - <location filename="../dbversionconverter.cpp" line="461"/> - <location filename="../dbversionconverter.cpp" line="482"/> - <location filename="../dbversionconverter.cpp" line="515"/> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> <translation>SQLite %1 не поддерживает оператор '%2'. Невозможно сконвертировать конструкцию '%3' с этим оператором.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="488"/> + <location filename="../dbversionconverter.cpp" line="497"/> <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> <translation>SQLite %1 не поддерживает оператор '%2' в конструкции '%3'.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="756"/> + <location filename="../dbversionconverter.cpp" line="772"/> <source>SQLite %1 does not support current date or time clauses in expressions.</source> <translation>SQLite %1 не поддерживает операторы текущей даты и текущего времени в выражениях.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="759"/> + <location filename="../dbversionconverter.cpp" line="775"/> <source>SQLite %1 does not support row value clauses in expressions.</source> - <translation type="unfinished"></translation> + <translation>SQLite %1 не поддерживает операции со значениями строк в выражениях.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="770"/> - <location filename="../dbversionconverter.cpp" line="773"/> - <location filename="../dbversionconverter.cpp" line="784"/> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> <source>SQLite %1 does not support '%2' clause in expressions.</source> <translation>SQLite %1 не поддерживает оператор '%2' в выражениях.</translation> </message> @@ -859,13 +877,13 @@ Error details: %2</source> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="1904"/> - <location filename="../parser/sqlite3_parse.cpp" line="2169"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> <source>Parser stack overflow</source> <translation>Переполнение стека анализатора</translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="4465"/> - <location filename="../parser/sqlite3_parse.cpp" line="5088"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> <source>Syntax error</source> <translation>Синтаксическая ошибка</translation> </message> @@ -920,58 +938,58 @@ Error details: %2</source> <translation>Заполняющий код не может быть пустым.</translation> </message> <message> - <location filename="../selectresolver.cpp" line="352"/> + <location filename="../selectresolver.cpp" line="359"/> <source>Could not resolve data source for column: %1</source> <translation>Невозможно определить источник данных для столбца: %1</translation> </message> <message> - <location filename="../selectresolver.cpp" line="424"/> + <location filename="../selectresolver.cpp" line="431"/> <source>Could not resolve table for column '%1'.</source> <translation>Невозможно определить таблицу для столбца '%1'.</translation> </message> <message> - <location filename="../services/impl/configimpl.cpp" line="614"/> + <location filename="../services/impl/configimpl.cpp" line="768"/> <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> <translation>Невозможно инициализировать файл конфигурации. Любые изменения конфигурации и история запросов будут утеряны после перезапуска приложения. Попытки инициализации файла предпринимались в следующих местах: %1.</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="291"/> + <location filename="../sqlitestudio.cpp" line="305"/> <source>General purpose</source> <comment>plugin category name</comment> <translation>Общего назначения</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="292"/> + <location filename="../sqlitestudio.cpp" line="306"/> <source>Database support</source> <comment>plugin category name</comment> <translation>Поддержка баз данных</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="293"/> + <location filename="../sqlitestudio.cpp" line="307"/> <source>Code formatter</source> <comment>plugin category name</comment> <translation>Форматирование кода</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="294"/> + <location filename="../sqlitestudio.cpp" line="308"/> <source>Scripting languages</source> <comment>plugin category name</comment> <translation>Скриптовые языки</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="295"/> + <location filename="../sqlitestudio.cpp" line="309"/> <source>Exporting</source> <comment>plugin category name</comment> <translation>Экспорт</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="296"/> + <location filename="../sqlitestudio.cpp" line="310"/> <source>Importing</source> <comment>plugin category name</comment> <translation>Импорт</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="297"/> + <location filename="../sqlitestudio.cpp" line="311"/> <source>Table populating</source> <comment>plugin category name</comment> <translation>Заполнение таблиц</translation> @@ -982,34 +1000,34 @@ Error details: %2</source> <translation>Таблица %1 ссылается на таблицу %2, но описание внешнего ключа не будет обновлено для описания новой таблицы из-за проблем с анализом DDL таблицы %3.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="389"/> + <location filename="../tablemodifier.cpp" line="438"/> <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> <translation>Все столбцы, проиндексированные индексом %1, удалены. Индекс не будет воссоздан после модификации таблицы.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="428"/> + <location filename="../tablemodifier.cpp" line="481"/> <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> <translation>Возникла проблема при обработке триггера %1. Впоследствии он не будет полностью обновлён и потребует вашего внимания.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="475"/> + <location filename="../tablemodifier.cpp" line="528"/> <source>Cannot not update trigger %1 according to table %2 modification.</source> <translation>Невозможно обновить триггер %1 в соответствии с модификацией таблицы %2.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="655"/> - <location filename="../tablemodifier.cpp" line="679"/> - <location filename="../tablemodifier.cpp" line="698"/> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> <translation>Возникла проблема при обновлении конструкции %1 внутри триггера %2. Одна из вложенных конструкций %1, которая возможно ссылается на таблицу %3, не может быть корректно модифицирована. Возможно необходима ручная правка триггера.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="443"/> + <location filename="../tablemodifier.cpp" line="496"/> <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> <translation>Все столбцы, затронутые в триггере %1, удалены. Триггер не будет воссоздан после модификации таблицы.</translation> </message> <message> - <location filename="../tablemodifier.cpp" line="493"/> + <location filename="../tablemodifier.cpp" line="546"/> <source>Cannot not update view %1 according to table %2 modifications. The view will remain as it is.</source> <translation>Невозможно обновить представление %1 в соответствии с модификациями таблицы %2. @@ -1034,32 +1052,37 @@ The view will remain as it is.</source> <source>SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process.</source> <translation>SQLiteStudio не удалось определить столбцы, возвращаемые новым представлением, поэтому невозможно указать, какие триггеры могут сломаться в процессе воссоздания.</translation> </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>QueryExecutor</name> <message> - <location filename="../db/queryexecutor.cpp" line="142"/> + <location filename="../db/queryexecutor.cpp" line="186"/> <source>Execution interrupted.</source> <translation>Выполнение прервано.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="183"/> + <location filename="../db/queryexecutor.cpp" line="227"/> <source>Database is not open.</source> <translation>База данных не открыта.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="191"/> + <location filename="../db/queryexecutor.cpp" line="235"/> <source>Only one query can be executed simultaneously.</source> <translation>Одновременно может быть выполнен только один запрос.</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="294"/> - <location filename="../db/queryexecutor.cpp" line="568"/> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> <translation>Возникла ошибка при выполнении запроса count(*), поэтому разбивка данных по страницам отключена. Детали ошибки из базы данных: %1</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="479"/> + <location filename="../db/queryexecutor.cpp" line="529"/> <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> <translation>SQLiteStudio не удалось извлечь метаданные из запроса. Результаты нельзя будет редактировать.</translation> </message> @@ -1080,31 +1103,31 @@ The view will remain as it is.</source> <context> <name>SqlHistoryModel</name> <message> - <location filename="../sqlhistorymodel.cpp" line="30"/> + <location filename="../sqlhistorymodel.cpp" line="34"/> <source>Database</source> <comment>sql history header</comment> <translation>База данных</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="32"/> + <location filename="../sqlhistorymodel.cpp" line="36"/> <source>Execution date</source> <comment>sql history header</comment> <translation>Дата выполнения</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="34"/> + <location filename="../sqlhistorymodel.cpp" line="38"/> <source>Time spent</source> <comment>sql history header</comment> <translation>Затраченное время</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="36"/> + <location filename="../sqlhistorymodel.cpp" line="40"/> <source>Rows affected</source> <comment>sql history header</comment> <translation>Затронуто строк</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="38"/> + <location filename="../sqlhistorymodel.cpp" line="42"/> <source>SQL</source> <comment>sql history header</comment> <translation>SQL</translation> @@ -1113,204 +1136,183 @@ The view will remain as it is.</source> <context> <name>UpdateManager</name> <message> - <location filename="../services/updatemanager.cpp" line="131"/> <source>An error occurred while checking for updates: %1.</source> - <translation>При проверке обновлений возникла ошибка: %1</translation> + <translation type="vanished">При проверке обновлений возникла ошибка: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="144"/> <source>Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.</source> - <translation>Невозможно проверить наличие обновлений, так как ответ сервера имеет некорректный формат. Это предупреждение можно проигнорировать.</translation> + <translation type="vanished">Невозможно проверить наличие обновлений, так как ответ сервера имеет некорректный формат. Это предупреждение можно проигнорировать.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="175"/> <source>An error occurred while reading updates metadata: %1.</source> - <translation>При чтении метаданных об обновлениях возникла ошибка: %1</translation> + <translation type="vanished">При чтении метаданных об обновлениях возникла ошибка: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="188"/> <source>Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details.</source> - <translation>Невозможно загрузить обновления, так как ответ сервера имеет некорректный формат. Вы можете попробовать снова позже или скачать и установить обновления вручную. Подробности смотрите в <a href="%1">Руководстве пользователя</a>.</translation> + <translation type="vanished">Невозможно загрузить обновления, так как ответ сервера имеет некорректный формат. Вы можете попробовать снова позже или скачать и установить обновления вручную. Подробности смотрите в <a href="%1">Руководстве пользователя</a>.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="195"/> <source>Could not create temporary directory for downloading the update. Updating aborted.</source> - <translation>Невозможно создать временный каталог для загрузки обновления. Обновление прервано.</translation> + <translation type="vanished">Невозможно создать временный каталог для загрузки обновления. Обновление прервано.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="206"/> <source>There was no updates to download. Updating aborted.</source> - <translation>Нет обновлений для загрузки. Обновление прервано.</translation> + <translation type="vanished">Нет обновлений для загрузки. Обновление прервано.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="241"/> <source>Downloading: %1</source> - <translation>Загрузка: %1</translation> + <translation type="vanished">Загрузка: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="247"/> <source>Could not determinate file name from update URL: %1. Updating aborted.</source> - <translation>Невозможно определить имя файла из URL обновления. Обновление прервано.</translation> + <translation type="vanished">Невозможно определить имя файла из URL обновления. Обновление прервано.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="255"/> <source>Failed to open file '%1' for writting: %2. Updating aborted.</source> - <translation>Не удалось открыть файл %1 для записи: %2. Обновление прервано.</translation> + <translation type="vanished">Не удалось открыть файл %1 для записи: %2. Обновление прервано.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="276"/> <source>Installing updates.</source> - <translation>Установка обновлений.</translation> + <translation type="vanished">Установка обновлений.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="287"/> <source>Could not copy current application directory into %1 directory.</source> - <translation>Невозможно скопировать текущий каталог приложения в каталог %1.</translation> + <translation type="vanished">Невозможно скопировать текущий каталог приложения в каталог %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="340"/> <source>Could not create directory %1.</source> - <translation>Невозможно создать каталог %1.</translation> + <translation type="vanished">Невозможно создать каталог %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="348"/> <source>Could not rename directory %1 to %2. Details: %3</source> - <translation>Невозможно переименовать каталог %1 в %2. + <translation type="vanished">Невозможно переименовать каталог %1 в %2. Подробности: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="352"/> <source>Cannot not rename directory %1 to %2. Details: %3</source> - <translation>Невозможно переименовать каталог %1 в %2. + <translation type="vanished">Невозможно переименовать каталог %1 в %2. Подробности: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="360"/> <source>Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3</source> - <translation>Невозможно переместить каталог %1 в %2, а также не удалось восстановить оригинальный каталог, поэтому оригинальный каталог SQLiteStudio теперь расположен в: %3</translation> + <translation type="vanished">Невозможно переместить каталог %1 в %2, а также не удалось восстановить оригинальный каталог, поэтому оригинальный каталог SQLiteStudio теперь расположен в: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="365"/> <source>Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.</source> - <translation>Невозможно переименовать каталог %1 в %2. Восстановлена изначальная версия SQLiteStudio.</translation> + <translation type="vanished">Невозможно переименовать каталог %1 в %2. Восстановлена изначальная версия SQLiteStudio.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="444"/> <source>Could not unpack component %1 into %2 directory.</source> - <translation>Невозможно распаковать компонент %1 в каталог %2.</translation> + <translation type="vanished">Невозможно распаковать компонент %1 в каталог %2.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="555"/> <source>Could not find permissions elevator application to run update as a root. Looked for: %1</source> - <translation>Невозможно найти приложение повышения привилегий для запуска обновления с правами root. Были испробованы: %1</translation> + <translation type="vanished">Невозможно найти приложение повышения привилегий для запуска обновления с правами root. Были испробованы: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="562"/> <source>Could not execute final updating steps as root: %1</source> - <translation>Невозможно выполнить финальные шаги обновления с правами root: %1</translation> + <translation type="vanished">Невозможно выполнить финальные шаги обновления с правами root: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <location filename="../services/updatemanager.cpp" line="600"/> - <location filename="../services/updatemanager.cpp" line="613"/> - <location filename="../services/updatemanager.cpp" line="623"/> <source>Could not execute final updating steps as admin: %1</source> - <translation>Невозможно выполнить финальные шаги обновления с правами администратора: %1</translation> + <translation type="vanished">Невозможно выполнить финальные шаги обновления с правами администратора: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="591"/> <source>Cannot create temporary directory for updater.</source> - <translation>Невозможно создать временный каталог для установщика обновлений.</translation> + <translation type="vanished">Невозможно создать временный каталог для установщика обновлений.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="600"/> <source>Cannot create updater script file.</source> - <translation>Невозможно создать файл скрипта обновления.</translation> + <translation type="vanished">Невозможно создать файл скрипта обновления.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="633"/> <source>Updating canceled.</source> - <translation>Обновление отменено.</translation> + <translation type="vanished">Обновление отменено.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="661"/> <source>Could not execute final updating steps as administrator.</source> - <translation>Невозможно выполнить финальные шаги обновления с правами администратора.</translation> + <translation type="vanished">Невозможно выполнить финальные шаги обновления с правами администратора.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="673"/> <source>Could not execute final updating steps as administrator. Updater startup timed out.</source> - <translation>Невозможно выполнить финальные шаги обновления с правами администратора. Превышен тайм-аут запуска программы обновления.</translation> + <translation type="vanished">Невозможно выполнить финальные шаги обновления с правами администратора. Превышен тайм-аут запуска программы обновления.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="679"/> <source>Could not execute final updating steps as administrator. Updater operation timed out.</source> - <translation>Невозможно выполнить финальные шаги обновления с правами администратора. Превышен тайм-аут операции программы обновления.</translation> + <translation type="vanished">Невозможно выполнить финальные шаги обновления с правами администратора. Превышен тайм-аут операции программы обновления.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="696"/> <source>Could not clean up temporary directory %1. You can delete it manually at any time.</source> - <translation>Невозможно очистить временный каталог %1. Вы можете удалить его вручную в любое время.</translation> + <translation type="vanished">Невозможно очистить временный каталог %1. Вы можете удалить его вручную в любое время.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="732"/> <source>Could not run new version for continuing update.</source> - <translation>Невозможно запустить новую версию приложения для продолжения обновления.</translation> + <translation type="vanished">Невозможно запустить новую версию приложения для продолжения обновления.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="817"/> <source>Package not in tar.gz format, cannot install: %1</source> - <translation>Пакет не в формате tar.gz, установка невозможна: %1</translation> + <translation type="vanished">Пакет не в формате tar.gz, установка невозможна: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="824"/> <source>Package %1 cannot be installed, because cannot move it to directory: %2</source> - <translation>Пакет %1 не может быть установлен, так как невозможно перенести его в каталог: %2</translation> + <translation type="vanished">Пакет %1 не может быть установлен, так как невозможно перенести его в каталог: %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="833"/> <source>Package %1 cannot be installed, because cannot unpack it: %2</source> - <translation>Пакет %1 не может быть установлен, так как его невозможно распаковать: %2</translation> + <translation type="vanished">Пакет %1 не может быть установлен, так как его невозможно распаковать: %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="852"/> <source>Package not in zip format, cannot install: %1</source> - <translation>Пакет не в формате zip, установка невозможна: %1</translation> + <translation type="vanished">Пакет не в формате zip, установка невозможна: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="859"/> <source>Package %1 cannot be installed, because cannot unzip it to directory %2: %3</source> - <translation>Пакет %1 не может быть установлен, так как его невозможно распаковать в каталог %2: %3</translation> + <translation type="vanished">Пакет %1 не может быть установлен, так как его невозможно распаковать в каталог %2: %3</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="873"/> <source>Package %1 cannot be installed, because cannot unzip it to directory: %2</source> - <translation>Пакет %1 не может быть установлен, так как его невозможно распаковать в каталог: %2</translation> + <translation type="vanished">Пакет %1 не может быть установлен, так как его невозможно распаковать в каталог: %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="923"/> - <location filename="../services/updatemanager.cpp" line="932"/> <source>Could not rename directory %1 to %2.</source> - <translation>Невозможно переименовать каталог %1 в %2.</translation> + <translation type="vanished">Невозможно переименовать каталог %1 в %2.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="945"/> <source>Could not delete directory %1.</source> - <translation>Невозможно удалить каталог %1.</translation> + <translation type="vanished">Невозможно удалить каталог %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="961"/> <source>Error executing update command: %1 Error message: %2</source> - <translation>Ошибка при выполнении команды обновления: %1 + <translation type="vanished">Ошибка при выполнении команды обновления: %1 Сообщение об ошибке: %2</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="1028"/> <source>An error occurred while downloading updates: %1. Updating aborted.</source> - <translation>При загрузке обновлений произошла ошибка: %1. Обновление прервано.</translation> + <translation type="vanished">При загрузке обновлений произошла ошибка: %1. Обновление прервано.</translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> + <translation type="unfinished"></translation> </message> </context> </TS> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.qm Binary files differindex eb79951..de604e9 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.qm +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.qm diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.ts index 3298d89..8db8efb 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.ts @@ -4,13 +4,13 @@ <context> <name>AbstractDb</name> <message> - <location filename="../db/abstractdb.cpp" line="306"/> - <location filename="../db/abstractdb.cpp" line="323"/> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> <source>Cannot execute query on closed database.</source> <translation>Nemôžem spustiť dotaz na uzatvorenej databáze.</translation> </message> <message> - <location filename="../db/abstractdb.cpp" line="603"/> + <location filename="../db/abstractdb.cpp" line="643"/> <source>Error attaching database %1: %2</source> <translation>Chyba pri pripájaní databázy %1: %2</translation> </message> @@ -18,9 +18,8 @@ <context> <name>BugReporter</name> <message> - <location filename="../services/bugreporter.cpp" line="46"/> <source>Invalid login or password</source> - <translation>Neplatné meno alebo heslo</translation> + <translation type="vanished">Neplatné meno alebo heslo</translation> </message> </context> <context> @@ -146,37 +145,50 @@ </message> </context> <context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>DbManagerImpl</name> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="63"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> <source>Could not add database %1: %2</source> <translation>Nemôžem pridať databázu %1: %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="138"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> <source>Database %1 could not be updated, because of an error: %2</source> <translation>Databáza %1 nemôže byť aktualizovaná kvôli chybe: %2</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="350"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="379"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> <source>Database file doesn't exist.</source> <translation>Databázový súbor neexistuje.</translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="352"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="381"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="604"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> <source>No supporting plugin loaded.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="522"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> <source>Database could not be initialized.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="532"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> <source>No suitable database driver plugin found.</source> <translation type="unfinished"></translation> </message> @@ -243,17 +255,17 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>DbVersionConverter</name> <message> - <location filename="../dbversionconverter.cpp" line="916"/> + <location filename="../dbversionconverter.cpp" line="932"/> <source>Target file exists, but could not be overwritten.</source> <translation>Cieľový súbor existuje ale nemôže byť prepísaný.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="935"/> + <location filename="../dbversionconverter.cpp" line="951"/> <source>Could not find proper database plugin to create target database.</source> <translation>Nieje možné nájsť správny databázový plugin pre vytvorenie cieľovej databázy.</translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="1169"/> + <location filename="../dbversionconverter.cpp" line="1185"/> <source>Error while converting database: %1</source> <translation>Vyskytla sa chyba počas konvertovania databázy: %1</translation> </message> @@ -456,20 +468,20 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="180"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> <source>Error while importing data: %1</source> <translation>Vyskytla sa chyba počas importu dát: %1</translation> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="184"/> <source>Interrupted.</source> <comment>import process status update</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../importworker.cpp" line="175"/> + <location filename="../importworker.cpp" line="172"/> <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> <translation type="unfinished"></translation> </message> @@ -763,12 +775,12 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../populateworker.cpp" line="63"/> + <location filename="../populateworker.cpp" line="70"/> <source>Error while populating table: %1</source> <translation>Vyskytla sa chyba počas napĺňania tabuľky: %1</translation> </message> <message> - <location filename="../populateworker.cpp" line="74"/> + <location filename="../populateworker.cpp" line="81"/> <source>Could not commit transaction after table populating. Error details: %1</source> <translation type="unfinished"></translation> </message> @@ -776,71 +788,77 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>QObject</name> <message> - <location filename="../db/abstractdb2.h" line="199"/> - <location filename="../db/abstractdb3.h" line="356"/> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> <source>Could not open database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb2.h" line="805"/> - <location filename="../db/abstractdb3.h" line="1100"/> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> <source>Result set expired or no row available.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb3.h" line="376"/> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> <source>Could not close database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="137"/> - <location filename="../dbversionconverter.cpp" line="142"/> - <location filename="../dbversionconverter.cpp" line="195"/> - <location filename="../dbversionconverter.cpp" line="240"/> - <location filename="../dbversionconverter.cpp" line="245"/> - <location filename="../dbversionconverter.cpp" line="253"/> - <location filename="../dbversionconverter.cpp" line="331"/> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> <source>SQLite %1 does not support '%2' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="201"/> + <location filename="../dbversionconverter.cpp" line="202"/> <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="424"/> + <location filename="../dbversionconverter.cpp" line="429"/> <source>Could not parse statement: %1 Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="435"/> - <location filename="../dbversionconverter.cpp" line="461"/> - <location filename="../dbversionconverter.cpp" line="482"/> - <location filename="../dbversionconverter.cpp" line="515"/> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="488"/> + <location filename="../dbversionconverter.cpp" line="497"/> <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="756"/> + <location filename="../dbversionconverter.cpp" line="772"/> <source>SQLite %1 does not support current date or time clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="759"/> + <location filename="../dbversionconverter.cpp" line="775"/> <source>SQLite %1 does not support row value clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="770"/> - <location filename="../dbversionconverter.cpp" line="773"/> - <location filename="../dbversionconverter.cpp" line="784"/> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> <source>SQLite %1 does not support '%2' clause in expressions.</source> <translation type="unfinished"></translation> </message> @@ -857,13 +875,13 @@ Error details: %2</source> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="1904"/> - <location filename="../parser/sqlite3_parse.cpp" line="2169"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> <source>Parser stack overflow</source> <translation type="unfinished"></translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="4465"/> - <location filename="../parser/sqlite3_parse.cpp" line="5088"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> <source>Syntax error</source> <translation>Chyba syntaxe</translation> </message> @@ -918,58 +936,58 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="352"/> + <location filename="../selectresolver.cpp" line="359"/> <source>Could not resolve data source for column: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="424"/> + <location filename="../selectresolver.cpp" line="431"/> <source>Could not resolve table for column '%1'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/configimpl.cpp" line="614"/> + <location filename="../services/impl/configimpl.cpp" line="768"/> <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="291"/> + <location filename="../sqlitestudio.cpp" line="305"/> <source>General purpose</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="292"/> + <location filename="../sqlitestudio.cpp" line="306"/> <source>Database support</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="293"/> + <location filename="../sqlitestudio.cpp" line="307"/> <source>Code formatter</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="294"/> + <location filename="../sqlitestudio.cpp" line="308"/> <source>Scripting languages</source> <comment>plugin category name</comment> <translation>Skriptovacie jazyky</translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="295"/> + <location filename="../sqlitestudio.cpp" line="309"/> <source>Exporting</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="296"/> + <location filename="../sqlitestudio.cpp" line="310"/> <source>Importing</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="297"/> + <location filename="../sqlitestudio.cpp" line="311"/> <source>Table populating</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> @@ -980,34 +998,34 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="389"/> + <location filename="../tablemodifier.cpp" line="438"/> <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="428"/> + <location filename="../tablemodifier.cpp" line="481"/> <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="475"/> + <location filename="../tablemodifier.cpp" line="528"/> <source>Cannot not update trigger %1 according to table %2 modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="655"/> - <location filename="../tablemodifier.cpp" line="679"/> - <location filename="../tablemodifier.cpp" line="698"/> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="443"/> + <location filename="../tablemodifier.cpp" line="496"/> <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="493"/> + <location filename="../tablemodifier.cpp" line="546"/> <source>Cannot not update view %1 according to table %2 modifications. The view will remain as it is.</source> <translation type="unfinished"></translation> @@ -1027,32 +1045,37 @@ The view will remain as it is.</source> <source>SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process.</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>QueryExecutor</name> <message> - <location filename="../db/queryexecutor.cpp" line="142"/> + <location filename="../db/queryexecutor.cpp" line="186"/> <source>Execution interrupted.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="183"/> + <location filename="../db/queryexecutor.cpp" line="227"/> <source>Database is not open.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="191"/> + <location filename="../db/queryexecutor.cpp" line="235"/> <source>Only one query can be executed simultaneously.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="294"/> - <location filename="../db/queryexecutor.cpp" line="568"/> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> <translation>Vyskytla sa chyba počas vykonávania dotazu count(*), dôsledkom čoho bolo zablokované stránkovanie. Detail chyby: %1</translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="479"/> + <location filename="../db/queryexecutor.cpp" line="529"/> <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> <translation type="unfinished"></translation> </message> @@ -1073,32 +1096,32 @@ The view will remain as it is.</source> <context> <name>SqlHistoryModel</name> <message> - <location filename="../sqlhistorymodel.cpp" line="30"/> + <location filename="../sqlhistorymodel.cpp" line="34"/> <source>Database</source> <comment>sql history header</comment> <translatorcomment>Dátum spustenia</translatorcomment> <translation>Databáza</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="32"/> + <location filename="../sqlhistorymodel.cpp" line="36"/> <source>Execution date</source> <comment>sql history header</comment> <translation>Dátum spustenia</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="34"/> + <location filename="../sqlhistorymodel.cpp" line="38"/> <source>Time spent</source> <comment>sql history header</comment> <translation>Trvanie dotazu</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="36"/> + <location filename="../sqlhistorymodel.cpp" line="40"/> <source>Rows affected</source> <comment>sql history header</comment> <translation>Počet riadkov</translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="38"/> + <location filename="../sqlhistorymodel.cpp" line="42"/> <source>SQL</source> <comment>sql history header</comment> <translation>SQL</translation> @@ -1107,201 +1130,49 @@ The view will remain as it is.</source> <context> <name>UpdateManager</name> <message> - <location filename="../services/updatemanager.cpp" line="131"/> <source>An error occurred while checking for updates: %1.</source> - <translation>Vyskytla sa chyba počas kontroly aktualizácii: %1.</translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="144"/> - <source>Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.</source> - <translation type="unfinished"></translation> + <translation type="vanished">Vyskytla sa chyba počas kontroly aktualizácii: %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="175"/> - <source>An error occurred while reading updates metadata: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="188"/> - <source>Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="195"/> - <source>Could not create temporary directory for downloading the update. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="206"/> - <source>There was no updates to download. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="241"/> <source>Downloading: %1</source> - <translation>Sťahujem: %1</translation> + <translation type="vanished">Sťahujem: %1</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="247"/> - <source>Could not determinate file name from update URL: %1. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="255"/> - <source>Failed to open file '%1' for writting: %2. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="276"/> <source>Installing updates.</source> - <translation>Inštalujem aktualizácie.</translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="287"/> - <source>Could not copy current application directory into %1 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="340"/> - <source>Could not create directory %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="348"/> - <source>Could not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="352"/> - <source>Cannot not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="360"/> - <source>Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="365"/> - <source>Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="444"/> - <source>Could not unpack component %1 into %2 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="555"/> - <source>Could not find permissions elevator application to run update as a root. Looked for: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="562"/> - <source>Could not execute final updating steps as root: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <location filename="../services/updatemanager.cpp" line="600"/> - <location filename="../services/updatemanager.cpp" line="613"/> - <location filename="../services/updatemanager.cpp" line="623"/> - <source>Could not execute final updating steps as admin: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <source>Cannot create temporary directory for updater.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="600"/> - <source>Cannot create updater script file.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="633"/> - <source>Updating canceled.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="661"/> - <source>Could not execute final updating steps as administrator.</source> - <translation type="unfinished"></translation> + <translation type="vanished">Inštalujem aktualizácie.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="673"/> - <source>Could not execute final updating steps as administrator. Updater startup timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="679"/> - <source>Could not execute final updating steps as administrator. Updater operation timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="696"/> - <source>Could not clean up temporary directory %1. You can delete it manually at any time.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="732"/> - <source>Could not run new version for continuing update.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="817"/> - <source>Package not in tar.gz format, cannot install: %1</source> - <translation type="unfinished"></translation> + <source>Could not rename directory %1 to %2.</source> + <translation type="vanished">Nemôžem premenovať adresár %1na %2.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="824"/> - <source>Package %1 cannot be installed, because cannot move it to directory: %2</source> - <translation type="unfinished"></translation> + <source>Could not delete directory %1.</source> + <translation type="vanished">Nemôžem vymazať adresár %1.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="833"/> - <source>Package %1 cannot be installed, because cannot unpack it: %2</source> - <translation type="unfinished"></translation> + <source>An error occurred while downloading updates: %1. Updating aborted.</source> + <translation type="vanished">Vyskytla sa chyba počas sťahovani aktualizácií:%1. Aktualizácia zrušená.</translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="852"/> - <source>Package not in zip format, cannot install: %1</source> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="859"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory %2: %3</source> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="873"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory: %2</source> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="923"/> - <location filename="../services/updatemanager.cpp" line="932"/> - <source>Could not rename directory %1 to %2.</source> - <translation>Nemôžem premenovať adresár %1na %2.</translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="945"/> - <source>Could not delete directory %1.</source> - <translation>Nemôžem vymazať adresár %1.</translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="961"/> - <source>Error executing update command: %1 -Error message: %2</source> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> <translation type="unfinished"></translation> </message> - <message> - <location filename="../services/updatemanager.cpp" line="1028"/> - <source>An error occurred while downloading updates: %1. Updating aborted.</source> - <translation>Vyskytla sa chyba počas sťahovani aktualizácií:%1. Aktualizácia zrušená.</translation> - </message> </context> </TS> diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.qm Binary files differindex 3c6eeb3..be651ee 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.qm +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.qm diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.ts index b9c43f2..2d84208 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.ts @@ -4,13 +4,13 @@ <context> <name>AbstractDb</name> <message> - <location filename="../db/abstractdb.cpp" line="306"/> - <location filename="../db/abstractdb.cpp" line="323"/> + <location filename="../db/abstractdb.cpp" line="343"/> + <location filename="../db/abstractdb.cpp" line="360"/> <source>Cannot execute query on closed database.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb.cpp" line="603"/> + <location filename="../db/abstractdb.cpp" line="643"/> <source>Error attaching database %1: %2</source> <translation type="unfinished"></translation> </message> @@ -18,9 +18,8 @@ <context> <name>BugReporter</name> <message> - <location filename="../services/bugreporter.cpp" line="46"/> <source>Invalid login or password</source> - <translation>用户名或密码错误</translation> + <translation type="vanished">用户名或密码错误</translation> </message> </context> <context> @@ -146,37 +145,50 @@ </message> </context> <context> + <name>ConfigImpl</name> + <message> + <location filename="../services/impl/configimpl.cpp" line="863"/> + <source>Could not start database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../services/impl/configimpl.cpp" line="870"/> + <source>Could not commit database transaction for deleting SQL history, therefore it's not deleted.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>DbManagerImpl</name> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="63"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="64"/> <source>Could not add database %1: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="138"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="139"/> <source>Database %1 could not be updated, because of an error: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="350"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="379"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="355"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="384"/> <source>Database file doesn't exist.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="352"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="381"/> - <location filename="../services/impl/dbmanagerimpl.cpp" line="604"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="357"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="386"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="609"/> <source>No supporting plugin loaded.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="522"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="527"/> <source>Database could not be initialized.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/dbmanagerimpl.cpp" line="532"/> + <location filename="../services/impl/dbmanagerimpl.cpp" line="537"/> <source>No suitable database driver plugin found.</source> <translation type="unfinished"></translation> </message> @@ -243,17 +255,17 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>DbVersionConverter</name> <message> - <location filename="../dbversionconverter.cpp" line="916"/> + <location filename="../dbversionconverter.cpp" line="932"/> <source>Target file exists, but could not be overwritten.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="935"/> + <location filename="../dbversionconverter.cpp" line="951"/> <source>Could not find proper database plugin to create target database.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="1169"/> + <location filename="../dbversionconverter.cpp" line="1185"/> <source>Error while converting database: %1</source> <translation type="unfinished"></translation> </message> @@ -456,20 +468,20 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="180"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="177"/> + <location filename="../importworker.cpp" line="184"/> <source>Error while importing data: %1</source> <translation type="unfinished"></translation> </message> <message> <location filename="../importworker.cpp" line="133"/> - <location filename="../importworker.cpp" line="187"/> + <location filename="../importworker.cpp" line="184"/> <source>Interrupted.</source> <comment>import process status update</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../importworker.cpp" line="175"/> + <location filename="../importworker.cpp" line="172"/> <source>Could not import data row number %1. The row was ignored. Problem details: %2</source> <translation type="unfinished"></translation> </message> @@ -763,12 +775,12 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../populateworker.cpp" line="63"/> + <location filename="../populateworker.cpp" line="70"/> <source>Error while populating table: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../populateworker.cpp" line="74"/> + <location filename="../populateworker.cpp" line="81"/> <source>Could not commit transaction after table populating. Error details: %1</source> <translation type="unfinished"></translation> </message> @@ -776,71 +788,77 @@ Tables, indexes, triggers and views copied to database %3 will remain.</source> <context> <name>QObject</name> <message> - <location filename="../db/abstractdb2.h" line="199"/> - <location filename="../db/abstractdb3.h" line="356"/> + <location filename="../db/abstractdb2.h" line="222"/> + <location filename="../db/abstractdb3.h" line="384"/> <source>Could not open database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb2.h" line="805"/> - <location filename="../db/abstractdb3.h" line="1100"/> + <location filename="../db/abstractdb2.h" line="833"/> + <location filename="../db/abstractdb3.h" line="1132"/> <source>Result set expired or no row available.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/abstractdb3.h" line="376"/> + <location filename="../db/abstractdb3.h" line="328"/> + <location filename="../db/abstractdb3.h" line="332"/> + <source>Could not load extension %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../db/abstractdb3.h" line="405"/> <source>Could not close database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="137"/> - <location filename="../dbversionconverter.cpp" line="142"/> - <location filename="../dbversionconverter.cpp" line="195"/> - <location filename="../dbversionconverter.cpp" line="240"/> - <location filename="../dbversionconverter.cpp" line="245"/> - <location filename="../dbversionconverter.cpp" line="253"/> - <location filename="../dbversionconverter.cpp" line="331"/> + <location filename="../dbversionconverter.cpp" line="138"/> + <location filename="../dbversionconverter.cpp" line="143"/> + <location filename="../dbversionconverter.cpp" line="196"/> + <location filename="../dbversionconverter.cpp" line="243"/> + <location filename="../dbversionconverter.cpp" line="248"/> + <location filename="../dbversionconverter.cpp" line="256"/> + <location filename="../dbversionconverter.cpp" line="336"/> <source>SQLite %1 does not support '%2' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="201"/> + <location filename="../dbversionconverter.cpp" line="202"/> <source>SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="424"/> + <location filename="../dbversionconverter.cpp" line="429"/> <source>Could not parse statement: %1 Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="435"/> - <location filename="../dbversionconverter.cpp" line="461"/> - <location filename="../dbversionconverter.cpp" line="482"/> - <location filename="../dbversionconverter.cpp" line="515"/> + <location filename="../dbversionconverter.cpp" line="440"/> + <location filename="../dbversionconverter.cpp" line="468"/> + <location filename="../dbversionconverter.cpp" line="491"/> + <location filename="../dbversionconverter.cpp" line="529"/> <source>SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="488"/> + <location filename="../dbversionconverter.cpp" line="497"/> <source>SQLite %1 does not support the '%2' clause in the '%3' statement.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="756"/> + <location filename="../dbversionconverter.cpp" line="772"/> <source>SQLite %1 does not support current date or time clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="759"/> + <location filename="../dbversionconverter.cpp" line="775"/> <source>SQLite %1 does not support row value clauses in expressions.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dbversionconverter.cpp" line="770"/> - <location filename="../dbversionconverter.cpp" line="773"/> - <location filename="../dbversionconverter.cpp" line="784"/> + <location filename="../dbversionconverter.cpp" line="786"/> + <location filename="../dbversionconverter.cpp" line="789"/> + <location filename="../dbversionconverter.cpp" line="800"/> <source>SQLite %1 does not support '%2' clause in expressions.</source> <translation type="unfinished"></translation> </message> @@ -857,13 +875,13 @@ Error details: %2</source> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="1904"/> - <location filename="../parser/sqlite3_parse.cpp" line="2169"/> + <location filename="../parser/sqlite3_parse.cpp" line="2212"/> <source>Parser stack overflow</source> <translation type="unfinished"></translation> </message> <message> <location filename="../parser/sqlite2_parse.cpp" line="4465"/> - <location filename="../parser/sqlite3_parse.cpp" line="5088"/> + <location filename="../parser/sqlite3_parse.cpp" line="5195"/> <source>Syntax error</source> <translation type="unfinished"></translation> </message> @@ -918,58 +936,58 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="352"/> + <location filename="../selectresolver.cpp" line="359"/> <source>Could not resolve data source for column: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../selectresolver.cpp" line="424"/> + <location filename="../selectresolver.cpp" line="431"/> <source>Could not resolve table for column '%1'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/impl/configimpl.cpp" line="614"/> + <location filename="../services/impl/configimpl.cpp" line="768"/> <source>Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="291"/> + <location filename="../sqlitestudio.cpp" line="305"/> <source>General purpose</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="292"/> + <location filename="../sqlitestudio.cpp" line="306"/> <source>Database support</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="293"/> + <location filename="../sqlitestudio.cpp" line="307"/> <source>Code formatter</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="294"/> + <location filename="../sqlitestudio.cpp" line="308"/> <source>Scripting languages</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="295"/> + <location filename="../sqlitestudio.cpp" line="309"/> <source>Exporting</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="296"/> + <location filename="../sqlitestudio.cpp" line="310"/> <source>Importing</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlitestudio.cpp" line="297"/> + <location filename="../sqlitestudio.cpp" line="311"/> <source>Table populating</source> <comment>plugin category name</comment> <translation type="unfinished"></translation> @@ -980,34 +998,34 @@ Error details: %2</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="389"/> + <location filename="../tablemodifier.cpp" line="438"/> <source>All columns indexed by the index %1 are gone. The index will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="428"/> + <location filename="../tablemodifier.cpp" line="481"/> <source>There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="475"/> + <location filename="../tablemodifier.cpp" line="528"/> <source>Cannot not update trigger %1 according to table %2 modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="655"/> - <location filename="../tablemodifier.cpp" line="679"/> - <location filename="../tablemodifier.cpp" line="698"/> + <location filename="../tablemodifier.cpp" line="708"/> + <location filename="../tablemodifier.cpp" line="732"/> + <location filename="../tablemodifier.cpp" line="751"/> <source>There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="443"/> + <location filename="../tablemodifier.cpp" line="496"/> <source>All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../tablemodifier.cpp" line="493"/> + <location filename="../tablemodifier.cpp" line="546"/> <source>Cannot not update view %1 according to table %2 modifications. The view will remain as it is.</source> <translation type="unfinished"></translation> @@ -1027,32 +1045,37 @@ The view will remain as it is.</source> <source>SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process.</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../common/utils.cpp" line="1022"/> + <source>Could not open file '%1' for reading: %2</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>QueryExecutor</name> <message> - <location filename="../db/queryexecutor.cpp" line="142"/> + <location filename="../db/queryexecutor.cpp" line="186"/> <source>Execution interrupted.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="183"/> + <location filename="../db/queryexecutor.cpp" line="227"/> <source>Database is not open.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="191"/> + <location filename="../db/queryexecutor.cpp" line="235"/> <source>Only one query can be executed simultaneously.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="294"/> - <location filename="../db/queryexecutor.cpp" line="568"/> + <location filename="../db/queryexecutor.cpp" line="339"/> + <location filename="../db/queryexecutor.cpp" line="618"/> <source>An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../db/queryexecutor.cpp" line="479"/> + <location filename="../db/queryexecutor.cpp" line="529"/> <source>SQLiteStudio was unable to extract metadata from the query. Results won't be editable.</source> <translation type="unfinished"></translation> </message> @@ -1073,31 +1096,31 @@ The view will remain as it is.</source> <context> <name>SqlHistoryModel</name> <message> - <location filename="../sqlhistorymodel.cpp" line="30"/> + <location filename="../sqlhistorymodel.cpp" line="34"/> <source>Database</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="32"/> + <location filename="../sqlhistorymodel.cpp" line="36"/> <source>Execution date</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="34"/> + <location filename="../sqlhistorymodel.cpp" line="38"/> <source>Time spent</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="36"/> + <location filename="../sqlhistorymodel.cpp" line="40"/> <source>Rows affected</source> <comment>sql history header</comment> <translation type="unfinished"></translation> </message> <message> - <location filename="../sqlhistorymodel.cpp" line="38"/> + <location filename="../sqlhistorymodel.cpp" line="42"/> <source>SQL</source> <comment>sql history header</comment> <translation type="unfinished"></translation> @@ -1106,200 +1129,24 @@ The view will remain as it is.</source> <context> <name>UpdateManager</name> <message> - <location filename="../services/updatemanager.cpp" line="131"/> - <source>An error occurred while checking for updates: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="144"/> - <source>Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="175"/> - <source>An error occurred while reading updates metadata: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="188"/> - <source>Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="195"/> - <source>Could not create temporary directory for downloading the update. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="206"/> - <source>There was no updates to download. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="241"/> - <source>Downloading: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="247"/> - <source>Could not determinate file name from update URL: %1. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="255"/> - <source>Failed to open file '%1' for writting: %2. Updating aborted.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="276"/> - <source>Installing updates.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="287"/> - <source>Could not copy current application directory into %1 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="340"/> - <source>Could not create directory %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="348"/> - <source>Could not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="352"/> - <source>Cannot not rename directory %1 to %2. -Details: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="360"/> - <source>Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="365"/> - <source>Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="444"/> - <source>Could not unpack component %1 into %2 directory.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="555"/> - <source>Could not find permissions elevator application to run update as a root. Looked for: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="562"/> - <source>Could not execute final updating steps as root: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <location filename="../services/updatemanager.cpp" line="600"/> - <location filename="../services/updatemanager.cpp" line="613"/> - <location filename="../services/updatemanager.cpp" line="623"/> - <source>Could not execute final updating steps as admin: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="591"/> - <source>Cannot create temporary directory for updater.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="600"/> - <source>Cannot create updater script file.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="633"/> - <source>Updating canceled.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="661"/> - <source>Could not execute final updating steps as administrator.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="673"/> - <source>Could not execute final updating steps as administrator. Updater startup timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="679"/> - <source>Could not execute final updating steps as administrator. Updater operation timed out.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="696"/> - <source>Could not clean up temporary directory %1. You can delete it manually at any time.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="732"/> - <source>Could not run new version for continuing update.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="817"/> - <source>Package not in tar.gz format, cannot install: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="824"/> - <source>Package %1 cannot be installed, because cannot move it to directory: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="833"/> - <source>Package %1 cannot be installed, because cannot unpack it: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="852"/> - <source>Package not in zip format, cannot install: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="859"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory %2: %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="873"/> - <source>Package %1 cannot be installed, because cannot unzip it to directory: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../services/updatemanager.cpp" line="923"/> - <location filename="../services/updatemanager.cpp" line="932"/> - <source>Could not rename directory %1 to %2.</source> + <location filename="../services/updatemanager.cpp" line="48"/> + <source>Updates installer executable is missing.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="945"/> - <source>Could not delete directory %1.</source> + <location filename="../services/updatemanager.cpp" line="49"/> + <location filename="../services/updatemanager.cpp" line="68"/> + <source>Unable to check for updates (%1)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="961"/> - <source>Error executing update command: %1 -Error message: %2</source> + <location filename="../services/updatemanager.cpp" line="66"/> + <source>details are unknown</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../services/updatemanager.cpp" line="1028"/> - <source>An error occurred while downloading updates: %1. Updating aborted.</source> + <location filename="../services/updatemanager.cpp" line="81"/> + <source>Unable to run updater application (%1). Please report this.</source> <translation type="unfinished"></translation> </message> </context> diff --git a/SQLiteStudio3/coreSQLiteStudio/tsvserializer.cpp b/SQLiteStudio3/coreSQLiteStudio/tsvserializer.cpp index a42c76d..62f6201 100644 --- a/SQLiteStudio3/coreSQLiteStudio/tsvserializer.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/tsvserializer.cpp @@ -11,7 +11,7 @@ QString TsvSerializer::serialize(const QList<QStringList>& data) { QStringList outputRows; - foreach (const QStringList& dataRow, data) + for (const QStringList& dataRow : data) outputRows << serialize(dataRow); return outputRows.join(rowSeparator); @@ -22,7 +22,7 @@ QString TsvSerializer::serialize(const QStringList& data) QString value; bool hasQuote; QStringList outputCells; - foreach (const QString& rowValue, data) + for (const QString& rowValue : data) { value = rowValue; diff --git a/SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp b/SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp index 36ab457..1c03770 100644 --- a/SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp @@ -55,7 +55,7 @@ void ViewModifier::handleTriggers() { SchemaResolver resolver(db); QList<SqliteCreateTriggerPtr> triggers = resolver.getParsedTriggersForView(view, true); - foreach (SqliteCreateTriggerPtr trigger, triggers) + for (SqliteCreateTriggerPtr trigger : triggers) { addOptionalSql(QString("DROP TRIGGER %1").arg(wrapObjIfNeeded(trigger->trigger, dialect))); @@ -84,7 +84,7 @@ void ViewModifier::collectNewColumns() return; } - foreach (const SelectResolver::Column& col, multiColumns.first()) + for (const SelectResolver::Column& col : multiColumns.first()) newColumns << col.column; } |
