| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-FileCopyrightText: 2023 Carl Zeiss Microscopy GmbH | ||
| 2 | // | ||
| 3 | // SPDX-License-Identifier: MIT | ||
| 4 | |||
| 5 | #include "sqlite_DbStatement.h" | ||
| 6 | #include <exceptions.h> | ||
| 7 | #include <sstream> | ||
| 8 | |||
| 9 | using namespace std; | ||
| 10 | using namespace imgdoc2; | ||
| 11 | |||
| 12 | 110522 | SqliteDbStatement::SqliteDbStatement(sqlite3_stmt* sql_statement) : | |
| 13 | 110522 | sql_statement_(sql_statement) | |
| 14 | { | ||
| 15 | 110522 | } | |
| 16 | |||
| 17 | 221044 | /*virtual*/SqliteDbStatement::~SqliteDbStatement() | |
| 18 | { | ||
| 19 | // TODO(JBL): check error (-> https://www.sqlite.org/c3ref/finalize.html) | ||
| 20 | 221044 | sqlite3_finalize(this->sql_statement_); | |
| 21 | 221044 | } | |
| 22 | |||
| 23 | ✗ | /*virtual*/void SqliteDbStatement::Reset() | |
| 24 | { | ||
| 25 | ✗ | throw std::logic_error("not implemented"); | |
| 26 | } | ||
| 27 | |||
| 28 | 1776 | /*virtual*/void SqliteDbStatement::BindNull(int index) | |
| 29 | { | ||
| 30 | 1776 | const int return_code = sqlite3_bind_null(this->sql_statement_, index); | |
| 31 | 1776 | this->ThrowIfBindError(return_code, "sqlite3_bind_null"); | |
| 32 | 1776 | } | |
| 33 | |||
| 34 | 291276 | /*virtual*/void SqliteDbStatement::BindInt32(int index, std::int32_t value) | |
| 35 | { | ||
| 36 | 291276 | const int return_code = sqlite3_bind_int(this->sql_statement_, index, value); | |
| 37 | 291276 | this->ThrowIfBindError(return_code, "sqlite3_bind_int"); | |
| 38 | 291276 | } | |
| 39 | |||
| 40 | 67854 | /*virtual*/void SqliteDbStatement::BindInt64(int index, std::int64_t value) | |
| 41 | { | ||
| 42 | 67854 | const int return_code = sqlite3_bind_int64(this->sql_statement_, index, value); | |
| 43 | 67854 | this->ThrowIfBindError(return_code, "sqlite3_bind_int64"); | |
| 44 | 67854 | } | |
| 45 | |||
| 46 | 355622 | /*virtual*/void SqliteDbStatement::BindDouble(int index, double value) | |
| 47 | { | ||
| 48 | 355622 | const int return_code = sqlite3_bind_double(this->sql_statement_, index, value); | |
| 49 | 355622 | this->ThrowIfBindError(return_code, "sqlite3_bind_double"); | |
| 50 | 355622 | } | |
| 51 | |||
| 52 | 1434 | /*virtual*/void SqliteDbStatement::BindString(int index, const char* value) | |
| 53 | { | ||
| 54 | // -1 means: determine length (assuming it is a null-terminated string) | ||
| 55 | // SQLITE_TRANSIENT means: make a copy of the string | ||
| 56 | 1434 | const int return_code = sqlite3_bind_text(this->sql_statement_, index, value, -1, SQLITE_TRANSIENT); | |
| 57 | 1434 | this->ThrowIfBindError(return_code, "sqlite3_bind_text"); | |
| 58 | 1434 | } | |
| 59 | |||
| 60 | 758 | /*virtual*/void SqliteDbStatement::BindStringView(int index, const std::string_view& value) | |
| 61 | { | ||
| 62 | 758 | const int return_code = sqlite3_bind_text(this->sql_statement_, index, value.data(), value.size(), SQLITE_TRANSIENT); | |
| 63 | 758 | this->ThrowIfBindError(return_code, "sqlite3_bind_text"); | |
| 64 | 758 | } | |
| 65 | |||
| 66 | 8 | /*virtual*/void SqliteDbStatement::BindBlob_Static(int index, const void* data, size_t size) | |
| 67 | { | ||
| 68 | 8 | const int return_code = sqlite3_bind_blob64(this->sql_statement_, index, data, size, SQLITE_STATIC); | |
| 69 | 8 | this->ThrowIfBindError(return_code, "sqlite3_bind_blob64"); | |
| 70 | 8 | } | |
| 71 | |||
| 72 | 234596 | /*virtual*/sqlite3_stmt* SqliteDbStatement::GetSqliteSqlStatement() | |
| 73 | { | ||
| 74 | 234596 | return this->sql_statement_; | |
| 75 | } | ||
| 76 | |||
| 77 | 5718 | /*virtual*/std::int32_t SqliteDbStatement::GetResultInt32(int column) | |
| 78 | { | ||
| 79 | 5718 | const std::int32_t value = sqlite3_column_int(this->sql_statement_, column); | |
| 80 | 5718 | return value; | |
| 81 | } | ||
| 82 | |||
| 83 | 28 | /*virtual*/std::optional<std::int32_t> SqliteDbStatement::GetResultInt32OrNull(int column) | |
| 84 | { | ||
| 85 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | int32_t result = this->GetResultInt32(column); |
| 86 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
|
28 | if (result == 0) |
| 87 | { | ||
| 88 | // a value of 0 **could** mean that we actually read a NULL (and it got coalesced into a 0) -> https://www.sqlite.org/c3ref/column_blob.html | ||
| 89 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | if (sqlite3_column_type(this->sql_statement_, column) == SQLITE_NULL) |
| 90 | { | ||
| 91 | 4 | return {}; | |
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | 24 | return result; | |
| 96 | } | ||
| 97 | |||
| 98 | 7776 | /*virtual*/std::int64_t SqliteDbStatement::GetResultInt64(int column) | |
| 99 | { | ||
| 100 | 7776 | const int64_t value = sqlite3_column_int64(this->sql_statement_, column); | |
| 101 | 7776 | return value; | |
| 102 | } | ||
| 103 | |||
| 104 | 108 | /*virtual*/double SqliteDbStatement::GetResultDouble(int column) | |
| 105 | { | ||
| 106 | 108 | const double value = sqlite3_column_double(this->sql_statement_, column); | |
| 107 | 108 | return value; | |
| 108 | } | ||
| 109 | |||
| 110 | 64 | /*virtual*/std::optional<double> SqliteDbStatement::GetResultDoubleOrNull(int column) | |
| 111 | { | ||
| 112 |
1/2✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
|
64 | const auto result = this->GetResultDouble(column); |
| 113 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 40 times.
|
64 | if (result == 0.0) |
| 114 | { | ||
| 115 | // a value of 0 **could** mean that we actually read a NULL (and it got coalesced into a 0) -> https://www.sqlite.org/c3ref/column_blob.html | ||
| 116 |
3/4✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 16 times.
|
24 | if (sqlite3_column_type(this->sql_statement_, column) == SQLITE_NULL) |
| 117 | { | ||
| 118 | 8 | return {}; | |
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | 56 | return result; | |
| 123 | } | ||
| 124 | |||
| 125 | 20 | /*virtual*/std::uint32_t SqliteDbStatement::GetResultUInt32(int column) | |
| 126 | { | ||
| 127 | 20 | const uint32_t value = static_cast<uint32_t>(sqlite3_column_int(this->sql_statement_, column)); | |
| 128 | 20 | return value; | |
| 129 | } | ||
| 130 | |||
| 131 | 8 | /*virtual*/std::uint8_t SqliteDbStatement::GetResultUInt8(int column) | |
| 132 | { | ||
| 133 | 8 | const uint8_t value = static_cast<uint8_t>(sqlite3_column_int(this->sql_statement_, column)); | |
| 134 | 8 | return value; | |
| 135 | } | ||
| 136 | |||
| 137 | 4 | /*virtual*/void SqliteDbStatement::GetResultBlob(int column, imgdoc2::IBlobOutput* blobOutput) | |
| 138 | { | ||
| 139 | 4 | int size_of_blob = sqlite3_column_bytes(this->sql_statement_, column); | |
| 140 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | if (blobOutput->Reserve(size_of_blob)) |
| 141 | { | ||
| 142 | 4 | const void* ptr_data = sqlite3_column_blob(this->sql_statement_, column); | |
| 143 | 4 | blobOutput->SetData(0, size_of_blob, ptr_data); | |
| 144 | } | ||
| 145 | 4 | } | |
| 146 | |||
| 147 | 1250 | /*virtual*/std::string SqliteDbStatement::GetResultString(int column) | |
| 148 | { | ||
| 149 | // TODO(JBL): this method is creating a copy of the string, it might be a good idea to have a method | ||
| 150 | // which returns a "dangereous pointer" | ||
| 151 | 1250 | const unsigned char* str = sqlite3_column_text(this->sql_statement_, column); | |
| 152 | |||
| 153 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) no way (I can see) to prevent the reinterpret_cast here | ||
| 154 |
1/2✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
|
3750 | return string{ reinterpret_cast<const char*>(str) }; |
| 155 | } | ||
| 156 | |||
| 157 | 718728 | void SqliteDbStatement::ThrowIfBindError(int error_code, const char* function_name) | |
| 158 | { | ||
| 159 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 718728 times.
|
718728 | if (error_code != SQLITE_OK) |
| 160 | { | ||
| 161 | // TODO(JBL) : not exactly sure which error to throw | ||
| 162 | // https://www.sqlite.org/c3ref/bind_blob.html | ||
| 163 | ✗ | ostringstream string_stream; | |
| 164 | ✗ | string_stream << "Error binding a value (with function \"" << function_name << "\")."; | |
| 165 | ✗ | throw database_exception(string_stream.str().c_str(), error_code); | |
| 166 | ✗ | } | |
| 167 | 718728 | } | |
| 168 |