diff --git a/sqliter/sqliter.cpp b/sqliter/sqliter.cpp --- a/sqliter/sqliter.cpp +++ b/sqliter/sqliter.cpp @@ -1,6 +1,65 @@ #include "sqliter.h" +#include +#include + +bool Sqliter::install(QVariant a_driverHandle) +{ + if (!a_driverHandle.isValid() || qstrcmp(a_driverHandle.typeName(), "sqlite3*") != 0) + return false; + + sqlite3* db = *static_cast(a_driverHandle.data()); + + if (!db) + return false; + + if (SQLITE_OK != sqlite3_create_function(db, "upper", 1, SQLITE_UTF16 | SQLITE_DETERMINISTIC, + nullptr, Sqliter::upper, nullptr, nullptr)) + return false; + + if (SQLITE_OK != sqlite3_create_function(db, "lower", 1, SQLITE_UTF16 | SQLITE_DETERMINISTIC, + nullptr, Sqliter::lower, nullptr, nullptr)) + return false; + + return true; +} -Sqliter::Sqliter() +void Sqliter::upper(sqlite3_context* context, int argc, sqlite3_value** argv) { + static QString result; + switch (sqlite3_value_type(argv[0])) + { + case SQLITE_TEXT: + result = QString::fromUtf16(static_cast(sqlite3_value_text16(argv[0]))).toUpper(); + sqlite3_result_text16(context, result.data(), -1, nullptr); + break; + + case SQLITE_NULL: + sqlite3_result_null(context); + break; + + default: + sqlite3_result_error_code(context, SQLITE_MISMATCH); + } + Q_UNUSED(argc); } + +void Sqliter::lower(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + static QString result; + switch (sqlite3_value_type(argv[0])) + { + case SQLITE_TEXT: + result = QString::fromUtf16(static_cast(sqlite3_value_text16(argv[0]))).toLower(); + sqlite3_result_text16(context, result.data(), -1, nullptr); + break; + + case SQLITE_NULL: + sqlite3_result_null(context); + break; + + default: + sqlite3_result_error_code(context, SQLITE_MISMATCH); + } + Q_UNUSED(argc); +} diff --git a/sqliter/sqliter.h b/sqliter/sqliter.h --- a/sqliter/sqliter.h +++ b/sqliter/sqliter.h @@ -1,13 +1,21 @@ #ifndef SQLITER_H #define SQLITER_H #include "sqliter_global.h" +#include + +struct sqlite3_context; +struct sqlite3_value; class SQLITERSHARED_EXPORT Sqliter { +public: + static bool install(QVariant a_driverHandle); -public: - Sqliter(); +private: + Sqliter() = default; + static void upper(sqlite3_context* a_context, int a_argc, sqlite3_value** a_argv); + static void lower(sqlite3_context* a_context, int a_argc, sqlite3_value** a_argv); }; #endif // SQLITER_H diff --git a/sqliter/sqliter.pro b/sqliter/sqliter.pro --- a/sqliter/sqliter.pro +++ b/sqliter/sqliter.pro @@ -1,35 +1,37 @@ #------------------------------------------------- # # Project created by QtCreator 2018-03-22T16:38:23 # #------------------------------------------------- QT -= gui TARGET = sqliter TEMPLATE = lib DEFINES += SQLITER_LIBRARY # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +LIBS += -lsqlite3 + SOURCES += \ sqliter.cpp HEADERS += \ sqliter.h \ sqliter_global.h unix { target.path = /usr/lib INSTALLS += target } diff --git a/tests/sqrtest.cpp b/tests/sqrtest.cpp --- a/tests/sqrtest.cpp +++ b/tests/sqrtest.cpp @@ -1,100 +1,127 @@ #include +#include +#include #include #include #include +#include "sqliter.h" + class SqliterTest : public QObject { Q_OBJECT public: SqliterTest() = default; private Q_SLOTS: void initTestCase(); void testUpperDefault(); void testLowerDefault(); + void installSqliter(); void testUpperR(); void testLowerR(); }; void SqliterTest::initTestCase() { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(":memory:"); QVERIFY(db.open()); QSqlQuery q; QVERIFY(q.exec("CREATE TABLE tt1 (id INTEGER PRIMARY KEY, t TEXT)")); QVERIFY(db.transaction()); + QVERIFY(q.exec(QStringLiteral("INSERT INTO tt1 (id, t) VALUES (0, NULL)"))); QVERIFY(q.exec(QStringLiteral("INSERT INTO tt1 (id, t) VALUES (1, 'One')"))); QVERIFY(q.exec(QStringLiteral("INSERT INTO tt1 (id, t) VALUES (2, 'two')"))); QVERIFY(q.exec(QStringLiteral("INSERT INTO tt1 (id, t) VALUES (3, 'THREE')"))); QVERIFY(q.exec(QStringLiteral("INSERT INTO tt1 (id, t) VALUES (4, 'Четыре')"))); QVERIFY(q.exec(QStringLiteral("INSERT INTO tt1 (id, t) VALUES (5, 'пять')"))); QVERIFY(q.exec(QStringLiteral("INSERT INTO tt1 (id, t) VALUES (6, 'ШЕСТЬ')"))); QVERIFY(db.commit()); } void SqliterTest::testUpperDefault() { QStringList list; QSqlQuery q; QVERIFY(q.exec("SELECT UPPER(t) FROM tt1 ORDER BY id")); + + q.next(); + QVERIFY(q.value(0).isNull()); + while (q.next()) list.append(q.value(0).toString()); QVERIFY(list[0] == "ONE"); QVERIFY(list[1] == "TWO"); QVERIFY(list[2] == "THREE"); QVERIFY(list[3] == "Четыре"); QVERIFY(list[4] == "пять"); QVERIFY(list[5] == "ШЕСТЬ"); } void SqliterTest::testLowerDefault() { QStringList list; QSqlQuery q; QVERIFY(q.exec("SELECT LOWER(t) FROM tt1 ORDER BY id")); + + q.next(); + QVERIFY(q.value(0).isNull()); + while (q.next()) list.append(q.value(0).toString()); QVERIFY(list[0] == "one"); QVERIFY(list[1] == "two"); QVERIFY(list[2] == "three"); QVERIFY(list[3] == "Четыре"); QVERIFY(list[4] == "пять"); QVERIFY(list[5] == "ШЕСТЬ"); } +void SqliterTest::installSqliter() +{ + QVERIFY(Sqliter::install(QSqlDatabase::database().driver()->handle())); +} + void SqliterTest::testUpperR() { QStringList list; QSqlQuery q; QVERIFY(q.exec("SELECT UPPER(t) FROM tt1 ORDER BY id")); + + q.next(); + QVERIFY(q.value(0).isNull()); + while (q.next()) list.append(q.value(0).toString()); QVERIFY(list[0] == "ONE"); QVERIFY(list[1] == "TWO"); QVERIFY(list[2] == "THREE"); QVERIFY(list[3] == "ЧЕТЫРЕ"); QVERIFY(list[4] == "ПЯТЬ"); QVERIFY(list[5] == "ШЕСТЬ"); } void SqliterTest::testLowerR() { QStringList list; QSqlQuery q; QVERIFY(q.exec("SELECT LOWER(t) FROM tt1 ORDER BY id")); + + q.next(); + QVERIFY(q.value(0).isNull()); + while (q.next()) list.append(q.value(0).toString()); QVERIFY(list[0] == "one"); QVERIFY(list[1] == "two"); QVERIFY(list[2] == "three"); QVERIFY(list[3] == "четыре"); QVERIFY(list[4] == "пять"); QVERIFY(list[5] == "шесть"); } QTEST_APPLESS_MAIN(SqliterTest) #include "sqrtest.moc" diff --git a/tests/tests.pro b/tests/tests.pro --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,32 +1,42 @@ #------------------------------------------------- # # Project created by QtCreator 2018-03-22T16:40:26 # #------------------------------------------------- TEMPLATE = app TARGET = sqrtest QT += testlib sql QT -= gui CONFIG += console CONFIG -= app_bundle - +CONFIG(staticlib): DEFINES += SQLITER_STATIC # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 -SOURCES += \ - sqrtest.cpp +SOURCES += sqrtest.cpp DEFINES += SRCDIR=\\\"$$PWD/\\\" + +win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../sqliter/release/ +else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../sqliter/debug/ +else:mac:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../sqliter/debug/ +else:unix: LIBS += -L$$OUT_PWD/../sqliter/ +LIBS += -lsqliter + +INCLUDEPATH += $$PWD/../sqliter +DEPENDPATH += $$PWD/../sqliter + +INSTALLS -= target