diff options
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/common')
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp | 25 | ||||
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h | 21 | ||||
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/common/compatibility.cpp | 7 | ||||
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/common/compatibility.h | 3 | ||||
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/common/global.h | 19 | ||||
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/common/utils.cpp | 39 | ||||
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/common/utils.h | 37 | ||||
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp | 94 | ||||
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/common/utils_sql.h | 2 |
9 files changed, 233 insertions, 14 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp index 5aac017..f2c1b2c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp @@ -17,6 +17,15 @@ BiStrHash::BiStrHash(const BiStrHash& other) : hash(other.hash), inverted(other. { } +BiStrHash& BiStrHash::operator=(const BiStrHash& other) +{ + this->hash = other.hash; + this->inverted = other.inverted; + this->lowerHash = other.lowerHash; + this->lowerInverted = other.lowerInverted; + return *this; +} + void BiStrHash::insert(const QString& left, const QString& right) { if (lowerHash.contains(left.toLower())) @@ -163,6 +172,14 @@ QString BiStrHash::valueByLeft(const QString& left, Qt::CaseSensitivity cs) cons return hash.value(lowerHash.value(left.toLower())); } +QString BiStrHash::valueByLeft(const QString& left, const QString& defaultValue, Qt::CaseSensitivity cs) const +{ + if (containsLeft(left, cs)) + return valueByLeft(left, cs); + + return defaultValue; +} + QString BiStrHash::valueByRight(const QString& right, Qt::CaseSensitivity cs) const { if (cs == Qt::CaseSensitive) @@ -171,6 +188,14 @@ QString BiStrHash::valueByRight(const QString& right, Qt::CaseSensitivity cs) co return inverted.value(lowerInverted.value(right.toLower())); } +QString BiStrHash::valueByRight(const QString& right, const QString& defaultValue, Qt::CaseSensitivity cs) const +{ + if (containsRight(right, cs)) + return valueByRight(right, cs); + + return defaultValue; +} + QStringList BiStrHash::leftValues() const { return hash.keys(); diff --git a/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h index cec9b8a..0ad80ea 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h @@ -1,7 +1,6 @@ #ifndef BISTRHASH_H
#define BISTRHASH_H
-#include "bihash.h"
#include "coreSQLiteStudio_global.h"
#include <QHash>
#include <QString>
@@ -44,6 +43,8 @@ class API_EXPORT BiStrHash */
BiStrHash(const BiStrHash& other);
+ BiStrHash& operator=(const BiStrHash& other);
+
/**
* @brief Inserts entry into the hash.
* @param left Left-side value to insert.
@@ -123,6 +124,15 @@ class API_EXPORT BiStrHash QString valueByLeft(const QString& left, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
/**
+ * @brief Finds right-side value by matching the left-side value or returns defaultValue if not matched.
+ * @param left Left-side value to match.
+ * @param defaultValue Value to be returned if requested left key cannot be found.
+ * @param cs Case sensitivity flag.
+ * @return Right-side value, or provided default value if left-side value was not matched.
+ */
+ QString valueByLeft(const QString& left, const QString& defaultValue, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+
+ /**
* @brief Finds left-side value by matching the right-side value.
* @param right Right-side value to match.
* @param cs Case sensitivity flag.
@@ -131,6 +141,15 @@ class API_EXPORT BiStrHash QString valueByRight(const QString& right, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
/**
+ * @brief Finds left-side value by matching the right-side value or returns defaultValue if not matched.
+ * @param right Right-side value to match.
+ * @param defaultValue Value to be returned if requested right key cannot be found.
+ * @param cs Case sensitivity flag.
+ * @return Left-side value, or provided default value if right-side value was not matched.
+ */
+ QString valueByRight(const QString& right, const QString& defaultValue, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+
+ /**
* @brief Gives all left-side values.
* @return List of values.
*/
diff --git a/SQLiteStudio3/coreSQLiteStudio/common/compatibility.cpp b/SQLiteStudio3/coreSQLiteStudio/common/compatibility.cpp index 9676105..c5918c4 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/compatibility.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/compatibility.cpp @@ -1,2 +1,9 @@ #include "compatibility.h" +void strSort(QStringList& collection, Qt::CaseSensitivity cs) +{ + std::stable_sort(collection.begin(), collection.end(), [cs](const QString& v1, const QString& v2) -> bool + { + return v1.compare(v2, cs) < 0; + }); +} diff --git a/SQLiteStudio3/coreSQLiteStudio/common/compatibility.h b/SQLiteStudio3/coreSQLiteStudio/common/compatibility.h index 5ed5c8b..97637b0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/compatibility.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/compatibility.h @@ -1,6 +1,7 @@ #ifndef COMPATIBILITY_H #define COMPATIBILITY_H +#include "coreSQLiteStudio_global.h" #include <QList> #include <QSet> #include <QHash> @@ -37,4 +38,6 @@ void sSort(T& collection, C cmp) std::sort(collection.begin(), collection.end(), cmp); } +API_EXPORT void strSort(QStringList& collection, Qt::CaseSensitivity cs); + #endif // COMPATIBILITY_H diff --git a/SQLiteStudio3/coreSQLiteStudio/common/global.h b/SQLiteStudio3/coreSQLiteStudio/common/global.h index e09391a..c056abb 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/global.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/global.h @@ -39,9 +39,7 @@ var = nullptr; \ } -#define parser_safe_delete(var) \ - if (var) \ - delete var +#define parser_safe_delete(var) delete var #define static_char static constexpr const char @@ -74,4 +72,19 @@ #define STRINGIFY(s) _STRINGIFY(s) #define _STRINGIFY(s) #s +#define __SQLS_INIT_RESOURCE(proj, name) Q_INIT_RESOURCE(proj ## _ ## name) +#define __SQLS_CLEANUP_RESOURCE(proj, name) Q_CLEANUP_RESOURCE(proj ## _ ## name) +#define _SQLS_INIT_RESOURCE(pname, name) __SQLS_INIT_RESOURCE(pname, name) +#define _SQLS_CLEANUP_RESOURCE(pname, name) __SQLS_CLEANUP_RESOURCE(pname, name) + +// These are replacements for Qt's macros to cover customized resource naming, +// which is used to avoid duplication of qmake_qmake_qm_files resource initialization function across different shared libraries. +#ifdef PROJECT_MODULE_NAME +# define SQLS_INIT_RESOURCE(name) _SQLS_INIT_RESOURCE(PROJECT_MODULE_NAME, name) +# define SQLS_CLEANUP_RESOURCE(name) _SQLS_CLEANUP_RESOURCE(PROJECT_MODULE_NAME, name) +#else +# define SQLS_INIT_RESOURCE(name) +# define SQLS_CLEANUP_RESOURCE(name) +#endif + #endif // GLOBAL_H diff --git a/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp b/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp index 0b95a85..a572330 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp @@ -54,6 +54,7 @@ void initUtils() { qRegisterMetaType<QList<int>>("QList<int>"); qRegisterMetaType<DbObjectType>("DbObjectType"); + qRegisterMetaType<QList<QPair<QString, QString>>>("QList<QPair<QString, QString>>"); } bool isXDigit(const QChar& c) @@ -805,7 +806,7 @@ QString getOsString() DistributionType getDistributionType() { #if defined(Q_OS_OSX) - return DistributionType::OSX_BOUNDLE; + return DistributionType::OSX_BUNDLE; #elif defined(PORTABLE_CONFIG) return DistributionType::PORTABLE; #else @@ -966,12 +967,14 @@ QStringList concat(const QList<QStringList>& list) QString doubleToString(const QVariant& val) { QString str = val.toString(); - if (str.contains("e")) + if (str.contains("e") || str.midRef(str.indexOf('.') + 1).length() > 14) + { str = QString::number(val.toDouble(), 'f', 14).remove(QRegExp("0*$")); + if (str.endsWith(".")) + str += "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; } @@ -1097,3 +1100,31 @@ uint qHash(const QVariant& var) // could not generate a hash for the given variant return -2; } + +QString indentMultiline(const QString& str) +{ + QStringList lines = str.split("\n"); + for (QString& line : lines) + line = line.prepend(" "); + + return lines.join("\n"); +} + +QString toNativePath(const QString& path) +{ + return QDir::toNativeSeparators(path); +} + +QStringList sharedLibFileFilters() +{ + static QStringList filters({ +#ifdef Q_OS_WIN + "*.dll" +#elif defined Q_OS_MACOS + "*.dylib" +#elif defined Q_OS_LINUX || Q_OS_BSD + "*.so" +#endif + }); + return filters; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/common/utils.h b/SQLiteStudio3/coreSQLiteStudio/common/utils.h index f7317e2..0ceecc5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils.h @@ -2,6 +2,7 @@ #define UTILS_H #include "coreSQLiteStudio_global.h" +#include <functional> #include <QList> #include <QMutableListIterator> #include <QSet> @@ -66,6 +67,7 @@ API_EXPORT QStringList tokenizeArgs(const QString& str); API_EXPORT QStringList prefixEach(const QString& prefix, const QStringList& list); API_EXPORT QByteArray hashToBytes(const QHash<QString,QVariant>& hash); API_EXPORT QHash<QString,QVariant> bytesToHash(const QByteArray& bytes); +API_EXPORT QString indentMultiline(const QString& str); /** * @brief indexOf Extension to QStringList::indexOf(). * @@ -261,6 +263,7 @@ API_EXPORT QTextCodec* defaultCodec(); API_EXPORT QTextCodec* codecForName(const QString& name); API_EXPORT QStringList splitByLines(const QString& str); API_EXPORT QString joinLines(const QStringList& lines); +API_EXPORT QStringList sharedLibFileFilters(); API_EXPORT int sum(const QList<int>& integers); API_EXPORT QString getOsString(); API_EXPORT bool validateEmail(const QString& email); @@ -289,7 +292,7 @@ API_EXPORT void sortWithReferenceList(QList<QString>& listToSort, const QList<QS enum class DistributionType { PORTABLE, - OSX_BOUNDLE, + OSX_BUNDLE, OS_MANAGED }; @@ -305,6 +308,36 @@ QList<T> reverse(const QList<T>& list) return result; } +template <class S, class T> +QList<T> map(const QList<S>& list, std::function<T(S)> transformer) +{ + QList<T> result; + for (const S& el : list) + result << transformer(el); + + return result; +} + +template <class S, class T> +QHash<S, T> toHash(const QList<S>& list, std::function<T(S)> transformer) +{ + QHash<S, T> result; + for (const S& el : list) + result[el] = transformer(el); + + return result; +} + +template <class S, class T> +QSet<T> map(const QSet<S>& set, std::function<T(S)> transformer) +{ + QSet<T> result; + for (const S& el : set) + result << transformer(el); + + return result; +} + template <class T> void removeDuplicates(QList<T>& list) { @@ -328,6 +361,8 @@ API_EXPORT QVariant deserializeFromBytes(const QByteArray& bytes); API_EXPORT QString readFileContents(const QString& path, QString* err); +API_EXPORT QString toNativePath(const QString& path); + 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 c8d63e1..0122352 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp @@ -4,14 +4,13 @@ #include "parser/token.h" #include "parser/lexer.h" #include "parser/keywords.h" -#include "log.h" #include <QHash> #include <QPair> #include <QString> #include <QDebug> #include <QMetaType> -QString invalidIdCharacters = "[]()\"'@*.,+-=/%&|:; \t\n<>"; +QString invalidIdCharacters = "[](){}\"'@*.,+-=/#$%&|:; \t\n<>"; QHash<NameWrapper,QPair<QChar,QChar>> wrapperChars; QHash<NameWrapper,QPair<QChar,bool>> wrapperEscapedEnding; QList<NameWrapper> sqlite3Wrappers; @@ -41,10 +40,15 @@ bool doesObjectNeedWrapping(const QString& str) if (str.isEmpty()) return true; - if (isObjWrapped(str)) - return false; + // It used to return false if object name looked to be wrapped already, + // but actually name [abc] is proper name that needs to be wrapped (i.e. "[abc]"). + // Bug reported for this was #4362 + //if (isObjWrapped(str)) + // return false; - if (isKeyword(str)) + // The "soft keyword" check added, as they don't require wrapping. + // For example: SELECT replace('abc', 'a', '1'); + if (isKeyword(str) && !isSoftKeyword(str)) return true; for (int i = 0; i < str.size(); i++) @@ -580,12 +584,80 @@ QString getQueryWithPosition(const QStringList& queries, int position, int* star return QString(); } +int getCursorFinalPositionForQueries(const QString& queries, int position) +{ + const static QSet<QChar> whitespaceChars = {' ', '\t'}; + + int len = queries.length(); + if (position >= len || position < 1) + return position; + + if (!whitespaceChars.contains(queries[position]) && queries[position] != '\xa') + return position; + + // First checking characters at & after cursor - are they just whitespaces until end of line? + int newPos = position; + while (newPos < len) + { + QChar c = queries[newPos++]; + if (whitespaceChars.contains(c)) + continue; + else if (c == '\xa') + break; + else + return position; + } + + // Okay, only whitespaces after cursor, so let's check whats before cursor, + // until the ';' - is it just whitespaces too? + newPos = position; + while (newPos > 1 && whitespaceChars.contains(queries[newPos - 1])) + newPos--; + + if (queries[newPos - 1] == ';') + { + // Jackpot! Our cursor is just somewhere in whitespaces after the query. + // Let's consider that prior query as current. + return newPos - 1; + } + + return position; +} + QString getQueryWithPosition(const QString& queries, int position, int* startPos) { + position = getCursorFinalPositionForQueries(queries, position); QStringList queryList = splitQueries(queries); return getQueryWithPosition(queryList, position, startPos); } +QPair<int, int> getQueryBoundriesForPosition(const QString& contents, int cursorPosition, bool fallBackToPreviousIfNecessary) +{ + int queryStartPos; + QString query = getQueryWithPosition(contents, cursorPosition, &queryStartPos); + TokenList tokens = Lexer::tokenize(query); + tokens.trim(); + tokens.trimRight(Token::OPERATOR, ";"); + + if (tokens.size() == 0 && fallBackToPreviousIfNecessary) + { + // Fallback + cursorPosition = contents.lastIndexOf(";", cursorPosition - 1); + if (cursorPosition > -1) + { + query = getQueryWithPosition(contents, cursorPosition, &queryStartPos); + tokens = Lexer::tokenize(query); + tokens.trim(); + tokens.trimRight(Token::OPERATOR, ";"); + } + } + + if (tokens.size() == 0) + return QPair<int, int>(-1, -1); + + return QPair<int, int>(tokens.first()->start + queryStartPos, tokens.last()->end + 1 + queryStartPos); +} + QString trimBindParamPrefix(const QString& param) { if (param == "?") @@ -822,3 +894,15 @@ SqliteDataType toSqliteDataType(const QString& typeStr) return SqliteDataType::UNKNOWN; } + +QByteArray blobFromLiteral(const QString& value) +{ + if (value.length() <= 3) + { + qCritical() << "Call to blobFromLiteral() with blob literal shorter or equal to 3 characters:" << value; + return QByteArray(); + } + + QString hex = value.mid(2, value.length() - 3); + return QByteArray::fromHex(hex.toLatin1()); +} diff --git a/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.h b/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.h index b9cfdcf..353faf3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.h @@ -78,6 +78,7 @@ API_EXPORT QStringList splitQueries(const QString& sql, bool keepEmptyQueries = API_EXPORT QStringList quickSplitQueries(const QString& sql, bool keepEmptyQueries = true, bool removeComments = false); API_EXPORT QString getQueryWithPosition(const QStringList& queries, int position, int* startPos = nullptr); API_EXPORT QString getQueryWithPosition(const QString& queries, int position, int* startPos = nullptr); +API_EXPORT QPair<int, int> getQueryBoundriesForPosition(const QString& contents, int cursorPosition, bool fallBackToPreviousIfNecessary); API_EXPORT QList<QueryWithParamNames> getQueriesWithParamNames(const QString& query); API_EXPORT QList<QueryWithParamCount> getQueriesWithParamCount(const QString& query); API_EXPORT QueryWithParamNames getQueryWithParamNames(const QString& query); @@ -88,6 +89,7 @@ API_EXPORT QString getBindTokenName(const TokenPtr& token); API_EXPORT QueryAccessMode getQueryAccessMode(const QString& query, bool* isSelect = nullptr); API_EXPORT QStringList valueListToSqlList(const QList<QVariant>& values); API_EXPORT QString trimQueryEnd(const QString& query); +API_EXPORT QByteArray blobFromLiteral(const QString& value); #endif // UTILS_SQL_H |
