1 |
|
|
/** |
2 |
|
|
* This file is part of the CernVM file system. |
3 |
|
|
*/ |
4 |
|
|
|
5 |
|
|
#include "cvmfs_config.h" |
6 |
|
|
#include "sql.h" |
7 |
|
|
|
8 |
|
|
#include "logging.h" |
9 |
|
|
#include "util/string.h" |
10 |
|
|
|
11 |
|
|
using namespace std; // NOLINT |
12 |
|
|
|
13 |
|
|
namespace sqlite { |
14 |
|
|
|
15 |
|
2844 |
Sql::Sql(sqlite3 *sqlite_db, const std::string &statement) |
16 |
|
|
: database_(NULL) |
17 |
|
|
, statement_(NULL) |
18 |
|
|
, query_string_(NULL) |
19 |
|
2844 |
, last_error_code_(0) |
20 |
|
|
{ |
21 |
|
2844 |
Init(sqlite_db, statement); |
22 |
|
2844 |
} |
23 |
|
|
|
24 |
|
|
|
25 |
|
8464 |
Sql::~Sql() { |
26 |
|
6634 |
last_error_code_ = sqlite3_finalize(statement_); |
27 |
|
|
|
28 |
✓✓ |
6634 |
if (!Successful()) { |
29 |
|
|
LogCvmfs(kLogSql, kLogDebug, |
30 |
|
6 |
"failed to finalize statement - error code: %d", last_error_code_); |
31 |
|
|
} |
32 |
|
6634 |
LogCvmfs(kLogSql, kLogDebug, "successfully finalized statement"); |
33 |
✗✓ |
8464 |
} |
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 |
|
159272 |
bool Sql::Execute() { |
42 |
|
159272 |
LazyInit(); |
43 |
|
159272 |
last_error_code_ = sqlite3_step(statement_); |
44 |
|
|
#ifdef DEBUGMSG |
45 |
✓✓ |
159272 |
if (!Successful()) { |
46 |
|
|
LogCvmfs(kLogSql, kLogDebug, "SQL query failed - SQLite: %d - %s", |
47 |
|
6 |
GetLastError(), GetLastErrorMsg().c_str()); |
48 |
|
|
} |
49 |
|
|
#endif |
50 |
|
159272 |
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 neccessarily 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 |
|
8124 |
bool Sql::FetchRow() { |
62 |
|
8124 |
LazyInit(); |
63 |
|
8124 |
last_error_code_ = sqlite3_step(statement_); |
64 |
|
8124 |
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) line += " | "; |
82 |
|
|
} |
83 |
|
|
result += line + "\n"; |
84 |
|
|
line.clear(); |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
// retrieve the data fields for each row |
88 |
|
|
for (unsigned int col = 0; col < cols; ++col) { |
89 |
|
|
const int type = sqlite3_column_type(statement_, col); |
90 |
|
|
switch (type) { |
91 |
|
|
case SQLITE_INTEGER: |
92 |
|
|
line += StringifyInt(RetrieveInt64(col)); |
93 |
|
|
break; |
94 |
|
|
case SQLITE_FLOAT: |
95 |
|
|
line += StringifyDouble(RetrieveDouble(col)); |
96 |
|
|
break; |
97 |
|
|
case SQLITE_TEXT: |
98 |
|
|
line += reinterpret_cast<const char *>(RetrieveText(col)); |
99 |
|
|
break; |
100 |
|
|
case SQLITE_BLOB: |
101 |
|
|
line += "[BLOB data]"; |
102 |
|
|
break; |
103 |
|
|
case SQLITE_NULL: |
104 |
|
|
line += "[NULL]"; |
105 |
|
|
break; |
106 |
|
|
} |
107 |
|
|
if (col + 1 < cols) line += " | "; |
108 |
|
|
} |
109 |
|
|
|
110 |
|
|
result += line + "\n"; |
111 |
|
|
line.clear(); |
112 |
|
|
++rows; |
113 |
|
|
} |
114 |
|
|
|
115 |
|
|
// print the result |
116 |
|
|
result += "Retrieved Rows: " + StringifyInt(rows); |
117 |
|
|
return result; |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
|
121 |
|
|
/** |
122 |
|
|
* Reset a prepared statement to make it reusable. |
123 |
|
|
* @return true on success otherwise false |
124 |
|
|
*/ |
125 |
|
162401 |
bool Sql::Reset() { |
126 |
|
162401 |
last_error_code_ = sqlite3_reset(statement_); |
127 |
|
162401 |
return Successful(); |
128 |
|
|
} |
129 |
|
|
|
130 |
|
|
|
131 |
|
3535 |
bool Sql::Init(const sqlite3 *database, const std::string &statement) { |
132 |
|
3535 |
database_ = const_cast<sqlite3 *>(database); |
133 |
|
3535 |
return Init(statement.c_str()); |
134 |
|
|
} |
135 |
|
|
|
136 |
|
4092 |
bool Sql::Init(const char *statement) { |
137 |
✗✓ |
4092 |
assert(NULL == statement_); |
138 |
✗✓ |
4092 |
assert(NULL != database_); |
139 |
|
|
|
140 |
|
|
last_error_code_ = sqlite3_prepare_v2(database_, |
141 |
|
|
statement, |
142 |
|
|
-1, // parse until null termination |
143 |
|
|
&statement_, |
144 |
|
4092 |
NULL); |
145 |
|
|
|
146 |
✗✓ |
4092 |
if (!Successful()) { |
147 |
|
|
LogCvmfs(kLogSql, kLogDebug, "failed to prepare statement '%s' (%d: %s)", |
148 |
|
|
statement, GetLastError(), sqlite3_errmsg(database_)); |
149 |
|
|
return false; |
150 |
|
|
} |
151 |
|
|
|
152 |
|
|
LogCvmfs(kLogSql, kLogDebug, "successfully prepared statement '%s'", |
153 |
|
4092 |
statement); |
154 |
|
4092 |
return true; |
155 |
|
|
} |
156 |
|
|
|
157 |
|
3110 |
void Sql::DeferredInit(const sqlite3 *database, const char *statement) { |
158 |
✗✓ |
3110 |
assert(NULL == database_); |
159 |
|
3110 |
database_ = const_cast<sqlite3 *>(database); |
160 |
|
3110 |
query_string_ = statement; |
161 |
|
3110 |
} |
162 |
|
|
|
163 |
|
6 |
std::string Sql::GetLastErrorMsg() const { |
164 |
|
6 |
std::string msg = sqlite3_errmsg(database_); |
165 |
|
6 |
return msg; |
166 |
|
|
} |
167 |
|
|
|
168 |
|
|
} // namespace sqlite |