diff --git a/src/libs/sqlite/CMakeLists.txt b/src/libs/sqlite/CMakeLists.txt index 888945b1be2..c30899a5c59 100644 --- a/src/libs/sqlite/CMakeLists.txt +++ b/src/libs/sqlite/CMakeLists.txt @@ -32,6 +32,7 @@ add_qtc_library(Sqlite sqlitedatabaseinterface.h sqliteexception.cpp sqliteexception.h sqliteglobal.cpp sqliteglobal.h + sqlitefunctionregistry.cpp sqlitefunctionregistry.h sqliteindex.h sqliteprogresshandler.h sqlitereadstatement.h diff --git a/src/libs/sqlite/sqlitefunctionregistry.cpp b/src/libs/sqlite/sqlitefunctionregistry.cpp new file mode 100644 index 00000000000..c2cb6a696a1 --- /dev/null +++ b/src/libs/sqlite/sqlitefunctionregistry.cpp @@ -0,0 +1,50 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "sqlitefunctionregistry.h" + +#include "sqlite.h" + +#include + +namespace { +extern "C" { +void pathExists(sqlite3_context *context, int, sqlite3_value **arguments) +{ + auto argument = arguments[0]; + + auto errorText = "pathExists only accepts text"; + + if (sqlite3_value_type(argument) != SQLITE_TEXT) { + sqlite3_result_error(context, errorText, int(std::char_traits::length(errorText))); + return; + } + + auto size = sqlite3_value_bytes(argument); + + auto content = QByteArrayView{sqlite3_value_text(argument), size}; + + QString path = QString::fromUtf8(content); + + bool exists = QFileInfo::exists(path); + + sqlite3_result_int(context, exists); +} +} +} // namespace + +namespace Sqlite::FunctionRegistry { + +void registerPathExists(Sqlite::Database &database) +{ + sqlite3_create_function(database.backend().sqliteDatabaseHandle(), + "pathExists", + 1, + SQLITE_UTF8 | SQLITE_INNOCUOUS, + nullptr, + pathExists, + nullptr, + nullptr); +} + +} // namespace Sqlite::FunctionRegistry diff --git a/src/libs/sqlite/sqlitefunctionregistry.h b/src/libs/sqlite/sqlitefunctionregistry.h new file mode 100644 index 00000000000..ccf8152ecf2 --- /dev/null +++ b/src/libs/sqlite/sqlitefunctionregistry.h @@ -0,0 +1,12 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Sqlite::FunctionRegistry { + +SQLITE_EXPORT void registerPathExists(Sqlite::Database &database); + +} // namespace Sqlite::FunctionRegistry diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt index 5b0ae081c28..22065f4f565 100644 --- a/tests/unit/unittest/CMakeLists.txt +++ b/tests/unit/unittest/CMakeLists.txt @@ -73,6 +73,7 @@ add_qtc_test(unittest GTEST sqlitecolumn-test.cpp sqlitedatabasebackend-test.cpp sqlitedatabase-test.cpp + sqlitefunctionregistry-test.cpp sqlitesessions-test.cpp sqlitestatement-test.cpp sqlitetable-test.cpp diff --git a/tests/unit/unittest/sqlitefunctionregistry-test.cpp b/tests/unit/unittest/sqlitefunctionregistry-test.cpp new file mode 100644 index 00000000000..de9a566fd50 --- /dev/null +++ b/tests/unit/unittest/sqlitefunctionregistry-test.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "googletest.h" + +#include + +namespace { + +class SqliteFunctionRegistry : public testing::Test +{ +public: + SqliteFunctionRegistry() { Sqlite::FunctionRegistry::registerPathExists(database); } + +protected: + Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; +}; + +TEST_F(SqliteFunctionRegistry, PathExists) +{ + std::lock_guard lock{database}; + Sqlite::ReadStatement<1> statement{"SELECT pathExists('" TESTDATA_DIR "/sqlite_database.db')", + database}; + + auto pathExists = statement.value(); + + ASSERT_TRUE(pathExists); +} + +TEST_F(SqliteFunctionRegistry, PathDoesntExists) +{ + std::lock_guard lock{database}; + Sqlite::ReadStatement<1> statement{"SELECT pathExists('" TESTDATA_DIR "/sqlite_database2.db')", + database}; + + auto pathExists = statement.value(); + + ASSERT_FALSE(pathExists); +} + +} // namespace