| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/sql.cc |
| Date: | 2025-11-02 02:35:35 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 46 | 87 | 52.9% |
| Branches: | 12 | 86 | 14.0% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * This file is part of the CernVM file system. | ||
| 3 | */ | ||
| 4 | |||
| 5 | |||
| 6 | #include "sql.h" | ||
| 7 | |||
| 8 | #include "util/logging.h" | ||
| 9 | #include "util/string.h" | ||
| 10 | |||
| 11 | using namespace std; // NOLINT | ||
| 12 | |||
| 13 | namespace sqlite { | ||
| 14 | |||
| 15 | 105431 | Sql::Sql(sqlite3 *sqlite_db, const std::string &statement) | |
| 16 | 105431 | : database_(NULL) | |
| 17 | 105431 | , statement_(NULL) | |
| 18 | 105431 | , query_string_(NULL) | |
| 19 | 105431 | , last_error_code_(0) { | |
| 20 | 105431 | const bool success = Init(sqlite_db, statement); | |
| 21 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 105431 times.
|
105431 | assert(success); |
| 22 | 105431 | } | |
| 23 | |||
| 24 | |||
| 25 | 667090 | Sql::~Sql() { | |
| 26 | 529140 | last_error_code_ = sqlite3_finalize(statement_); | |
| 27 | |||
| 28 |
2/2✓ Branch 1 taken 264 times.
✓ Branch 2 taken 264306 times.
|
529140 | if (!Successful()) { |
| 29 | 528 | LogCvmfs(kLogSql, kLogDebug, | |
| 30 | "failed to finalize statement - error code: %d", last_error_code_); | ||
| 31 | } | ||
| 32 | 529140 | LogCvmfs(kLogSql, kLogDebug, "successfully finalized statement"); | |
| 33 | 667090 | } | |
| 34 | |||
| 35 | |||
| 36 | /** | ||
| 37 | * Executes the prepared statement. | ||
| 38 | * (this method should be used for modifying statements like DELETE or INSERT) | ||
| 39 | * @return true on success otherwise false | ||
| 40 | */ | ||
| 41 | 6452718 | bool Sql::Execute() { | |
| 42 | 6452718 | LazyInit(); | |
| 43 | 6452718 | last_error_code_ = sqlite3_step(statement_); | |
| 44 | #ifdef DEBUGMSG | ||
| 45 |
2/2✓ Branch 1 taken 264 times.
✓ Branch 2 taken 6452454 times.
|
6452718 | if (!Successful()) { |
| 46 |
1/2✓ Branch 3 taken 264 times.
✗ Branch 4 not taken.
|
264 | LogCvmfs(kLogSql, kLogDebug, "SQL query failed - SQLite: %d - %s", |
| 47 | 528 | GetLastError(), GetLastErrorMsg().c_str()); | |
| 48 | } | ||
| 49 | #endif | ||
| 50 | 6452718 | return Successful(); | |
| 51 | } | ||
| 52 | |||
| 53 | |||
| 54 | /** | ||
| 55 | * Execute the prepared statement or fetch its next row. | ||
| 56 | * This method is intended to step through the result set. | ||
| 57 | * If it returns false this does not necessarily mean, that the actual | ||
| 58 | * statement execution failed, but that no row was fetched. | ||
| 59 | * @return true if a new row was fetched otherwise false | ||
| 60 | */ | ||
| 61 | 423370 | bool Sql::FetchRow() { | |
| 62 | 423370 | LazyInit(); | |
| 63 | 423370 | last_error_code_ = sqlite3_step(statement_); | |
| 64 | 423370 | return SQLITE_ROW == last_error_code_; | |
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | ✗ | std::string Sql::DebugResultTable() { | |
| 69 | ✗ | std::string line; | |
| 70 | ✗ | std::string result; | |
| 71 | ✗ | unsigned int rows = 0; | |
| 72 | |||
| 73 | // go through all data rows | ||
| 74 | ✗ | while (FetchRow()) { | |
| 75 | // retrieve the table header (once) | ||
| 76 | ✗ | const unsigned int cols = sqlite3_column_count(statement_); | |
| 77 | ✗ | if (rows == 0) { | |
| 78 | ✗ | for (unsigned int col = 0; col < cols; ++col) { | |
| 79 | ✗ | const char *name = sqlite3_column_name(statement_, col); | |
| 80 | ✗ | line += name; | |
| 81 | ✗ | if (col + 1 < cols) | |
| 82 | ✗ | line += " | "; | |
| 83 | } | ||
| 84 | ✗ | result += line + "\n"; | |
| 85 | ✗ | line.clear(); | |
| 86 | } | ||
| 87 | |||
| 88 | // retrieve the data fields for each row | ||
| 89 | ✗ | for (unsigned int col = 0; col < cols; ++col) { | |
| 90 | ✗ | const int type = sqlite3_column_type(statement_, col); | |
| 91 | ✗ | switch (type) { | |
| 92 | ✗ | case SQLITE_INTEGER: | |
| 93 | ✗ | line += StringifyInt(RetrieveInt64(col)); | |
| 94 | ✗ | break; | |
| 95 | ✗ | case SQLITE_FLOAT: | |
| 96 | ✗ | line += StringifyDouble(RetrieveDouble(col)); | |
| 97 | ✗ | break; | |
| 98 | ✗ | case SQLITE_TEXT: | |
| 99 | ✗ | line += reinterpret_cast<const char *>(RetrieveText(col)); | |
| 100 | ✗ | break; | |
| 101 | ✗ | case SQLITE_BLOB: | |
| 102 | ✗ | line += "[BLOB data]"; | |
| 103 | ✗ | break; | |
| 104 | ✗ | case SQLITE_NULL: | |
| 105 | ✗ | line += "[NULL]"; | |
| 106 | ✗ | break; | |
| 107 | } | ||
| 108 | ✗ | if (col + 1 < cols) | |
| 109 | ✗ | line += " | "; | |
| 110 | } | ||
| 111 | |||
| 112 | ✗ | result += line + "\n"; | |
| 113 | ✗ | line.clear(); | |
| 114 | ✗ | ++rows; | |
| 115 | } | ||
| 116 | |||
| 117 | // print the result | ||
| 118 | ✗ | result += "Retrieved Rows: " + StringifyInt(rows); | |
| 119 | ✗ | return result; | |
| 120 | } | ||
| 121 | |||
| 122 | |||
| 123 | /** | ||
| 124 | * Reset a prepared statement to make it reusable. | ||
| 125 | * @return true on success otherwise false | ||
| 126 | */ | ||
| 127 | 6656681 | bool Sql::Reset() { | |
| 128 | 6656681 | last_error_code_ = sqlite3_reset(statement_); | |
| 129 | 6656681 | return Successful(); | |
| 130 | } | ||
| 131 | |||
| 132 | |||
| 133 | 139898 | bool Sql::Init(const sqlite3 *database, const std::string &statement) { | |
| 134 | 139898 | database_ = const_cast<sqlite3 *>(database); | |
| 135 | 139898 | return Init(statement.c_str()); | |
| 136 | } | ||
| 137 | |||
| 138 | 174268 | bool Sql::Init(const char *statement) { | |
| 139 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 174268 times.
|
174268 | assert(NULL == statement_); |
| 140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 174268 times.
|
174268 | assert(NULL != database_); |
| 141 | |||
| 142 | 174268 | last_error_code_ = sqlite3_prepare_v2(database_, | |
| 143 | statement, | ||
| 144 | -1, // parse until null termination | ||
| 145 | &statement_, | ||
| 146 | NULL); | ||
| 147 | |||
| 148 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 174268 times.
|
174268 | if (!Successful()) { |
| 149 | ✗ | LogCvmfs(kLogSql, kLogDebug, "failed to prepare statement '%s' (%d: %s)", | |
| 150 | statement, GetLastError(), sqlite3_errmsg(database_)); | ||
| 151 | ✗ | return false; | |
| 152 | } | ||
| 153 | |||
| 154 | 174268 | LogCvmfs(kLogSql, kLogDebug, "successfully prepared statement '%s'", | |
| 155 | statement); | ||
| 156 | 174268 | return true; | |
| 157 | } | ||
| 158 | |||
| 159 | 125453 | void Sql::DeferredInit(const sqlite3 *database, const char *statement) { | |
| 160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 125453 times.
|
125453 | assert(NULL == database_); |
| 161 | 125453 | database_ = const_cast<sqlite3 *>(database); | |
| 162 | 125453 | query_string_ = statement; | |
| 163 | 125453 | } | |
| 164 | |||
| 165 | 264 | std::string Sql::GetLastErrorMsg() const { | |
| 166 |
2/4✓ Branch 2 taken 264 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 264 times.
✗ Branch 6 not taken.
|
264 | std::string msg = sqlite3_errmsg(database_); |
| 167 | 264 | return msg; | |
| 168 | } | ||
| 169 | |||
| 170 | } // namespace sqlite | ||
| 171 |