31 : connection_(nullptr)
40 std::string db_path = config.
database.empty() ?
":memory:" : config.
database;
45 sqlite3* db =
nullptr;
48 int result = sqlite3_open(db_path.c_str(), &db);
50 if (result != SQLITE_OK) {
51 last_error_ = std::string(
"Connection failed: ") + sqlite3_errmsg(db);
56 return kcenon::common::error_info{
66 char* error_msg =
nullptr;
67 if (sqlite3_exec(db,
"PRAGMA foreign_keys = ON",
nullptr,
nullptr, &error_msg) != SQLITE_OK) {
68 logger_.warning(std::string(
"Failed to enable foreign key constraints: ") + (error_msg ? error_msg :
""));
69 if (error_msg) sqlite3_free(error_msg);
73 return kcenon::common::ok();
74 }
catch (
const std::exception& e) {
75 last_error_ = std::string(
"Connection error: ") + e.what();
79 logger_.warning(
"SQLite support not compiled. Mock mode enabled.");
82 return kcenon::common::ok();
86 last_error_ =
"Failed to connect to SQLite database";
88 return kcenon::common::error_info{
106 int result = sqlite3_close(db);
108 if (result != SQLITE_OK) {
110 return kcenon::common::error_info{
120 return kcenon::common::ok();
126 sqlite3_stmt* sqlite_stmt =
static_cast<sqlite3_stmt*
>(stmt);
128 int sqlite_type = sqlite3_column_type(sqlite_stmt, column_index);
130 switch (sqlite_type) {
132 return static_cast<int64_t
>(sqlite3_column_int64(sqlite_stmt, column_index));
135 return sqlite3_column_double(sqlite_stmt, column_index);
139 const char* text =
reinterpret_cast<const char*
>(sqlite3_column_text(sqlite_stmt, column_index));
140 return std::string(text ? text :
"");
146 const void* blob = sqlite3_column_blob(sqlite_stmt, column_index);
147 int blob_size = sqlite3_column_bytes(sqlite_stmt, column_index);
148 if (blob && blob_size > 0) {
149 const char* blob_chars =
static_cast<const char*
>(blob);
150 return std::string(blob_chars, blob_size);
152 return std::string();
170 char* error_msg =
nullptr;
172 int result = sqlite3_exec(db, query_string.c_str(),
nullptr,
nullptr, &error_msg);
174 if (result != SQLITE_OK) {
175 last_error_ = std::string(
"Modification query failed: ") + (error_msg ? error_msg :
"Unknown error");
176 logger_.error(
"execute_modification_query",
last_error_);
177 if (error_msg) sqlite3_free(error_msg);
182 return static_cast<unsigned int>(sqlite3_changes(db));
183 }
catch (
const std::exception& e) {
184 last_error_ = std::string(
"Modification query error: ") + e.what();
185 logger_.error(
"execute_modification_query",
last_error_);
188 logger_.warning(
"SQLite support not compiled. Modification query: " + query_string.substr(0, 20) +
"...");
198 return kcenon::common::error_info{
210 return kcenon::common::error_info{
219 sqlite3_stmt* stmt =
nullptr;
222 int prepare_result = sqlite3_prepare_v2(db, query_string.c_str(), -1, &stmt,
nullptr);
223 if (prepare_result != SQLITE_OK) {
224 last_error_ = std::string(
"Prepare failed: ") + sqlite3_errmsg(db);
226 return kcenon::common::error_info{
234 int column_count = sqlite3_column_count(stmt);
235 std::vector<std::string> column_names;
236 for (
int i = 0; i < column_count; i++) {
237 column_names.push_back(sqlite3_column_name(stmt, i));
241 while (sqlite3_step(stmt) == SQLITE_ROW) {
244 for (
int i = 0; i < column_count; i++) {
245 const std::string& column_name = column_names[i];
249 result.push_back(std::move(row));
253 sqlite3_finalize(stmt);
255 }
catch (
const std::exception& e) {
256 last_error_ = std::string(
"Select query error: ") + e.what();
258 return kcenon::common::error_info{
265 logger_.warning(
"SQLite support not compiled. Select query: " + query_string.substr(0, 20) +
"...");
267 if (query_string.find(
"SELECT") != std::string::npos) {
269 mock_row[
"id"] = int64_t(1);
270 mock_row[
"name"] = std::string(
"sqlite_mock_data");
271 mock_row[
"active"] =
true;
272 result.push_back(mock_row);
284 return kcenon::common::error_info{
295 return kcenon::common::error_info{
305 char* error_msg =
nullptr;
306 int result = sqlite3_exec(db, query_string.c_str(),
nullptr,
nullptr, &error_msg);
308 if (result != SQLITE_OK) {
309 last_error_ = std::string(
"Execute error: ") + (error_msg ? error_msg :
"Unknown error");
311 if (error_msg) sqlite3_free(error_msg);
312 return kcenon::common::error_info{
320 return kcenon::common::ok();
323 logger_.info(
"SQLite support not compiled. Mock execute: " + query_string);
325 return kcenon::common::ok();
330 const std::string& query,
331 const std::vector<core::database_value>& params)
335 return kcenon::common::error_info{
347 return kcenon::common::error_info{
356 sqlite3_stmt* stmt =
nullptr;
358 int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt,
nullptr);
359 if (rc != SQLITE_OK) {
360 last_error_ = std::string(
"Prepare error: ") + sqlite3_errmsg(db);
362 return kcenon::common::error_info{
370 for (
size_t i = 0; i < params.size(); ++i) {
371 int bind_idx =
static_cast<int>(i + 1);
372 int bind_rc = SQLITE_OK;
374 std::visit([&bind_rc, stmt, bind_idx](
const auto& v) {
375 using T = std::decay_t<
decltype(v)>;
376 if constexpr (std::is_same_v<T, std::nullptr_t>) {
377 bind_rc = sqlite3_bind_null(stmt, bind_idx);
378 }
else if constexpr (std::is_same_v<T, bool>) {
379 bind_rc = sqlite3_bind_int(stmt, bind_idx, v ? 1 : 0);
380 }
else if constexpr (std::is_same_v<T, int64_t>) {
381 bind_rc = sqlite3_bind_int64(stmt, bind_idx, v);
382 }
else if constexpr (std::is_same_v<T, double>) {
383 bind_rc = sqlite3_bind_double(stmt, bind_idx, v);
384 }
else if constexpr (std::is_same_v<T, std::string>) {
385 bind_rc = sqlite3_bind_text(stmt, bind_idx, v.c_str(),
386 static_cast<int>(v.size()), SQLITE_TRANSIENT);
390 if (bind_rc != SQLITE_OK) {
391 last_error_ = std::string(
"Bind error at param ") + std::to_string(i + 1)
392 +
": " + sqlite3_errmsg(db);
394 sqlite3_finalize(stmt);
395 return kcenon::common::error_info{
404 int col_count = sqlite3_column_count(stmt);
405 while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
407 for (
int col = 0; col < col_count; ++col) {
408 std::string column_name = sqlite3_column_name(stmt, col);
411 result.push_back(std::move(db_row));
414 sqlite3_finalize(stmt);
416 if (rc != SQLITE_DONE) {
417 last_error_ = std::string(
"Step error: ") + sqlite3_errmsg(db);
419 return kcenon::common::error_info{
426 return database_backend::select_prepared(query, params);
434 const std::string& query,
435 const std::vector<core::database_value>& params)
439 return kcenon::common::error_info{
450 return kcenon::common::error_info{
459 sqlite3_stmt* stmt =
nullptr;
461 int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt,
nullptr);
462 if (rc != SQLITE_OK) {
463 last_error_ = std::string(
"Prepare error: ") + sqlite3_errmsg(db);
465 return kcenon::common::error_info{
472 for (
size_t i = 0; i < params.size(); ++i) {
473 int bind_idx =
static_cast<int>(i + 1);
474 int bind_rc = SQLITE_OK;
476 std::visit([&bind_rc, stmt, bind_idx](
const auto& v) {
477 using T = std::decay_t<
decltype(v)>;
478 if constexpr (std::is_same_v<T, std::nullptr_t>) {
479 bind_rc = sqlite3_bind_null(stmt, bind_idx);
480 }
else if constexpr (std::is_same_v<T, bool>) {
481 bind_rc = sqlite3_bind_int(stmt, bind_idx, v ? 1 : 0);
482 }
else if constexpr (std::is_same_v<T, int64_t>) {
483 bind_rc = sqlite3_bind_int64(stmt, bind_idx, v);
484 }
else if constexpr (std::is_same_v<T, double>) {
485 bind_rc = sqlite3_bind_double(stmt, bind_idx, v);
486 }
else if constexpr (std::is_same_v<T, std::string>) {
487 bind_rc = sqlite3_bind_text(stmt, bind_idx, v.c_str(),
488 static_cast<int>(v.size()), SQLITE_TRANSIENT);
492 if (bind_rc != SQLITE_OK) {
493 last_error_ = std::string(
"Bind error at param ") + std::to_string(i + 1)
494 +
": " + sqlite3_errmsg(db);
496 sqlite3_finalize(stmt);
497 return kcenon::common::error_info{
505 rc = sqlite3_step(stmt);
506 sqlite3_finalize(stmt);
508 if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
509 last_error_ = std::string(
"Execute prepared error: ") + sqlite3_errmsg(db);
511 return kcenon::common::error_info{
519 return kcenon::common::ok();
521 return database_backend::execute_prepared(query, params);
529 return kcenon::common::error_info{
538 return kcenon::common::error_info{
546 if (result.is_err()) {
552 return kcenon::common::ok();
559 return kcenon::common::error_info{
568 return kcenon::common::error_info{
576 if (result.is_err()) {
582 return kcenon::common::ok();
589 return kcenon::common::error_info{
598 return kcenon::common::ok();
604 if (result.is_err()) {
609 return kcenon::common::ok();
624 std::map<std::string, std::string> info;
625 info[
"backend"] =
"sqlite";
Centralized logging utility for database backends.
core::database_value convert_sqlite_value(void *stmt, int column_index)
Convert SQLite column value to database_value.
core::connection_config connection_config_
Cached connection config.
kcenon::common::VoidResult do_initialize(const core::connection_config &config)
Database-specific initialization logic.
kcenon::common::VoidResult execute_prepared(const std::string &query, const std::vector< core::database_value > ¶ms) override
Execute a parameterized DML/DDL query (prepared statement)
sqlite_backend()
Default constructor.
kcenon::common::VoidResult rollback_transaction() override
Rollback the current transaction.
std::map< std::string, std::string > connection_info() const override
Get backend-specific connection information.
kcenon::common::VoidResult begin_transaction() override
Begin a transaction.
kcenon::common::VoidResult do_shutdown()
Database-specific shutdown logic.
unsigned int execute_modification_query(const std::string &query_string)
Execute a modification query (INSERT, UPDATE, DELETE)
kcenon::common::Result< core::database_result > select_prepared(const std::string &query, const std::vector< core::database_value > ¶ms) override
Execute a parameterized SELECT query (prepared statement)
kcenon::common::VoidResult commit_transaction() override
Commit the current transaction.
kcenon::common::VoidResult execute_query(const std::string &query_string) override
Execute a general SQL query (DDL, DML)
bool in_transaction() const override
Check if backend is currently in a transaction.
void * connection_
SQLite connection (sqlite3*)
std::string last_error() const override
Get last error message from backend.
kcenon::common::Result< core::database_result > select_query(const std::string &query_string) override
Execute a SELECT query.
std::string last_error_
Last error message.
std::recursive_mutex sqlite_mutex_
Mutex for thread safety.
std::atomic< bool > in_transaction_
Transaction state.
std::atomic< bool > initialized_
bool is_initialized() const override
Helper class for automatic backend registration.
Centralized logging utility for database backends.
std::vector< database_row > database_result
std::map< std::string, database_value > database_row
std::variant< std::string, int64_t, double, bool, std::nullptr_t > database_value
Result<T> type for database_system error handling.
SQLite database backend plugin implementation.
Configuration for database connection.