aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/plugins')
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.cpp7
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.h2
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginstdfilebase.cpp6
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.cpp4
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.h2
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.cpp4
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.h2
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/populatescript.cpp29
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/scriptingplugin.h28
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp157
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.h52
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.pngbin1750 -> 488 bytes
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.cpp28
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.h13
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.cpp29
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.h8
16 files changed, 244 insertions, 127 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.cpp
index 4a19489..854e7b4 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.cpp
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.cpp
@@ -10,6 +10,9 @@ Db* DbPluginSqlite3::getInstance(const QString& name, const QString& path, const
if (!db->openForProbing())
{
+ if (errorMessage)
+ *errorMessage = db->getErrorText();
+
delete db;
return nullptr;
}
@@ -17,9 +20,13 @@ Db* DbPluginSqlite3::getInstance(const QString& name, const QString& path, const
SqlQueryPtr results = db->exec("SELECT * FROM sqlite_master");
if (results->isError())
{
+ if (errorMessage)
+ *errorMessage = db->getErrorText();
+
delete db;
return nullptr;
}
+ results.clear();
db->closeQuiet();
return db;
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.h b/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.h
index 79b762a..417c93e 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.h
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginsqlite3.h
@@ -10,7 +10,7 @@ class DbPluginSqlite3 : public BuiltInPlugin, public DbPlugin
SQLITESTUDIO_PLUGIN_TITLE("SQLite 3")
SQLITESTUDIO_PLUGIN_DESC("SQLite 3 databases support.")
- SQLITESTUDIO_PLUGIN_VERSION(10000)
+ SQLITESTUDIO_PLUGIN_VERSION(10001)
SQLITESTUDIO_PLUGIN_AUTHOR("sqlitestudio.pl")
public:
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginstdfilebase.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginstdfilebase.cpp
index b890c26..5887eac 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginstdfilebase.cpp
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/dbpluginstdfilebase.cpp
@@ -11,6 +11,9 @@ Db *DbPluginStdFileBase::getInstance(const QString &name, const QString &path, c
if (!db->openForProbing())
{
+ if (errorMessage)
+ *errorMessage = db->getErrorText();
+
delete db;
return nullptr;
}
@@ -18,6 +21,9 @@ Db *DbPluginStdFileBase::getInstance(const QString &name, const QString &path, c
SqlQueryPtr results = db->exec("SELECT * FROM sqlite_master");
if (results->isError())
{
+ if (errorMessage)
+ *errorMessage = db->getErrorText();
+
delete db;
return nullptr;
}
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.cpp
index 149e92b..e1d9f98 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.cpp
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.cpp
@@ -22,7 +22,7 @@ bool PopulateRandomEngine::beforePopulating(Db* db, const QString& table)
{
UNUSED(db);
UNUSED(table);
- QRandomGenerator::system()->seed(QDateTime::currentDateTime().toTime_t());
+ randomGenerator = QRandomGenerator::securelySeeded();
range = cfg.PopulateRandom.MaxValue.get() - cfg.PopulateRandom.MinValue.get() + 1;
return (range > 0);
}
@@ -30,7 +30,7 @@ bool PopulateRandomEngine::beforePopulating(Db* db, const QString& table)
QVariant PopulateRandomEngine::nextValue(bool& nextValueError)
{
UNUSED(nextValueError);
- QString randValue = QString::number((QRandomGenerator::system()->generate() % range) + cfg.PopulateRandom.MinValue.get());
+ QString randValue = QString::number((randomGenerator.generate() % range) + cfg.PopulateRandom.MinValue.get());
return (cfg.PopulateRandom.Prefix.get() + randValue + cfg.PopulateRandom.Suffix.get());
}
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.h b/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.h
index f4e9feb..29bb02b 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.h
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandom.h
@@ -4,6 +4,7 @@
#include "builtinplugin.h"
#include "populateplugin.h"
#include "config_builder.h"
+#include <QRandomGenerator>
CFG_CATEGORIES(PopulateRandomConfig,
CFG_CATEGORY(PopulateRandom,
@@ -43,5 +44,6 @@ class PopulateRandomEngine : public PopulateEngine
private:
CFG_LOCAL(PopulateRandomConfig, cfg)
int range;
+ QRandomGenerator randomGenerator;
};
#endif // POPULATERANDOM_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.cpp
index e2f8733..33ac1d6 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.cpp
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.cpp
@@ -23,7 +23,7 @@ bool PopulateRandomTextEngine::beforePopulating(Db* db, const QString& table)
{
UNUSED(db);
UNUSED(table);
- QRandomGenerator::system()->seed(QDateTime::currentDateTime().toTime_t());
+ randomGenerator = QRandomGenerator::securelySeeded();
range = cfg.PopulateRandomText.MaxLength.get() - cfg.PopulateRandomText.MinLength.get() + 1;
chars = "";
@@ -55,7 +55,7 @@ bool PopulateRandomTextEngine::beforePopulating(Db* db, const QString& table)
QVariant PopulateRandomTextEngine::nextValue(bool& nextValueError)
{
UNUSED(nextValueError);
- int lgt = (QRandomGenerator::system()->generate() % range) + cfg.PopulateRandomText.MinLength.get();
+ int lgt = (randomGenerator.generate() % range) + cfg.PopulateRandomText.MinLength.get();
return randStr(lgt, chars);
}
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.h b/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.h
index 892b302..fdc5c43 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.h
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/populaterandomtext.h
@@ -4,6 +4,7 @@
#include "builtinplugin.h"
#include "populateplugin.h"
#include "config_builder.h"
+#include <QRandomGenerator>
CFG_CATEGORIES(PopulateRandomTextConfig,
CFG_CATEGORY(PopulateRandomText,
@@ -47,6 +48,7 @@ class PopulateRandomTextEngine : public PopulateEngine
CFG_LOCAL(PopulateRandomTextConfig, cfg)
int range;
QString chars;
+ QRandomGenerator randomGenerator;
};
#endif // POPULATERANDOMTEXT_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/populatescript.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/populatescript.cpp
index 79a8ac1..8c356f9 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/populatescript.cpp
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/populatescript.cpp
@@ -4,6 +4,27 @@
#include "services/pluginmanager.h"
#include "services/notifymanager.h"
+class PopulateFunctionInfoImpl : public ScriptingPlugin::FunctionInfo
+{
+ public:
+ PopulateFunctionInfoImpl(bool rowCount)
+ {
+ args = QStringList({"dbName", "tableName"});
+ if (rowCount)
+ args << "rowCount";
+ }
+
+ QString getName() const {return QString();}
+ QStringList getArguments() const {return args;}
+ bool getUndefinedArgs() const {return false;}
+
+ private:
+ QStringList args;
+};
+
+PopulateFunctionInfoImpl populateInitFunctionInfo(false);
+PopulateFunctionInfoImpl populateNextFunctionInfo(true);
+
PopulateScript::PopulateScript()
{
}
@@ -49,9 +70,9 @@ bool PopulateScriptEngine::beforePopulating(Db* db, const QString& table)
if (!initCode.trimmed().isEmpty())
{
if (dbAwarePlugin)
- dbAwarePlugin->evaluate(context, initCode, evalArgs, db);
+ dbAwarePlugin->evaluate(context, initCode, populateInitFunctionInfo, evalArgs, db);
else
- scriptingPlugin->evaluate(context, initCode, evalArgs);
+ scriptingPlugin->evaluate(context, initCode, populateInitFunctionInfo, evalArgs);
if (scriptingPlugin->hasError(context))
{
@@ -71,9 +92,9 @@ QVariant PopulateScriptEngine::nextValue(bool& nextValueError)
{
QVariant result;
if (dbAwarePlugin)
- result = dbAwarePlugin->evaluate(context, cfg.PopulateScript.Code.get(), evalArgs, db);
+ result = dbAwarePlugin->evaluate(context, cfg.PopulateScript.Code.get(), populateNextFunctionInfo, evalArgs, db);
else
- result = scriptingPlugin->evaluate(context, cfg.PopulateScript.Code.get(), evalArgs);
+ result = scriptingPlugin->evaluate(context, cfg.PopulateScript.Code.get(), populateNextFunctionInfo, evalArgs);
if (scriptingPlugin->hasError(context))
{
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingplugin.h b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingplugin.h
index d081073..80aa758 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingplugin.h
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingplugin.h
@@ -15,33 +15,45 @@ class ScriptingPlugin : virtual public Plugin
virtual ~Context() {}
};
+ class FunctionInfo
+ {
+ public:
+ virtual QString getName() const = 0;
+ virtual QStringList getArguments() const = 0;
+ virtual bool getUndefinedArgs() const = 0;
+ };
+
virtual QString getLanguage() const = 0;
virtual Context* createContext() = 0;
virtual void releaseContext(Context* context) = 0;
virtual void resetContext(Context* context) = 0;
virtual void setVariable(Context* context, const QString& name, const QVariant& value) = 0;
virtual QVariant getVariable(Context* context, const QString& name) = 0;
- virtual QVariant evaluate(Context* context, const QString& code, const QList<QVariant>& args = QList<QVariant>()) = 0;
+ virtual QVariant evaluate(Context* context, const QString& code, const FunctionInfo& funcInfo,
+ const QList<QVariant>& args = QList<QVariant>()) = 0;
virtual bool hasError(Context* context) const = 0;
virtual QString getErrorMessage(Context* context) const = 0;
- virtual QVariant evaluate(const QString& code, const QList<QVariant>& args = QList<QVariant>(), QString* errorMessage = nullptr) = 0;
+ virtual QVariant evaluate(const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args = QList<QVariant>(),
+ QString* errorMessage = nullptr) = 0;
virtual QString getIconPath() const = 0;
};
class DbAwareScriptingPlugin : public ScriptingPlugin
{
public:
- virtual QVariant evaluate(Context* context, const QString& code, const QList<QVariant>& args, Db* db, bool locking = false) = 0;
- virtual QVariant evaluate(const QString& code, const QList<QVariant>& args, Db* db, bool locking = false, QString* errorMessage = nullptr) = 0;
+ virtual QVariant evaluate(Context* context, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args,
+ Db* db, bool locking = false) = 0;
+ virtual QVariant evaluate(const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db,
+ bool locking = false, QString* errorMessage = nullptr) = 0;
- QVariant evaluate(Context* context, const QString& code, const QList<QVariant>& args)
+ QVariant evaluate(Context* context, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args)
{
- return evaluate(context, code, args, nullptr, true);
+ return evaluate(context, code, funcInfo, args, nullptr, true);
}
- QVariant evaluate(const QString& code, const QList<QVariant>& args, QString* errorMessage = nullptr)
+ QVariant evaluate(const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, QString* errorMessage = nullptr)
{
- return evaluate(code, args, nullptr, true, errorMessage);
+ return evaluate(code, funcInfo, args, nullptr, true, errorMessage);
}
};
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp
index f88fa85..5305f24 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp
@@ -1,42 +1,39 @@
#include "scriptingqt.h"
-#include "common/unused.h"
#include "common/global.h"
#include "scriptingqtdbproxy.h"
-#include <QScriptEngine>
+#include "services/notifymanager.h"
+#include <QJSEngine>
#include <QMutex>
#include <QMutexLocker>
#include <QDebug>
-static QScriptValue scriptingQtDebug(QScriptContext *context, QScriptEngine *engine)
+ScriptingQt::ScriptingQt()
{
- UNUSED(engine);
- QStringList args;
- for (int i = 0; i < context->argumentCount(); i++)
- args << context->argument(i).toString();
-
- qDebug() << "[ScriptingQt]" << args;
- return QScriptValue();
+ managedMainContextsMutex = new QMutex();
}
-ScriptingQt::ScriptingQt()
+ScriptingQt::~ScriptingQt()
{
- mainEngineMutex = new QMutex();
+ safe_delete(managedMainContextsMutex);
}
-ScriptingQt::~ScriptingQt()
+QJSValueList ScriptingQt::toValueList(QJSEngine* engine, const QList<QVariant>& values)
{
- safe_delete(mainEngineMutex);
+ QJSValueList result;
+ for (const QVariant& value : values)
+ result << engine->toScriptValue(value);
+
+ return result;
}
QString ScriptingQt::getLanguage() const
{
- return QStringLiteral("QtScript");
+ return QStringLiteral("JavaScript");
}
ScriptingPlugin::Context* ScriptingQt::createContext()
{
ContextQt* ctx = new ContextQt;
- ctx->engine->pushContext();
contexts << ctx;
return ctx;
}
@@ -56,60 +53,54 @@ void ScriptingQt::resetContext(ScriptingPlugin::Context* context)
ContextQt* ctx = getContext(context);
if (!ctx)
return;
-
- ctx->engine->popContext();
- ctx->engine->pushContext();
}
-QVariant ScriptingQt::evaluate(const QString& code, const QList<QVariant>& args, Db* db, bool locking, QString* errorMessage)
+QVariant ScriptingQt::evaluate(const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking, QString* errorMessage)
{
- QMutexLocker locker(mainEngineMutex);
-
- // Enter a new context
- QScriptContext* engineContext = mainContext->engine->pushContext();
-
// Call the function
- QVariant result = evaluate(mainContext, engineContext, code, args, db, locking);
+ ContextQt* context = getMainContext();
+ QVariant result = evaluate(context, code, funcInfo, args, db, locking);
// Handle errors
- if (!mainContext->error.isEmpty())
- *errorMessage = mainContext->error;
-
- // Leave the context to reset "this".
- mainContext->engine->popContext();
+ if (!context->error.isEmpty())
+ *errorMessage = context->error;
return result;
}
-QVariant ScriptingQt::evaluate(ScriptingPlugin::Context* context, const QString& code, const QList<QVariant>& args, Db* db, bool locking)
+QVariant ScriptingQt::evaluate(ScriptingPlugin::Context* context, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking)
{
ContextQt* ctx = getContext(context);
if (!ctx)
return QVariant();
- return evaluate(ctx, ctx->engine->currentContext(), code, args, db, locking);
+ return evaluate(ctx, code, funcInfo, args, db, locking);
}
-QVariant ScriptingQt::evaluate(ContextQt* ctx, QScriptContext* engineContext, const QString& code, const QList<QVariant>& args, Db* db, bool locking)
+QVariant ScriptingQt::evaluate(ContextQt* ctx, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking)
{
// Define function to call
- QScriptValue functionValue = getFunctionValue(ctx, code);
+ QJSValue functionValue = getFunctionValue(ctx, code, funcInfo);
// Db for this evaluation
ctx->dbProxy->setDb(db);
ctx->dbProxy->setUseDbLocking(locking);
// Call the function
- QScriptValue result;
+ QJSValue result;
if (args.size() > 0)
- result = functionValue.call(engineContext->activationObject(), ctx->engine->toScriptValue(args));
+ result = functionValue.call(toValueList(ctx->engine, args));
else
- result = functionValue.call(engineContext->activationObject());
+ result = functionValue.call();
// Handle errors
ctx->error.clear();
- if (ctx->engine->hasUncaughtException())
- ctx->error = ctx->engine->uncaughtException().toString();
+ if (result.isError())
+ {
+ ctx->error = QString("Uncaught exception at line %1: %2").arg(
+ result.property("lineNumber").toString(),
+ result.toString());
+ }
ctx->dbProxy->setDb(nullptr);
ctx->dbProxy->setUseDbLocking(false);
@@ -117,6 +108,20 @@ QVariant ScriptingQt::evaluate(ContextQt* ctx, QScriptContext* engineContext, co
return convertVariant(result.toVariant());
}
+ScriptingQt::ContextQt* ScriptingQt::getMainContext()
+{
+ if (mainContext.hasLocalData())
+ return mainContext.localData();
+
+ ContextQt* context = new ContextQt();
+ mainContext.setLocalData(context);
+
+ QMutexLocker locker(managedMainContextsMutex);
+ managedMainContexts << context;
+
+ return context;
+}
+
QVariant ScriptingQt::convertVariant(const QVariant& value, bool wrapStrings)
{
switch (value.type())
@@ -148,7 +153,7 @@ QVariant ScriptingQt::convertVariant(const QVariant& value, bool wrapStrings)
case QVariant::List:
{
QStringList list;
- for (const QVariant& var : value.toList())
+ for (QVariant& var : value.toList())
list << convertVariant(var, true).toString();
return "[" + list.join(", ") + "]";
@@ -176,7 +181,7 @@ void ScriptingQt::setVariable(ScriptingPlugin::Context* context, const QString&
if (!ctx)
return;
- ctx->engine->globalObject().setProperty(name, ctx->engine->newVariant(value));
+ ctx->engine->globalObject().setProperty(name, ctx->engine->toScriptValue(value));
}
QVariant ScriptingQt::getVariable(ScriptingPlugin::Context* context, const QString& name)
@@ -185,7 +190,7 @@ QVariant ScriptingQt::getVariable(ScriptingPlugin::Context* context, const QStri
if (!ctx)
return QVariant();
- QScriptValue value = ctx->engine->globalObject().property(name);
+ QJSValue value = ctx->engine->globalObject().property(name);
return convertVariant(value.toVariant());
}
@@ -214,20 +219,28 @@ QString ScriptingQt::getIconPath() const
bool ScriptingQt::init()
{
- QMutexLocker locker(mainEngineMutex);
- mainContext = new ContextQt;
return true;
}
void ScriptingQt::deinit()
{
- for (Context* ctx : contexts)
+ for (Context*& ctx : contexts)
delete ctx;
contexts.clear();
- QMutexLocker locker(mainEngineMutex);
- safe_delete(mainContext);
+ QMutexLocker locker(managedMainContextsMutex);
+ for (ContextQt*& ctx : managedMainContexts)
+ {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ ctx->engine->setInterrupted(true);
+#else
+ // FIXME No way to cleanly interrupt QJSEngine before Qt 5.14
+#endif
+ delete ctx;
+ }
+
+ managedMainContexts.clear();
}
ScriptingQt::ContextQt* ScriptingQt::getContext(ScriptingPlugin::Context* context) const
@@ -239,31 +252,30 @@ ScriptingQt::ContextQt* ScriptingQt::getContext(ScriptingPlugin::Context* contex
return ctx;
}
-QScriptValue ScriptingQt::getFunctionValue(ContextQt* ctx, const QString& code)
+QJSValue ScriptingQt::getFunctionValue(ContextQt* ctx, const QString& code, const FunctionInfo& funcInfo)
{
- static const QString fnDef = QStringLiteral("(function () {%1\n})");
+ static const QString fnDef = QStringLiteral("(function (%1) {%2\n})");
- QScriptProgram* prog = nullptr;
- if (!ctx->scriptCache.contains(code))
- {
- prog = new QScriptProgram(fnDef.arg(code));
- ctx->scriptCache.insert(code, prog);
- }
- else
- {
- prog = ctx->scriptCache[code];
- }
- return ctx->engine->evaluate(*prog);
+ QString fullCode = fnDef.arg(funcInfo.getArguments().join(", "), code);
+ QJSValue* func = ctx->scriptCache[fullCode];
+ if (func)
+ return *func;
+
+ func = new QJSValue(ctx->engine->evaluate(fullCode));
+ ctx->scriptCache.insert(fullCode, func);
+ return *func;
}
ScriptingQt::ContextQt::ContextQt()
{
- engine = new QScriptEngine();
+ engine = new QJSEngine();
+ engine->installExtensions(QJSEngine::ConsoleExtension);
- dbProxy = new ScriptingQtDbProxy();
- dbProxyScriptValue = engine->newQObject(dbProxy, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater);
+ dbProxy = new ScriptingQtDbProxy(engine);
+ dbProxyScriptValue = engine->newQObject(dbProxy);
+ console = new ScriptingQtConsole(engine);
- engine->globalObject().setProperty("debug", engine->newFunction(scriptingQtDebug));
+ engine->globalObject().setProperty("console", engine->newQObject(console));
engine->globalObject().setProperty("db", dbProxyScriptValue);
scriptCache.setMaxCost(cacheSize);
@@ -271,6 +283,19 @@ ScriptingQt::ContextQt::ContextQt()
ScriptingQt::ContextQt::~ContextQt()
{
- safe_delete(engine);
+ safe_delete(console);
safe_delete(dbProxy);
+ safe_delete(engine);
+}
+
+ScriptingQtConsole::ScriptingQtConsole(QJSEngine* engine) :
+ QObject(), engine(engine)
+{
+}
+
+QJSValue ScriptingQtConsole::log(const QJSValue& value)
+{
+ static_qstring(tpl, "[JS] %1");
+ NOTIFY_MANAGER->info(tpl.arg(ScriptingQt::convertVariant(value.toVariant()).toString()));
+ return QJSValue();
}
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.h b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.h
index 125789a..a7e156c 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.h
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.h
@@ -6,33 +6,35 @@
#include <QHash>
#include <QVariant>
#include <QCache>
-#include <QScriptValue>
-#include <QScriptProgram>
+#include <QJSValue>
+#include <QThreadStorage>
-class QScriptEngine;
class QMutex;
-class QScriptContext;
class ScriptingQtDbProxy;
+class ScriptingQtConsole;
class ScriptingQt : public BuiltInPlugin, public DbAwareScriptingPlugin
{
Q_OBJECT
- SQLITESTUDIO_PLUGIN_TITLE("Qt scripting")
- SQLITESTUDIO_PLUGIN_DESC("Qt scripting support.")
- SQLITESTUDIO_PLUGIN_VERSION(10000)
+ SQLITESTUDIO_PLUGIN_TITLE("JavaScript scripting")
+ SQLITESTUDIO_PLUGIN_DESC("JavaScript scripting support.")
+ SQLITESTUDIO_PLUGIN_VERSION(10100)
SQLITESTUDIO_PLUGIN_AUTHOR("sqlitestudio.pl")
public:
ScriptingQt();
~ScriptingQt();
+ static QJSValueList toValueList(QJSEngine* engine, const QList<QVariant>& values);
+ static QVariant convertVariant(const QVariant& value, bool wrapStrings = false);
+
QString getLanguage() const;
Context* createContext();
void releaseContext(Context* context);
void resetContext(Context* context);
- QVariant evaluate(const QString& code, const QList<QVariant>& args, Db* db, bool locking = false, QString* errorMessage = nullptr);
- QVariant evaluate(Context* context, const QString& code, const QList<QVariant>& args, Db* db, bool locking = false);
+ QVariant evaluate(const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking = false, QString* errorMessage = nullptr);
+ QVariant evaluate(Context* context, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking = false);
void setVariable(Context* context, const QString& name, const QVariant& value);
QVariant getVariable(Context* context, const QString& name);
bool hasError(Context* context) const;
@@ -50,23 +52,39 @@ class ScriptingQt : public BuiltInPlugin, public DbAwareScriptingPlugin
ContextQt();
~ContextQt();
- QScriptEngine* engine = nullptr;
- QCache<QString,QScriptProgram> scriptCache;
+ QJSEngine* engine = nullptr;
+ QCache<QString, QJSValue> scriptCache;
QString error;
ScriptingQtDbProxy* dbProxy = nullptr;
- QScriptValue dbProxyScriptValue;
+ ScriptingQtConsole* console = nullptr;
+ QJSValue dbProxyScriptValue;
};
ContextQt* getContext(ScriptingPlugin::Context* context) const;
- QScriptValue getFunctionValue(ContextQt* ctx, const QString& code);
- QVariant evaluate(ContextQt* ctx, QScriptContext* engineContext, const QString& code, const QList<QVariant>& args, Db* db, bool locking);
- QVariant convertVariant(const QVariant& value, bool wrapStrings = false);
+ QJSValue getFunctionValue(ContextQt* ctx, const QString& code, const FunctionInfo& funcInfo);
+ QVariant evaluate(ContextQt* ctx, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking);
+ ContextQt* getMainContext();
static const constexpr int cacheSize = 5;
- ContextQt* mainContext = nullptr;
+ QThreadStorage<ContextQt*> mainContext;
QList<Context*> contexts;
- QMutex* mainEngineMutex = nullptr;
+ QList<ContextQt*> managedMainContexts;
+ QMutex* managedMainContextsMutex = nullptr;
+};
+
+class ScriptingQtConsole : public QObject
+{
+ Q_OBJECT
+
+ public:
+ ScriptingQtConsole(QJSEngine* engine);
+
+ private:
+ QJSEngine* engine = nullptr;
+
+ public slots:
+ QJSValue log(const QJSValue& value);
};
#endif // SCRIPTINGQT_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.png b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.png
index 220ea27..ce8e60a 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.png
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.png
Binary files differ
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.cpp
index ff3c7ee..cc9fa2d 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.cpp
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.cpp
@@ -1,11 +1,11 @@
+#include "scriptingqt.h"
#include "scriptingqtdbproxy.h"
#include "db/db.h"
#include "db/sqlquery.h"
-#include <QScriptContext>
-#include <QScriptEngine>
+#include <QJSEngine>
-ScriptingQtDbProxy::ScriptingQtDbProxy(QObject *parent) :
- QObject(parent)
+ScriptingQtDbProxy::ScriptingQtDbProxy(QJSEngine* engine, QObject *parent) :
+ QObject(parent), engine(engine)
{
}
Db* ScriptingQtDbProxy::getDb() const
@@ -40,12 +40,12 @@ QHash<QString, QVariant> ScriptingQtDbProxy::mapToHash(const QMap<QString, QVari
}
QVariant ScriptingQtDbProxy::evalInternal(const QString& sql, const QList<QVariant>& listArgs, const QMap<QString, QVariant>& mapArgs,
- bool singleCell, const QScriptValue* funcPtr)
+ bool singleCell, const QJSValue* funcPtr)
{
if (!db)
{
QString funcName = singleCell ? QStringLiteral("db.onecolumn()") : QStringLiteral("db.eval()");
- context()->throwError(tr("No database available in current context, while called QtScript's %1 command.").arg(funcName));
+ engine->throwError(tr("No database available in current context, while called JavaScript's %1 command.").arg(funcName));
return evalInternalErrorResult(singleCell);
}
@@ -62,7 +62,7 @@ QVariant ScriptingQtDbProxy::evalInternal(const QString& sql, const QList<QVaria
if (results->isError())
{
QString funcName = singleCell ? QStringLiteral("db.onecolumn()") : QStringLiteral("db.eval()");
- context()->throwError(tr("Error from %1: %2").arg(funcName, results->getErrorText()));
+ engine->throwError(tr("Error from %1: %2").arg(funcName, results->getErrorText()));
return evalInternalErrorResult(singleCell);
}
@@ -72,15 +72,15 @@ QVariant ScriptingQtDbProxy::evalInternal(const QString& sql, const QList<QVaria
}
else if (funcPtr)
{
- QScriptValue func(*funcPtr);
+ QJSValue func(*funcPtr);
SqlResultsRowPtr row;
- QScriptValue funcArgs;
- QScriptValue funcResult;
+ QJSValueList funcArgs;
+ QJSValue funcResult;
while (results->hasNext())
{
row = results->next();
- funcArgs = context()->engine()->toScriptValue(row->valueList());
- funcResult = func.call(context()->thisObject(), funcArgs);
+ funcArgs = ScriptingQt::toValueList(engine, row->valueList());
+ funcResult = func.call(funcArgs);
if (!funcResult.isUndefined())
break;
}
@@ -123,12 +123,12 @@ QVariant ScriptingQtDbProxy::eval(const QString& sql, const QMap<QString, QVaria
return evalInternal(sql, QList<QVariant>(), args, false);
}
-QVariant ScriptingQtDbProxy::eval(const QString& sql, const QList<QVariant>& args, const QScriptValue& func)
+QVariant ScriptingQtDbProxy::eval(const QString& sql, const QList<QVariant>& args, const QJSValue& func)
{
return evalInternal(sql, args, QMap<QString, QVariant>(), false, &func);
}
-QVariant ScriptingQtDbProxy::eval(const QString& sql, const QMap<QString, QVariant>& args, const QScriptValue& func)
+QVariant ScriptingQtDbProxy::eval(const QString& sql, const QMap<QString, QVariant>& args, const QJSValue& func)
{
return evalInternal(sql, QList<QVariant>(), args, false, &func);
}
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.h b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.h
index add9540..9a86f6b 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.h
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqtdbproxy.h
@@ -2,18 +2,18 @@
#define SCRIPTINGQTDBPROXY_H
#include <QObject>
-#include <QScriptable>
#include <QHash>
#include <QList>
#include <QVariant>
+#include <QJSValue>
class Db;
-class ScriptingQtDbProxy : public QObject, protected QScriptable
+class ScriptingQtDbProxy : public QObject
{
Q_OBJECT
public:
- explicit ScriptingQtDbProxy(QObject *parent = 0);
+ explicit ScriptingQtDbProxy(QJSEngine* engine, QObject *parent = 0);
Db* getDb() const;
void setDb(Db* value);
@@ -23,20 +23,21 @@ class ScriptingQtDbProxy : public QObject, protected QScriptable
private:
QVariant evalInternal(const QString& sql, const QList<QVariant>& listArgs, const QMap<QString, QVariant>& mapArgs, bool singleCell,
- const QScriptValue* funcPtr = nullptr);
+ const QJSValue* funcPtr = nullptr);
QVariant evalInternalErrorResult(bool singleCell);
static QHash<QString, QVariant> mapToHash(const QMap<QString, QVariant>& map);
Db* db = nullptr;
bool useDbLocking = false;
+ QJSEngine* engine = nullptr;
public slots:
QVariant eval(const QString& sql);
QVariant eval(const QString& sql, const QList<QVariant>& args);
QVariant eval(const QString& sql, const QMap<QString, QVariant>& args);
- QVariant eval(const QString& sql, const QList<QVariant>& args, const QScriptValue& func);
- QVariant eval(const QString& sql, const QMap<QString, QVariant>& args, const QScriptValue& func);
+ QVariant eval(const QString& sql, const QList<QVariant>& args, const QJSValue& func);
+ QVariant eval(const QString& sql, const QMap<QString, QVariant>& args, const QJSValue& func);
QVariant onecolumn(const QString& sql, const QList<QVariant>& args);
QVariant onecolumn(const QString& sql, const QMap<QString, QVariant>& args);
};
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.cpp
index 93a6d91..7edd7e7 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.cpp
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.cpp
@@ -38,7 +38,7 @@ void ScriptingSql::resetContext(ScriptingPlugin::Context* context)
dynamic_cast<SqlContext*>(context)->errorText.clear();
}
-QVariant ScriptingSql::evaluate(ScriptingPlugin::Context* context, const QString& code, const QList<QVariant>& args, Db* db, bool locking)
+QVariant ScriptingSql::evaluate(ScriptingPlugin::Context* context, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking)
{
SqlContext* ctx = dynamic_cast<SqlContext*>(context);
ctx->errorText.clear();
@@ -58,14 +58,15 @@ QVariant ScriptingSql::evaluate(ScriptingPlugin::Context* context, const QString
QString sql = code;
if (ctx->variables.size() > 0)
{
- QString value;
for (const QString& key : ctx->variables.keys())
{
- value = "'" + ctx->variables[key].toString() + "'";
+ QString value = "'" + ctx->variables[key].toString() + "'";
sql.replace(":" + key, value).replace("@" + key, value).replace("$" + key, value);
}
}
+ replaceNamedArgs(sql, funcInfo, args);
+
SqlQueryPtr result = theDb->exec(sql, args, execFlags);
if (result->isError())
{
@@ -76,7 +77,7 @@ QVariant ScriptingSql::evaluate(ScriptingPlugin::Context* context, const QString
return result->getSingleCell();
}
-QVariant ScriptingSql::evaluate(const QString& code, const QList<QVariant>& args, Db* db, bool locking, QString* errorMessage)
+QVariant ScriptingSql::evaluate(const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking, QString* errorMessage)
{
Db* theDb = nullptr;
@@ -91,7 +92,10 @@ QVariant ScriptingSql::evaluate(const QString& code, const QList<QVariant>& args
if (!locking)
execFlags |= Db::Flag::NO_LOCK;
- SqlQueryPtr result = theDb->exec(code, args, execFlags);
+ QString sql = code;
+ replaceNamedArgs(sql, funcInfo, args);
+
+ SqlQueryPtr result = theDb->exec(sql, args, execFlags);
if (result->isError())
{
*errorMessage = result->getErrorText();
@@ -144,3 +148,18 @@ void ScriptingSql::deinit()
safe_delete(memDb);
}
+
+void ScriptingSql::replaceNamedArgs(QString& sql, const ScriptingPlugin::FunctionInfo& funcInfo, const QList<QVariant>& args)
+{
+ int i = 0;
+ for (const QString& key : funcInfo.getArguments())
+ {
+ if (i >= args.size())
+ break;
+
+ QString value = "'" + args[i++].toString() + "'";
+ sql.replace(":" + key, value)
+ .replace("@" + key, value)
+ .replace("$" + key, value);
+ }
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.h b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.h
index 7b8fd3b..8fa51db 100644
--- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.h
+++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingsql.h
@@ -28,8 +28,10 @@ class ScriptingSql : public BuiltInPlugin, public DbAwareScriptingPlugin
Context* createContext();
void releaseContext(Context* context);
void resetContext(Context* context);
- QVariant evaluate(Context* context, const QString& code, const QList<QVariant>& args, Db* db, bool locking);
- QVariant evaluate(const QString& code, const QList<QVariant>& args, Db* db, bool locking, QString* errorMessage);
+ QVariant evaluate(Context* context, const QString& code, const FunctionInfo& funcInfo,
+ const QList<QVariant>& args, Db* db, bool locking);
+ QVariant evaluate(const QString& code, const FunctionInfo& funcInfo,
+ const QList<QVariant>& args, Db* db, bool locking, QString* errorMessage);
void setVariable(Context* context, const QString& name, const QVariant& value);
QVariant getVariable(Context* context, const QString& name);
bool hasError(Context* context) const;
@@ -39,6 +41,8 @@ class ScriptingSql : public BuiltInPlugin, public DbAwareScriptingPlugin
void deinit();
private:
+ void replaceNamedArgs(QString& sql, const FunctionInfo& funcInfo, const QList<QVariant>& args);
+
QList<Context*> contexts;
Db* memDb = nullptr;
};