mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-05-19 12:08:23 -05:00
Use a custom extension function instead of the json_array function
For multi-column PKs in WITHOUT ROWID tables the first implementation added a dependency on the JSON extension by using the json_array function. To make sure DB4S works even without this extension, this commit adds and makes use of a custom extension function which essentially does the same thing as json_array.
This commit is contained in:
+1
-1
@@ -52,7 +52,7 @@ std::string Query::buildQuery(bool withRowid) const
|
||||
{
|
||||
selector = sqlb::escapeIdentifier(m_rowid_columns.at(0)) + ",";
|
||||
} else {
|
||||
selector += "json_array(";
|
||||
selector += "sqlb_make_single_value(";
|
||||
for(size_t i=0;i<m_rowid_columns.size();i++)
|
||||
selector += sqlb::escapeIdentifier(m_rowid_columns.at(i)) + ",";
|
||||
selector.pop_back(); // Remove the last comma
|
||||
|
||||
+38
-6
@@ -20,6 +20,9 @@
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
QStringList DBBrowserDB::Datatypes = QStringList() << "INTEGER" << "TEXT" << "BLOB" << "REAL" << "NUMERIC";
|
||||
|
||||
@@ -60,6 +63,22 @@ static int sqlite_compare_utf16ci( void* /*arg*/,int size1, const void *str1, in
|
||||
return QString::compare(string1, string2, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
static void sqlite_make_single_value(sqlite3_context* ctx, int num_arguments, sqlite3_value* arguments[])
|
||||
{
|
||||
json array;
|
||||
for(int i=0;i<num_arguments;i++)
|
||||
array.push_back(reinterpret_cast<const char*>(sqlite3_value_text(arguments[i])));
|
||||
|
||||
std::string output = array.dump();
|
||||
char* output_str = new char[output.size()+1];
|
||||
std::strcpy(output_str, output.c_str());
|
||||
|
||||
sqlite3_result_text(ctx, output_str, output.length(), [](void* ptr) {
|
||||
char* cptr = static_cast<char*>(ptr);
|
||||
delete cptr;
|
||||
});
|
||||
}
|
||||
|
||||
void DBBrowserDB::collationNeeded(void* /*pData*/, sqlite3* /*db*/, int eTextRep, const char* sCollationName)
|
||||
{
|
||||
QString name(sCollationName);
|
||||
@@ -168,6 +187,19 @@ bool DBBrowserDB::open(const QString& db, bool readOnly)
|
||||
if(Settings::getValue("extensions", "disableregex").toBool() == false)
|
||||
sqlite3_create_function(_db, "REGEXP", 2, SQLITE_UTF8, nullptr, regexp, nullptr, nullptr);
|
||||
|
||||
// Register our internal helper function for putting multiple values into a single column
|
||||
sqlite3_create_function_v2(
|
||||
_db,
|
||||
"sqlb_make_single_value",
|
||||
-1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
nullptr,
|
||||
sqlite_make_single_value,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
|
||||
// Check if file is read only. In-memory databases are never read only
|
||||
if(db == ":memory:")
|
||||
{
|
||||
@@ -1144,13 +1176,13 @@ bool DBBrowserDB::getRow(const sqlb::ObjectIdentifier& table, const QString& row
|
||||
QString sQuery = QString("SELECT * FROM %1 WHERE ")
|
||||
.arg(table.toString());
|
||||
|
||||
// For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use json_array to decode the composed rowid values.
|
||||
// For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values.
|
||||
QStringList pks = getObjectByName<sqlb::Table>(table)->rowidColumns();
|
||||
if(pks.size() == 1)
|
||||
{
|
||||
sQuery += QString("%1='%2;").arg(sqlb::escapeIdentifier(pks.front())).arg(rowid);
|
||||
} else {
|
||||
sQuery += QString("json_array(%1)='%2';")
|
||||
sQuery += QString("sqlb_make_single_value(%1)='%2';")
|
||||
.arg(sqlb::escapeIdentifier(pks).join(","))
|
||||
.arg(QString(rowid).replace("'", "''"));
|
||||
}
|
||||
@@ -1317,7 +1349,7 @@ bool DBBrowserDB::deleteRecords(const sqlb::ObjectIdentifier& table, const QStri
|
||||
quoted_rowids.append("'" + rowid.replace("'", "''") + "'");
|
||||
|
||||
// For a single rowid column we can use a SELECT ... IN(...) statement which is faster.
|
||||
// For multiple rowid columns we have to use json_array to decode the composed rowid values.
|
||||
// For multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values.
|
||||
QString statement;
|
||||
if(pks.size() == 1)
|
||||
{
|
||||
@@ -1328,7 +1360,7 @@ bool DBBrowserDB::deleteRecords(const sqlb::ObjectIdentifier& table, const QStri
|
||||
} else {
|
||||
statement = QString("DELETE FROM %1 WHERE ").arg(table.toString());
|
||||
|
||||
statement += "json_array(";
|
||||
statement += "sqlb_make_single_value(";
|
||||
for(const auto& pk : pks)
|
||||
statement += sqlb::escapeIdentifier(pk) + ",";
|
||||
statement.chop(1);
|
||||
@@ -1362,14 +1394,14 @@ bool DBBrowserDB::updateRecord(const sqlb::ObjectIdentifier& table, const QStrin
|
||||
.arg(table.toString())
|
||||
.arg(sqlb::escapeIdentifier(column));
|
||||
|
||||
// For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use json_array to decode the composed rowid values.
|
||||
// For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values.
|
||||
if(pks.size() == 1)
|
||||
{
|
||||
sql += QString("%1='%2';")
|
||||
.arg(sqlb::escapeIdentifier(pks.first()))
|
||||
.arg(QString(rowid).replace("'", "''"));
|
||||
} else {
|
||||
sql += QString("json_array(%1)='%2';")
|
||||
sql += QString("sqlb_make_single_value(%1)='%2';")
|
||||
.arg(sqlb::escapeIdentifier(pks).join(","))
|
||||
.arg(QString(rowid).replace("'", "''"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user