aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/common
diff options
context:
space:
mode:
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/common')
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp25
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/common/bistrhash.h21
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/common/compatibility.cpp7
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/common/compatibility.h3
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/common/global.h19
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/common/utils.cpp39
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/common/utils.h37
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp94
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/common/utils_sql.h2
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