From 2bf45ec998620e4d0c8fc557efee8164ff4020cd Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 15 Apr 2021 14:18:26 +0200 Subject: [PATCH] Sqlite: Fix handling of blob and blob views MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I90c31307ff3299975f820e191085ba93ed8afe0f Reviewed-by: Henning Gründl Reviewed-by: Tim Jenssen --- src/libs/sqlite/sqlitebasestatement.cpp | 24 ++++ src/libs/sqlite/sqlitebasestatement.h | 1 + src/libs/sqlite/sqlitevalue.h | 19 ++-- tests/unit/unittest/sqlitestatement-test.cpp | 110 ++++++++++++++++++- tests/unit/unittest/sqlitevalue-test.cpp | 4 +- 5 files changed, 143 insertions(+), 15 deletions(-) diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp index 7f8cd86ab4b..6e60133511a 100644 --- a/src/libs/sqlite/sqlitebasestatement.cpp +++ b/src/libs/sqlite/sqlitebasestatement.cpp @@ -277,6 +277,30 @@ void BaseStatement::bind(int index, const Value &value) case ValueType::String: bind(index, value.toStringView()); break; + case ValueType::Blob: + bind(index, value.toBlobView()); + break; + case ValueType::Null: + bind(index, NullValue{}); + break; + } +} + +void BaseStatement::bind(int index, ValueView value) +{ + switch (value.type()) { + case ValueType::Integer: + bind(index, value.toInteger()); + break; + case ValueType::Float: + bind(index, value.toFloat()); + break; + case ValueType::String: + bind(index, value.toStringView()); + break; + case ValueType::Blob: + bind(index, value.toBlobView()); + break; case ValueType::Null: bind(index, NullValue{}); break; diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h index 08fb7ed0ed0..9f40be17060 100644 --- a/src/libs/sqlite/sqlitebasestatement.h +++ b/src/libs/sqlite/sqlitebasestatement.h @@ -91,6 +91,7 @@ public: void bind(int index, Utils::span values); void bind(int index, Utils::SmallStringView value); void bind(int index, const Value &value); + void bind(int index, ValueView value); void bind(int index, BlobView blobView); void bind(int index, uint value) { bind(index, static_cast(value)); } diff --git a/src/libs/sqlite/sqlitevalue.h b/src/libs/sqlite/sqlitevalue.h index 220d8d1e063..2ad97d7613d 100644 --- a/src/libs/sqlite/sqlitevalue.h +++ b/src/libs/sqlite/sqlitevalue.h @@ -44,11 +44,11 @@ class NullValue friend bool operator==(NullValue, NullValue) { return false; } }; -template +template class ValueBase { public: - using VariantType = Utils::variant; + using VariantType = Utils::variant; ValueBase() = default; @@ -115,9 +115,12 @@ public: BlobView toBlobView() const { - const Blob &blob = Utils::get(value); - - return {blob.bytes}; + const BlobType &blob = Utils::get(value); + if constexpr (std::is_same_v) { + return {blob.bytes}; + } else { + return blob; + } } explicit operator QVariant() const { @@ -245,7 +248,7 @@ public: VariantType value; }; -class ValueView : public ValueBase +class ValueView : public ValueBase { public: explicit ValueView(ValueBase &&base) @@ -259,9 +262,9 @@ public: } }; -class Value : public ValueBase +class Value : public ValueBase { - using Base = ValueBase; + using Base = ValueBase; public: using Base::Base; diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index c526cc3d4bc..ec59e1b4909 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -38,6 +38,7 @@ #include #include +#include #include namespace { @@ -50,6 +51,21 @@ using Sqlite::ReadWriteStatement; using Sqlite::Value; using Sqlite::WriteStatement; +template +bool compareValue(SqliteTestStatement &statement, Type value, int column) +{ + if constexpr (std::is_convertible_v && !std::is_same_v) + return statement.fetchLongLongValue(column) == value; + else if constexpr (std::is_convertible_v) + return statement.fetchDoubleValue(column) == value; + else if constexpr (std::is_convertible_v) + return statement.fetchSmallStringViewValue(column) == value; + else if constexpr (std::is_convertible_v) + return statement.fetchBlobValue(column) == value; + + return false; +} + MATCHER_P3(HasValues, value1, value2, rowid, std::string(negation ? "isn't" : "is") + PrintToString(value1) @@ -64,8 +80,7 @@ MATCHER_P3(HasValues, value1, value2, rowid, statement.next(); - return statement.fetchSmallStringViewValue(0) == value1 - && statement.fetchSmallStringViewValue(1) == value2; + return compareValue(statement, value1, 0) && compareValue(statement, value2, 1); } MATCHER_P(HasNullValues, rowid, std::string(negation ? "isn't null" : "is null")) @@ -490,13 +505,98 @@ TEST_F(SqliteStatement, WriteNullValues) ASSERT_THAT(statement, HasNullValues(1)); } -TEST_F(SqliteStatement, WriteSqliteValues) +TEST_F(SqliteStatement, WriteSqliteIntegerValue) +{ + WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + statement.write(1, 1, 1); + + statement.write("see", Sqlite::Value{33}, 1); + + ASSERT_THAT(statement, HasValues("see", 33, 1)); +} + +TEST_F(SqliteStatement, WriteSqliteDoubeValue) { WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); - statement.write(Value{"see"}, Value{7.23}, Value{1}); + statement.write("see", Value{7.23}, Value{1}); - ASSERT_THAT(statement, HasValues("see", "7.23", 1)); + ASSERT_THAT(statement, HasValues("see", 7.23, 1)); +} + +TEST_F(SqliteStatement, WriteSqliteStringValue) +{ + WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + + statement.write("see", Value{"foo"}, Value{1}); + + ASSERT_THAT(statement, HasValues("see", "foo", 1)); +} + +TEST_F(SqliteStatement, WriteSqliteBlobValue) +{ + SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database); + SqliteTestStatement readStatement("SELECT value FROM test WHERE name = 'blob'", database); + const unsigned char chars[] = "aaafdfdlll"; + auto bytePointer = reinterpret_cast(chars); + Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; + + statement.write(Sqlite::Value{bytes}); + + ASSERT_THAT(readStatement.template value(), + Optional(Field(&Sqlite::Blob::bytes, Eq(bytes)))); +} + +TEST_F(SqliteStatement, WriteNullValueView) +{ + WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + statement.write(1, 1, 1); + + statement.write(Sqlite::NullValue{}, Sqlite::ValueView::create(Sqlite::NullValue{}), 1); + + ASSERT_THAT(statement, HasNullValues(1)); +} + +TEST_F(SqliteStatement, WriteSqliteIntegerValueView) +{ + WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + statement.write(1, 1, 1); + + statement.write("see", Sqlite::ValueView::create(33), 1); + + ASSERT_THAT(statement, HasValues("see", 33, 1)); +} + +TEST_F(SqliteStatement, WriteSqliteDoubeValueView) +{ + WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + + statement.write("see", Sqlite::ValueView::create(7.23), 1); + + ASSERT_THAT(statement, HasValues("see", 7.23, 1)); +} + +TEST_F(SqliteStatement, WriteSqliteStringValueView) +{ + WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + + statement.write("see", Sqlite::ValueView::create("foo"), 1); + + ASSERT_THAT(statement, HasValues("see", "foo", 1)); +} + +TEST_F(SqliteStatement, WriteSqliteBlobValueView) +{ + SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database); + SqliteTestStatement readStatement("SELECT value FROM test WHERE name = 'blob'", database); + const unsigned char chars[] = "aaafdfdlll"; + auto bytePointer = reinterpret_cast(chars); + Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; + + statement.write(Sqlite::ValueView::create(bytes)); + + ASSERT_THAT(readStatement.template value(), + Optional(Field(&Sqlite::Blob::bytes, Eq(bytes)))); } TEST_F(SqliteStatement, WriteEmptyBlobs) diff --git a/tests/unit/unittest/sqlitevalue-test.cpp b/tests/unit/unittest/sqlitevalue-test.cpp index 682e8087abb..b36b23e732d 100644 --- a/tests/unit/unittest/sqlitevalue-test.cpp +++ b/tests/unit/unittest/sqlitevalue-test.cpp @@ -445,7 +445,7 @@ TEST(SqliteValue, BlobValueAndValueViewEquals) { Utils::span bytes{reinterpret_cast("abcd"), 4}; - bool isEqual = Sqlite::ValueView::create(bytes) == Sqlite::Value{bytes}; + bool isEqual = Sqlite::ValueView::create(Sqlite::BlobView{bytes}) == Sqlite::Value{bytes}; ASSERT_TRUE(isEqual); } @@ -489,7 +489,7 @@ TEST(SqliteValue, ConvertFloatValueViewIntoValue) TEST(SqliteValue, ConvertBlobValueViewIntoValue) { Utils::span bytes{reinterpret_cast("abcd"), 4}; - auto view = Sqlite::ValueView::create(bytes); + auto view = Sqlite::ValueView::create(Sqlite::BlobView{bytes}); Sqlite::Value value{view};