GCC Code Coverage Report


Directory: libimgdoc2/
File: libimgdoc2/src/db/sqlite/sqlite_DbStatement.cpp
Date: 2025-02-03 12:41:04
Exec Total Coverage
Lines: 75 81 92.6%
Functions: 20 21 95.2%
Branches: 14 36 38.9%

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