/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stddef.h>
#include <dpl/db/sql_connection.h>
#include <dpl/db/naive_synchronization_object.h>
-#include <dpl/noncopyable.h>
-#include <dpl/assert.h>
#include <dpl/scoped_ptr.h>
-#include <dpl/TransitoryString.h>
-#include <db-util.h>
#include <unistd.h>
+#include <cassert>
#include <cstdio>
#include <cstdarg>
#include <memory>
+#include <noncopyable.h>
-namespace CKM {
-namespace DB {
-namespace // anonymous
-{
-class ScopedNotifyAll :
- public Noncopyable
-{
- private:
- SqlConnection::SynchronizationObject *m_synchronizationObject;
-
- public:
- explicit ScopedNotifyAll(
- SqlConnection::SynchronizationObject *synchronizationObject) :
- m_synchronizationObject(synchronizationObject)
- {}
- ~ScopedNotifyAll()
- {
- if (!m_synchronizationObject) {
- return;
- }
+namespace {
+const int MAX_RETRY = 10;
+}
- LogPedantic("Notifying after successful synchronize");
- m_synchronizationObject->NotifyAll();
- }
+namespace CKM {
+namespace DB {
+namespace { // anonymous
+class ScopedNotifyAll {
+private:
+ SqlConnection::SynchronizationObject *m_synchronizationObject;
+
+public:
+ NONCOPYABLE(ScopedNotifyAll)
+
+ explicit ScopedNotifyAll(
+ SqlConnection::SynchronizationObject *synchronizationObject) :
+ m_synchronizationObject(synchronizationObject)
+ {
+ }
+
+ ~ScopedNotifyAll()
+ {
+ if (!m_synchronizationObject)
+ return;
+
+ LogPedantic("Notifying after successful synchronize");
+ m_synchronizationObject->NotifyAll();
+ }
};
} // namespace anonymous
SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
- const char *buffer) :
- m_masterConnection(connection),
- m_stmt(NULL)
+ const char *buffer) :
+ m_masterConnection(connection),
+ m_stmt(NULL)
{
- Assert(connection != NULL);
+ assert(connection != NULL);
- // Notify all after potentially synchronized database connection access
- ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
+ // Notify all after potentially synchronized database connection access
+ ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
- for (;;) {
- int ret = sqlcipher3_prepare_v2(connection->m_connection,
- buffer, strlen(buffer),
- &m_stmt, NULL);
+ for (int i = 0; i < MAX_RETRY; i++) {
+ int ret = sqlite3_prepare_v2(connection->m_connection,
+ buffer, strlen(buffer),
+ &m_stmt, NULL);
- if (ret == SQLCIPHER_OK) {
- LogPedantic("Data command prepared successfuly");
- break;
- } else if (ret == SQLCIPHER_BUSY) {
- LogPedantic("Collision occurred while preparing SQL command");
+ if (ret == SQLITE_OK) {
+ LogPedantic("Prepared data command: " << buffer);
- // Synchronize if synchronization object is available
- if (connection->m_synchronizationObject) {
- LogPedantic("Performing synchronization");
- connection->m_synchronizationObject->Synchronize();
- continue;
- }
+ // Increment stored data command count
+ ++m_masterConnection->m_dataCommandsCount;
+ return;
+ } else if (ret == SQLITE_BUSY) {
+ LogPedantic("Collision occurred while preparing SQL command");
- // No synchronization object defined. Fail.
- }
+ // Synchronize if synchronization object is available
+ if (connection->m_synchronizationObject) {
+ LogPedantic("Performing synchronization");
+ connection->m_synchronizationObject->Synchronize();
+ continue;
+ }
- // Fatal error
- const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
+ // No synchronization object defined. Fail.
+ }
- LogPedantic("SQL prepare data command failed");
- LogPedantic(" Statement: " << buffer);
- LogPedantic(" Error: " << error);
+ // Fatal error
+ const char *error = sqlite3_errmsg(m_masterConnection->m_connection);
- ThrowMsg(Exception::SyntaxError, error);
- }
+ LogError("SQL prepare data command failed");
+ LogError(" Statement: " << buffer);
+ LogError(" Error: " << error);
- LogPedantic("Prepared data command: " << buffer);
+ ThrowMsg(Exception::SyntaxError, error);
+ }
- // Increment stored data command count
- ++m_masterConnection->m_dataCommandsCount;
+ LogError("sqlite in the state of possible infinite loop");
+ ThrowMsg(Exception::InternalError, "sqlite permanently busy");
}
SqlConnection::DataCommand::~DataCommand()
{
- LogPedantic("SQL data command finalizing");
+ LogPedantic("SQL data command finalizing");
- if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK) {
- LogPedantic("Failed to finalize data command");
- }
+ if (sqlite3_finalize(m_stmt) != SQLITE_OK)
+ LogError("Failed to finalize data command");
- // Decrement stored data command count
- --m_masterConnection->m_dataCommandsCount;
+ // Decrement stored data command count
+ --m_masterConnection->m_dataCommandsCount;
}
void SqlConnection::DataCommand::CheckBindResult(int result)
{
- if (result != SQLCIPHER_OK) {
- const char *error = sqlcipher3_errmsg(
- m_masterConnection->m_connection);
+ if (result != SQLITE_OK) {
+ const char *error = sqlite3_errmsg(
+ m_masterConnection->m_connection);
- LogPedantic("Failed to bind SQL statement parameter");
- LogPedantic(" Error: " << error);
+ LogError("Failed to bind SQL statement parameter");
+ LogError(" Error: " << error);
- ThrowMsg(Exception::SyntaxError, error);
- }
+ ThrowMsg(Exception::SyntaxError, error);
+ }
}
+//LCOV_EXCL_START
void SqlConnection::DataCommand::BindNull(
- SqlConnection::ArgumentIndex position)
+ SqlConnection::ArgumentIndex position)
{
- CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
- LogPedantic("SQL data command bind null: ["
- << position << "]");
+ CheckBindResult(sqlite3_bind_null(m_stmt, position));
+ LogPedantic("SQL data command bind null: ["
+ << position << "]");
}
+//LCOV_EXCL_STOP
void SqlConnection::DataCommand::BindInteger(
- SqlConnection::ArgumentIndex position,
- int value)
+ SqlConnection::ArgumentIndex position,
+ int value)
{
- CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
- LogPedantic("SQL data command bind integer: ["
- << position << "] -> " << value);
+ CheckBindResult(sqlite3_bind_int(m_stmt, position, value));
+ LogPedantic("SQL data command bind integer: ["
+ << position << "] -> " << value);
}
+//LCOV_EXCL_START
void SqlConnection::DataCommand::BindInt8(
- SqlConnection::ArgumentIndex position,
- int8_t value)
+ SqlConnection::ArgumentIndex position,
+ int8_t value)
{
- CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
- static_cast<int>(value)));
- LogPedantic("SQL data command bind int8: ["
- << position << "] -> " << value);
+ CheckBindResult(sqlite3_bind_int(m_stmt, position,
+ static_cast<int>(value)));
+ LogPedantic("SQL data command bind int8: ["
+ << position << "] -> " << value);
}
void SqlConnection::DataCommand::BindInt16(
- SqlConnection::ArgumentIndex position,
- int16_t value)
+ SqlConnection::ArgumentIndex position,
+ int16_t value)
{
- CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
- static_cast<int>(value)));
- LogPedantic("SQL data command bind int16: ["
- << position << "] -> " << value);
+ CheckBindResult(sqlite3_bind_int(m_stmt, position,
+ static_cast<int>(value)));
+ LogPedantic("SQL data command bind int16: ["
+ << position << "] -> " << value);
}
void SqlConnection::DataCommand::BindInt32(
- SqlConnection::ArgumentIndex position,
- int32_t value)
+ SqlConnection::ArgumentIndex position,
+ int32_t value)
{
- CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
- static_cast<int>(value)));
- LogPedantic("SQL data command bind int32: ["
- << position << "] -> " << value);
+ CheckBindResult(sqlite3_bind_int(m_stmt, position,
+ static_cast<int>(value)));
+ LogPedantic("SQL data command bind int32: ["
+ << position << "] -> " << value);
}
void SqlConnection::DataCommand::BindInt64(
- SqlConnection::ArgumentIndex position,
- int64_t value)
+ SqlConnection::ArgumentIndex position,
+ int64_t value)
{
- CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
- static_cast<sqlcipher3_int64>(value)));
- LogPedantic("SQL data command bind int64: ["
- << position << "] -> " << value);
+ CheckBindResult(sqlite3_bind_int64(m_stmt, position,
+ static_cast<sqlite3_int64>(value)));
+ LogPedantic("SQL data command bind int64: ["
+ << position << "] -> " << value);
}
void SqlConnection::DataCommand::BindFloat(
- SqlConnection::ArgumentIndex position,
- float value)
+ SqlConnection::ArgumentIndex position,
+ float value)
{
- CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
- static_cast<double>(value)));
- LogPedantic("SQL data command bind float: ["
- << position << "] -> " << value);
+ CheckBindResult(sqlite3_bind_double(m_stmt, position,
+ static_cast<double>(value)));
+ LogPedantic("SQL data command bind float: ["
+ << position << "] -> " << value);
}
void SqlConnection::DataCommand::BindDouble(
- SqlConnection::ArgumentIndex position,
- double value)
+ SqlConnection::ArgumentIndex position,
+ double value)
{
- CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
- LogPedantic("SQL data command bind double: ["
- << position << "] -> " << value);
+ CheckBindResult(sqlite3_bind_double(m_stmt, position, value));
+ LogPedantic("SQL data command bind double: ["
+ << position << "] -> " << value);
}
+//LCOV_EXCL_STOP
void SqlConnection::DataCommand::BindString(
- SqlConnection::ArgumentIndex position,
- const char *value)
+ SqlConnection::ArgumentIndex position,
+ const char *value)
{
- if (!value) {
- BindNull(position);
- return;
- }
-
- // Assume that text may disappear
- CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
- value, strlen(value),
- SQLCIPHER_TRANSIENT));
-
- LogPedantic("SQL data command bind string: ["
- << position << "] -> " << value);
+ if (!value) {
+ BindNull(position);
+ return;
+ }
+
+ // Assume that text may disappear
+ CheckBindResult(sqlite3_bind_text(m_stmt, position,
+ value, strlen(value),
+ SQLITE_TRANSIENT));
+
+ LogPedantic("SQL data command bind string: ["
+ << position << "] -> " << value);
}
void SqlConnection::DataCommand::BindBlob(
- SqlConnection::ArgumentIndex position,
- const std::vector<unsigned char> &raw)
-{
- if (raw.size() == 0) {
- BindNull(position);
- return;
- }
-
- // Assume that blob may dissappear
- CheckBindResult(sqlcipher3_bind_blob(m_stmt, position,
- raw.data(), raw.size(),
- SQLCIPHER_TRANSIENT));
- LogPedantic("SQL data command bind blob of size "
- << raw.size());
-}
-
-void SqlConnection::DataCommand::BindString(
- SqlConnection::ArgumentIndex position,
- const String &value)
+ SqlConnection::ArgumentIndex position,
+ const RawBuffer &raw)
{
- BindString(position, ToUTF8String(value).c_str());
+ if (raw.size() == 0) {
+ BindNull(position);
+ return;
+ }
+
+ // Assume that blob may dissappear
+ CheckBindResult(sqlite3_bind_blob(m_stmt, position,
+ raw.data(), raw.size(),
+ SQLITE_TRANSIENT));
+ LogPedantic("SQL data command bind blob of size: ["
+ << position << "] -> " << raw.size());
}
+//LCOV_EXCL_START
void SqlConnection::DataCommand::BindInteger(
- SqlConnection::ArgumentIndex position,
- const boost::optional<int> &value)
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int> &value)
{
- if (!value) {
- BindNull(position);
- } else {
- BindInteger(position, *value);
- }
+ if (!value)
+ BindNull(position);
+ else
+ BindInteger(position, *value);
}
void SqlConnection::DataCommand::BindInt8(
- SqlConnection::ArgumentIndex position,
- const boost::optional<int8_t> &value)
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int8_t> &value)
{
- if (!value) {
- BindNull(position);
- } else {
- BindInt8(position, *value);
- }
+ if (!value)
+ BindNull(position);
+ else
+ BindInt8(position, *value);
}
void SqlConnection::DataCommand::BindInt16(
- SqlConnection::ArgumentIndex position,
- const boost::optional<int16_t> &value)
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int16_t> &value)
{
- if (!value) {
- BindNull(position);
- } else {
- BindInt16(position, *value);
- }
+ if (!value)
+ BindNull(position);
+ else
+ BindInt16(position, *value);
}
void SqlConnection::DataCommand::BindInt32(
- SqlConnection::ArgumentIndex position,
- const boost::optional<int32_t> &value)
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int32_t> &value)
{
- if (!value) {
- BindNull(position);
- } else {
- BindInt32(position, *value);
- }
+ if (!value)
+ BindNull(position);
+ else
+ BindInt32(position, *value);
}
void SqlConnection::DataCommand::BindInt64(
- SqlConnection::ArgumentIndex position,
- const boost::optional<int64_t> &value)
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int64_t> &value)
{
- if (!value) {
- BindNull(position);
- } else {
- BindInt64(position, *value);
- }
+ if (!value)
+ BindNull(position);
+ else
+ BindInt64(position, *value);
}
void SqlConnection::DataCommand::BindFloat(
- SqlConnection::ArgumentIndex position,
- const boost::optional<float> &value)
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<float> &value)
{
- if (!value) {
- BindNull(position);
- } else {
- BindFloat(position, *value);
- }
+ if (!value)
+ BindNull(position);
+ else
+ BindFloat(position, *value);
}
void SqlConnection::DataCommand::BindDouble(
- SqlConnection::ArgumentIndex position,
- const boost::optional<double> &value)
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<double> &value)
{
- if (!value) {
- BindNull(position);
- } else {
- BindDouble(position, *value);
- }
-}
-
-void SqlConnection::DataCommand::BindString(
- SqlConnection::ArgumentIndex position,
- const boost::optional<String> &value)
-{
- if (!!value) {
- BindString(position, ToUTF8String(*value).c_str());
- } else {
- BindNull(position);
- }
+ if (!value)
+ BindNull(position);
+ else
+ BindDouble(position, *value);
}
void SqlConnection::DataCommand::BindBlob(
- SqlConnection::ArgumentIndex position,
- const boost::optional<std::vector<unsigned char>> &value)
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<RawBuffer> &value)
{
- if (!!value) {
- BindBlob(position, *value);
- } else {
- BindNull(position);
- }
+ if (!!value)
+ BindBlob(position, *value);
+ else
+ BindNull(position);
}
+//LCOV_EXCL_STOP
bool SqlConnection::DataCommand::Step()
{
- // Notify all after potentially synchronized database connection access
- ScopedNotifyAll notifyAll(
- m_masterConnection->m_synchronizationObject.get());
+ // Notify all after potentially synchronized database connection access
+ ScopedNotifyAll notifyAll(
+ m_masterConnection->m_synchronizationObject.get());
- for (;;) {
- int ret = sqlcipher3_step(m_stmt);
+ for (int i = 0; i < MAX_RETRY; i++) {
+ int ret = sqlite3_step(m_stmt);
- if (ret == SQLCIPHER_ROW) {
- LogPedantic("SQL data command step ROW");
- return true;
- } else if (ret == SQLCIPHER_DONE) {
- LogPedantic("SQL data command step DONE");
- return false;
- } else if (ret == SQLCIPHER_BUSY) {
- LogPedantic("Collision occurred while executing SQL command");
+ if (ret == SQLITE_ROW) {
+ LogPedantic("SQL data command step ROW");
+ return true;
+ } else if (ret == SQLITE_DONE) {
+ LogPedantic("SQL data command step DONE");
+ return false;
+ } else if (ret == SQLITE_BUSY) {
+ LogPedantic("Collision occurred while executing SQL command");
- // Synchronize if synchronization object is available
- if (m_masterConnection->m_synchronizationObject) {
- LogPedantic("Performing synchronization");
+ // Synchronize if synchronization object is available
+ if (m_masterConnection->m_synchronizationObject) {
+ LogPedantic("Performing synchronization");
- m_masterConnection->
- m_synchronizationObject->Synchronize();
+ m_masterConnection->
+ m_synchronizationObject->Synchronize();
- continue;
- }
+ continue;
+ }
- // No synchronization object defined. Fail.
- }
+ // No synchronization object defined. Fail.
+ }
- // Fatal error
- const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
+ // Fatal error
+ const char *error = sqlite3_errmsg(m_masterConnection->m_connection);
- LogPedantic("SQL step data command failed");
- LogPedantic(" Error: " << error);
+ LogError("SQL step data command failed");
+ LogError(" Error: " << error);
- ThrowMsg(Exception::InternalError, error);
- }
+ ThrowMsg(Exception::InternalError, error);
+ }
+
+ LogError("sqlite in the state of possible infinite loop");
+ ThrowMsg(Exception::InternalError, "sqlite permanently busy");
}
void SqlConnection::DataCommand::Reset()
{
- /*
- * According to:
- * http://www.sqllite.org/c3ref/stmt.html
- *
- * if last sqlcipher3_step command on this stmt returned an error,
- * then sqlcipher3_reset will return that error, althought it is not an error.
- * So sqlcipher3_reset allways succedes.
- */
- sqlcipher3_reset(m_stmt);
-
- LogPedantic("SQL data command reset");
+ /*
+ * According to:
+ * http://www.sqllite.org/c3ref/stmt.html
+ *
+ * if last sqlite3_step command on this stmt returned an error,
+ * then sqlite3_reset will return that error, althought it is not an error.
+ * So sqlite3_reset allways succedes.
+ */
+ sqlite3_reset(m_stmt);
+
+ LogPedantic("SQL data command reset");
}
void SqlConnection::DataCommand::CheckColumnIndex(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- if (column < 0 || column >= sqlcipher3_column_count(m_stmt)) {
- ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
- }
+ if (column < 0 || column >= sqlite3_column_count(m_stmt))
+ ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
}
+//LCOV_EXCL_START
bool SqlConnection::DataCommand::IsColumnNull(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column type: [" << column << "]");
- CheckColumnIndex(column);
- return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
+ LogPedantic("SQL data command get column type: [" << column << "]");
+ CheckColumnIndex(column);
+ return sqlite3_column_type(m_stmt, column) == SQLITE_NULL;
}
+//LCOV_EXCL_STOP
int SqlConnection::DataCommand::GetColumnInteger(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column integer: [" << column << "]");
- CheckColumnIndex(column);
- int value = sqlcipher3_column_int(m_stmt, column);
- LogPedantic(" Value: " << value);
- return value;
+ LogPedantic("SQL data command get column integer: [" << column << "]");
+ CheckColumnIndex(column);
+ int value = sqlite3_column_int(m_stmt, column);
+ LogPedantic(" Value: " << value);
+ return value;
}
+//LCOV_EXCL_START
int8_t SqlConnection::DataCommand::GetColumnInt8(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column int8: [" << column << "]");
- CheckColumnIndex(column);
- int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
- LogPedantic(" Value: " << value);
- return value;
+ LogPedantic("SQL data command get column int8: [" << column << "]");
+ CheckColumnIndex(column);
+ int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
}
int16_t SqlConnection::DataCommand::GetColumnInt16(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column int16: [" << column << "]");
- CheckColumnIndex(column);
- int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
- LogPedantic(" Value: " << value);
- return value;
+ LogPedantic("SQL data command get column int16: [" << column << "]");
+ CheckColumnIndex(column);
+ int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
}
int32_t SqlConnection::DataCommand::GetColumnInt32(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column int32: [" << column << "]");
- CheckColumnIndex(column);
- int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
- LogPedantic(" Value: " << value);
- return value;
+ LogPedantic("SQL data command get column int32: [" << column << "]");
+ CheckColumnIndex(column);
+ int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
}
int64_t SqlConnection::DataCommand::GetColumnInt64(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column int64: [" << column << "]");
- CheckColumnIndex(column);
- int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
- LogPedantic(" Value: " << value);
- return value;
+ LogPedantic("SQL data command get column int64: [" << column << "]");
+ CheckColumnIndex(column);
+ int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
}
float SqlConnection::DataCommand::GetColumnFloat(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column float: [" << column << "]");
- CheckColumnIndex(column);
- float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
- LogPedantic(" Value: " << value);
- return value;
+ LogPedantic("SQL data command get column float: [" << column << "]");
+ CheckColumnIndex(column);
+ float value = static_cast<float>(sqlite3_column_double(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
}
double SqlConnection::DataCommand::GetColumnDouble(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column double: [" << column << "]");
- CheckColumnIndex(column);
- double value = sqlcipher3_column_double(m_stmt, column);
- LogPedantic(" Value: " << value);
- return value;
+ LogPedantic("SQL data command get column double: [" << column << "]");
+ CheckColumnIndex(column);
+ double value = sqlite3_column_double(m_stmt, column);
+ LogPedantic(" Value: " << value);
+ return value;
}
+//LCOV_EXCL_STOP
std::string SqlConnection::DataCommand::GetColumnString(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column string: [" << column << "]");
- CheckColumnIndex(column);
+ LogPedantic("SQL data command get column string: [" << column << "]");
+ CheckColumnIndex(column);
- const char *value = reinterpret_cast<const char *>(
- sqlcipher3_column_text(m_stmt, column));
+ const char *value = reinterpret_cast<const char *>(
+ sqlite3_column_text(m_stmt, column));
- LogPedantic("Value: " << (value ? value : "NULL"));
+ LogPedantic("Value: " << (value ? value : "NULL"));
- if (value == NULL) {
- return std::string();
- }
+ if (value == NULL)
+ return std::string();
- return std::string(value);
+ return std::string(value);
}
-std::vector<unsigned char> SqlConnection::DataCommand::GetColumnBlob(
- SqlConnection::ColumnIndex column)
+RawBuffer SqlConnection::DataCommand::GetColumnBlob(
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column blog: [" << column << "]");
- CheckColumnIndex(column);
+ LogPedantic("SQL data command get column blog: [" << column << "]");
+ CheckColumnIndex(column);
- const unsigned char *value = reinterpret_cast<const unsigned char*>(
- sqlcipher3_column_blob(m_stmt, column));
+ const unsigned char *value = reinterpret_cast<const unsigned char *>(
+ sqlite3_column_blob(m_stmt, column));
- if (value == NULL) {
- return std::vector<unsigned char>();
- }
+ if (value == NULL)
+ return RawBuffer();
- int length = sqlcipher3_column_bytes(m_stmt, column);
- LogPedantic("Got blob of length: " << length);
+ int length = sqlite3_column_bytes(m_stmt, column);
+ LogPedantic("Got blob of length: " << length);
- return std::vector<unsigned char>(value, value + length);
+ return RawBuffer(value, value + length);
}
+//LCOV_EXCL_START
boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column optional integer: ["
- << column << "]");
- CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
- return boost::optional<int>();
- }
- int value = sqlcipher3_column_int(m_stmt, column);
- LogPedantic(" Value: " << value);
- return boost::optional<int>(value);
+ LogPedantic("SQL data command get column optional integer: ["
+ << column << "]");
+ CheckColumnIndex(column);
+
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
+ return boost::optional<int>();
+
+ int value = sqlite3_column_int(m_stmt, column);
+ LogPedantic(" Value: " << value);
+ return boost::optional<int>(value);
}
boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column optional int8: ["
- << column << "]");
- CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
- return boost::optional<int8_t>();
- }
- int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
- LogPedantic(" Value: " << value);
- return boost::optional<int8_t>(value);
+ LogPedantic("SQL data command get column optional int8: ["
+ << column << "]");
+ CheckColumnIndex(column);
+
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
+ return boost::optional<int8_t>();
+
+ int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<int8_t>(value);
}
boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column optional int16: ["
- << column << "]");
- CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
- return boost::optional<int16_t>();
- }
- int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
- LogPedantic(" Value: " << value);
- return boost::optional<int16_t>(value);
+ LogPedantic("SQL data command get column optional int16: ["
+ << column << "]");
+ CheckColumnIndex(column);
+
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
+ return boost::optional<int16_t>();
+
+ int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<int16_t>(value);
}
boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column optional int32: ["
- << column << "]");
- CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
- return boost::optional<int32_t>();
- }
- int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
- LogPedantic(" Value: " << value);
- return boost::optional<int32_t>(value);
+ LogPedantic("SQL data command get column optional int32: ["
+ << column << "]");
+ CheckColumnIndex(column);
+
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
+ return boost::optional<int32_t>();
+
+ int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<int32_t>(value);
}
boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column optional int64: ["
- << column << "]");
- CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
- return boost::optional<int64_t>();
- }
- int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
- LogPedantic(" Value: " << value);
- return boost::optional<int64_t>(value);
+ LogPedantic("SQL data command get column optional int64: ["
+ << column << "]");
+ CheckColumnIndex(column);
+
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
+ return boost::optional<int64_t>();
+
+ int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<int64_t>(value);
}
boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column optional float: ["
- << column << "]");
- CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
- return boost::optional<float>();
- }
- float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
- LogPedantic(" Value: " << value);
- return boost::optional<float>(value);
+ LogPedantic("SQL data command get column optional float: ["
+ << column << "]");
+ CheckColumnIndex(column);
+
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
+ return boost::optional<float>();
+
+ float value = static_cast<float>(sqlite3_column_double(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<float>(value);
}
boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
- SqlConnection::ColumnIndex column)
+ SqlConnection::ColumnIndex column)
{
- LogPedantic("SQL data command get column optional double: ["
- << column << "]");
- CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
- return boost::optional<double>();
- }
- double value = sqlcipher3_column_double(m_stmt, column);
- LogPedantic(" Value: " << value);
- return boost::optional<double>(value);
+ LogPedantic("SQL data command get column optional double: ["
+ << column << "]");
+ CheckColumnIndex(column);
+
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
+ return boost::optional<double>();
+
+ double value = sqlite3_column_double(m_stmt, column);
+ LogPedantic(" Value: " << value);
+ return boost::optional<double>(value);
+}
+
+boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column blog: [" << column << "]");
+ CheckColumnIndex(column);
+
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
+ return boost::optional<RawBuffer>();
+
+ const unsigned char *value = reinterpret_cast<const unsigned char *>(
+ sqlite3_column_blob(m_stmt, column));
+
+ int length = sqlite3_column_bytes(m_stmt, column);
+ LogPedantic("Got blob of length: " << length);
+
+ RawBuffer temp(value, value + length);
+ return boost::optional<RawBuffer>(temp);
+}
+//LCOV_EXCL_STOP
+
+void SqlConnection::Connect(const std::string &address,
+ Flag::Option flag)
+{
+ if (m_connection != NULL) {
+ LogPedantic("Already connected.");
+ return;
+ }
+
+ LogPedantic("Connecting to DB: " << address << "...");
+
+ // Connect to database
+ int result;
+ result = sqlite3_open_v2(
+ address.c_str(),
+ &m_connection,
+ flag,
+ NULL);
+
+ if (result == SQLITE_OK) {
+ LogPedantic("Connected to DB");
+ } else {
+ LogError("Failed to connect to DB!");
+ ThrowMsg(Exception::ConnectionBroken, address);
+ }
+
+ // Enable foreign keys
+ TurnOnForeignKeys();
}
-boost::optional<String> SqlConnection::DataCommand::GetColumnOptionalString(
- SqlConnection::ColumnIndex column)
+const std::string SQLITE_RAW_PREFIX = "x'";
+const std::string SQLITE_RAW_SUFIX = "'";
+const std::size_t SQLITE_RAW_DATA_SIZE = 32;
+
+RawBuffer rawToHexString(const RawBuffer &raw)
{
- LogPedantic("SQL data command get column optional string: ["
- << column << "]");
- CheckColumnIndex(column);
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
- return boost::optional<String>();
- }
- const char *value = reinterpret_cast<const char *>(
- sqlcipher3_column_text(m_stmt, column));
- LogPedantic("Value: " << value);
- String s = FromUTF8String(value);
- return boost::optional<String>(s);
+ return hexDump<RawBuffer, true>(raw);
}
-boost::optional<std::vector<unsigned char>> SqlConnection::DataCommand::GetColumnOptionalBlob(
- SqlConnection::ColumnIndex column)
+RawBuffer createHexPass(const RawBuffer &rawPass)
{
- LogPedantic("SQL data command get column blog: [" << column << "]");
- CheckColumnIndex(column);
+ // We are required to pass 64byte long hex password made out of 32byte raw
+ // binary data
+ RawBuffer output;
+ std::copy(SQLITE_RAW_PREFIX.begin(), SQLITE_RAW_PREFIX.end(),
+ std::back_inserter(output));
- if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
- return boost::optional<std::vector<unsigned char>>();
- }
- const unsigned char *value = reinterpret_cast<const unsigned char*>(
- sqlcipher3_column_blob(m_stmt, column));
+ RawBuffer password = rawToHexString(rawPass);
- int length = sqlcipher3_column_bytes(m_stmt, column);
- LogPedantic("Got blob of length: " << length);
+ std::copy(password.begin(), password.end(),
+ std::back_inserter(output));
- std::vector<unsigned char> temp(value, value + length);
- return boost::optional<std::vector<unsigned char>>(temp);
+ std::copy(SQLITE_RAW_SUFIX.begin(), SQLITE_RAW_SUFIX.end(),
+ std::back_inserter(output));
+
+ return output;
}
-void SqlConnection::Connect(const std::string &address,
- Flag::Option flag)
-{
- if (m_connection != NULL) {
- LogPedantic("Already connected.");
- return;
- }
- LogPedantic("Connecting to DB: " << address << "...");
-
- // Connect to database
- int result;
- result = sqlcipher3_open_v2(
- address.c_str(),
- &m_connection,
- flag,
- NULL);
-
- if (result == SQLCIPHER_OK) {
- LogPedantic("Connected to DB");
- } else {
- LogPedantic("Failed to connect to DB!");
- ThrowMsg(Exception::ConnectionBroken, address);
- }
-
- // Enable foreign keys
- TurnOnForeignKeys();
-}
-
-const std::string SQLCIPHER_RAW_PREFIX="x'";
-const std::string SQLCIPHER_RAW_SUFIX="'";
-const std::size_t SQLCIPHER_RAW_DATA_SIZE = 32;
-
-void rawToHexString(TransitoryString& str,
- std::size_t offset,
- const std::vector<unsigned char> &raw) {
- for (std::size_t i = 0; i < raw.size(); i++)
- sprintf(&str[offset + i*2], "%02X", raw[i]);
-}
-
-TransitoryString createHexPass(const std::vector<unsigned char> &rawPass){
- TransitoryString pass = TransitoryString('0', SQLCIPHER_RAW_PREFIX.length() +
- //We are required to pass 64byte
- //long hex password made out of
- //32byte raw binary data
- rawPass.size() * 2 +
- SQLCIPHER_RAW_SUFIX.length());
- for(std::size_t i = 0; i < SQLCIPHER_RAW_PREFIX.size(); i++)
- pass[i] = SQLCIPHER_RAW_PREFIX[i];
- rawToHexString(pass, SQLCIPHER_RAW_PREFIX.size(), rawPass);
- for(std::size_t i = 0; i < SQLCIPHER_RAW_PREFIX.size(); i++)
- for(std::size_t i = 0; i < SQLCIPHER_RAW_SUFIX.size(); i++)
- pass[i + SQLCIPHER_RAW_PREFIX.size() + rawPass.size() * 2]
- = SQLCIPHER_RAW_SUFIX[i];
- return pass;
-
-}
-
-void SqlConnection::SetKey(const std::vector<unsigned char> &rawPass){
- if (m_connection == NULL) {
- LogPedantic("Cannot set key. No connection to DB!");
- return;
- }
- AssertMsg(rawPass.size() == SQLCIPHER_RAW_DATA_SIZE,
- "Binary data for raw password should be 32 bytes long."
- );
- TransitoryString pass = createHexPass(rawPass);
- int result = sqlcipher3_key(m_connection, pass.c_str(), pass.length());
- if (result == SQLCIPHER_OK) {
- LogPedantic("Set key on DB");
- } else {
- //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
- // key length == 0
- LogPedantic("Failed to set key on DB");
- ThrowMsg(Exception::InvalidArguments, result);
- }
-
- m_isKeySet = true;
+void SqlConnection::SetKey(const RawBuffer &rawPass)
+{
+ if (m_connection == NULL) {
+ LogPedantic("Cannot set key. No connection to DB!");
+ return;
+ }
+
+ if (rawPass.size() != SQLITE_RAW_DATA_SIZE)
+ ThrowMsg(Exception::InvalidArguments,
+ "Binary data for raw password should be 32 bytes long.");
+
+ RawBuffer pass = createHexPass(rawPass);
+ int result = sqlite3_key(m_connection, pass.data(), pass.size());
+
+ if (result == SQLITE_OK) {
+ LogPedantic("Set key on DB");
+ } else {
+ //sqlite3_key fails only when m_connection == NULL || key == NULL ||
+ // key length == 0
+ LogError("Failed to set key on DB");
+ ThrowMsg(Exception::InvalidArguments, result);
+ }
+
+ m_isKeySet = true;
};
-void SqlConnection::ResetKey(const std::vector<unsigned char> &rawPassOld,
- const std::vector<unsigned char> &rawPassNew) {
- if (m_connection == NULL) {
- LogPedantic("Cannot reset key. No connection to DB!");
- return;
- }
- AssertMsg(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
- rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE,
- "Binary data for raw password should be 32 bytes long."
- );
- // sqlcipher3_rekey requires for key to be already set
- if (!m_isKeySet)
- SetKey(rawPassOld);
-
- TransitoryString pass = createHexPass(rawPassNew);
- int result = sqlcipher3_rekey(m_connection, pass.c_str(), pass.length());
- if (result == SQLCIPHER_OK) {
- LogPedantic("Reset key on DB");
- } else {
- //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
- // key length == 0
- LogPedantic("Failed to reset key on DB");
- ThrowMsg(Exception::InvalidArguments, result);
- }
+//LCOV_EXCL_START
+void SqlConnection::ResetKey(const RawBuffer &rawPassOld,
+ const RawBuffer &rawPassNew)
+{
+ if (m_connection == NULL) {
+ LogPedantic("Cannot reset key. No connection to DB!");
+ return;
+ }
+
+ // Binary data for raw password should be 32 bytes long.
+ assert(rawPassOld.size() == SQLITE_RAW_DATA_SIZE &&
+ rawPassNew.size() == SQLITE_RAW_DATA_SIZE);
+
+ // sqlite3_rekey requires for key to be already set
+ if (!m_isKeySet)
+ SetKey(rawPassOld);
+
+ RawBuffer pass = createHexPass(rawPassNew);
+ int result = sqlite3_rekey(m_connection, pass.data(), pass.size());
+
+ if (result == SQLITE_OK) {
+ LogPedantic("Reset key on DB");
+ } else {
+ //sqlite3_rekey fails only when m_connection == NULL || key == NULL ||
+ // key length == 0
+ LogError("Failed to reset key on DB");
+ ThrowMsg(Exception::InvalidArguments, result);
+ }
}
+//LCOV_EXCL_STOP
void SqlConnection::Disconnect()
{
- if (m_connection == NULL) {
- LogPedantic("Already disconnected.");
- return;
- }
+ if (m_connection == NULL) {
+ LogPedantic("Already disconnected.");
+ return;
+ }
- LogPedantic("Disconnecting from DB...");
+ LogPedantic("Disconnecting from DB...");
- // All stored data commands must be deleted before disconnect
- AssertMsg(m_dataCommandsCount == 0,
- "All stored procedures must be deleted"
- " before disconnecting SqlConnection");
+ // All stored data commands must be deleted before disconnect
+ assert(m_dataCommandsCount == 0);
- int result;
+ int result;
- result = sqlcipher3_close(m_connection);
+ result = sqlite3_close(m_connection);
- if (result != SQLCIPHER_OK) {
- const char *error = sqlcipher3_errmsg(m_connection);
- LogPedantic("SQL close failed");
- LogPedantic(" Error: " << error);
- Throw(Exception::InternalError);
- }
+ if (result != SQLITE_OK) {
+ const char *error = sqlite3_errmsg(m_connection);
+ LogError("SQL close failed");
+ LogError(" Error: " << error);
+ Throw(Exception::InternalError);
+ }
- m_connection = NULL;
+ m_connection = NULL;
- LogPedantic("Disconnected from DB");
+ LogPedantic("Disconnected from DB");
}
bool SqlConnection::CheckTableExist(const char *tableName)
{
- if (m_connection == NULL) {
- LogPedantic("Cannot execute command. Not connected to DB!");
- return false;
- }
+ if (m_connection == NULL) {
+ LogPedantic("Cannot execute command. Not connected to DB!");
+ return false;
+ }
- DataCommandAutoPtr command =
- PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
+ DataCommandUniquePtr command =
+ PrepareDataCommand("select tbl_name from sqlite_master where name=?;");
- command->BindString(1, tableName);
+ command->BindString(1, tableName);
- if (!command->Step()) {
- LogPedantic("No matching records in table");
- return false;
- }
+ if (!command->Step()) {
+ LogPedantic("No matching records in table");
+ return false;
+ }
- return command->GetColumnString(0) == tableName;
+ return command->GetColumnString(0) == tableName;
}
SqlConnection::SqlConnection(const std::string &address,
- Flag::Option option,
- SynchronizationObject *synchronizationObject) :
- m_connection(NULL),
- m_dataCommandsCount(0),
- m_synchronizationObject(synchronizationObject),
- m_isKeySet(false)
+ Flag::Option option,
+ SynchronizationObject *synchronizationObject) :
+ m_connection(NULL),
+ m_dataCommandsCount(0),
+ m_synchronizationObject(synchronizationObject),
+ m_isKeySet(false)
{
- LogPedantic("Opening database connection to: " << address);
+ LogPedantic("Opening database connection to: " << address);
- // Connect to DB
- SqlConnection::Connect(address, option);
+ // Connect to DB
+ SqlConnection::Connect(address, option);
- if (!m_synchronizationObject) {
- LogPedantic("No synchronization object defined");
- }
+ if (!m_synchronizationObject)
+ LogPedantic("No synchronization object defined");
}
SqlConnection::~SqlConnection()
{
- LogPedantic("Closing database connection");
+ LogPedantic("Closing database connection");
+
+ // Disconnect from DB
+ try {
+ SqlConnection::Disconnect();
+ } catch (const Exception::Base &) {
+ LogError("Failed to disconnect from database");
+ }
+}
+
+//LCOV_EXCL_START
+int SqlConnection::Output::Callback(void *param, int columns, char **values,
+ char **names)
+{
+ if (param)
+ static_cast<Output *>(param)->SetResults(columns, values, names);
- // Disconnect from DB
- Try
- {
- SqlConnection::Disconnect();
- }
- Catch(Exception::Base)
- {
- LogPedantic("Failed to disconnect from database");
- }
+ return 0;
}
-void SqlConnection::ExecCommand(const char *format, ...)
+void SqlConnection::Output::SetResults(int columns, char **values, char **names)
{
- if (m_connection == NULL) {
- LogPedantic("Cannot execute command. Not connected to DB!");
- return;
- }
+ if (m_names.empty()) {
+ for (int i = 0; i < columns; i++)
+ m_names.push_back(names[i] ? names[i] : "NULL");
+ }
+
+ Row row;
+
+ for (int i = 0; i < columns; i++)
+ row.push_back(values[i] ? values[i] : "NULL");
- if (format == NULL) {
- LogPedantic("Null query!");
- ThrowMsg(Exception::SyntaxError, "Null statement");
- }
+ m_values.push_back(std::move(row));
+}
+//LCOV_EXCL_STOP
+
+void SqlConnection::ExecCommandHelper(Output *out, const char *format,
+ va_list args)
+{
+ if (m_connection == NULL) {
+ LogError("Cannot execute command. Not connected to DB!");
+ return;
+ }
- char *rawBuffer;
+ if (format == NULL) {
+ LogError("Null query!");
+ ThrowMsg(Exception::SyntaxError, "Null statement");
+ }
- va_list args;
- va_start(args, format);
+ char *query;
- if (vasprintf(&rawBuffer, format, args) == -1) {
- rawBuffer = NULL;
- }
+ if (vasprintf(&query, format, args) == -1) {
+ LogError("Failed to allocate statement string");
+ return;
+ }
- va_end(args);
+ CharUniquePtr queryPtr(query);
- CharUniquePtr buffer(rawBuffer);
+ LogPedantic("Executing SQL command: " << queryPtr.get());
- if (!buffer) {
- LogPedantic("Failed to allocate statement string");
- return;
- }
+ // Notify all after potentially synchronized database connection access
+ ScopedNotifyAll notifyAll(m_synchronizationObject.get());
- LogPedantic("Executing SQL command: " << buffer.get());
+ for (int i = 0; i < MAX_RETRY; i++) {
+ char *errorBuffer;
+ int ret = sqlite3_exec(m_connection,
+ queryPtr.get(),
+ out ? &Output::Callback : NULL,
+ out,
+ &errorBuffer);
- // Notify all after potentially synchronized database connection access
- ScopedNotifyAll notifyAll(m_synchronizationObject.get());
+ std::string errorMsg;
- for (;;) {
- char *errorBuffer;
+ // Take allocated error buffer
+ if (errorBuffer != NULL) {
+ errorMsg = errorBuffer;
+ sqlite3_free(errorBuffer);
+ }
- int ret = sqlcipher3_exec(m_connection,
- buffer.get(),
- NULL,
- NULL,
- &errorBuffer);
+ if (ret == SQLITE_OK)
+ return;
- std::string errorMsg;
+ if (ret == SQLITE_BUSY) {
+ LogPedantic("Collision occurred while executing SQL command");
- // Take allocated error buffer
- if (errorBuffer != NULL) {
- errorMsg = errorBuffer;
- sqlcipher3_free(errorBuffer);
- }
+ // Synchronize if synchronization object is available
+ if (m_synchronizationObject) {
+ LogPedantic("Performing synchronization");
+ m_synchronizationObject->Synchronize();
+ continue;
+ }
- if (ret == SQLCIPHER_OK) {
- return;
- }
+ // No synchronization object defined. Fail.
+ }
- if (ret == SQLCIPHER_BUSY) {
- LogPedantic("Collision occurred while executing SQL command");
+ // Fatal error
+ LogError("Failed to execute SQL command. Error: " << errorMsg);
+ ThrowMsg(Exception::SyntaxError, errorMsg);
+ }
- // Synchronize if synchronization object is available
- if (m_synchronizationObject) {
- LogPedantic("Performing synchronization");
- m_synchronizationObject->Synchronize();
- continue;
- }
+ LogError("sqlite in the state of possible infinite loop");
+ ThrowMsg(Exception::InternalError, "sqlite permanently busy");
+}
- // No synchronization object defined. Fail.
- }
+//LCOV_EXCL_START
+void SqlConnection::ExecCommand(Output *out, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ try {
+ ExecCommandHelper(out, format, args);
+ } catch (...) {
+ va_end(args);
+ throw;
+ }
+ va_end(args);
+}
+//LCOV_EXCL_STOP
- // Fatal error
- LogPedantic("Failed to execute SQL command. Error: " << errorMsg);
- ThrowMsg(Exception::SyntaxError, errorMsg);
- }
+void SqlConnection::ExecCommand(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ try {
+ ExecCommandHelper(NULL, format, args);
+ } catch (...) {
+ va_end(args);
+ throw;
+ }
+ va_end(args);
}
-SqlConnection::DataCommandAutoPtr SqlConnection::PrepareDataCommand(
- const char *format,
- ...)
+SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
+ const char *format,
+ ...)
{
- if (m_connection == NULL) {
- LogPedantic("Cannot execute data command. Not connected to DB!");
- return DataCommandAutoPtr();
- }
+ if (m_connection == NULL) {
+ LogError("Cannot execute data command. Not connected to DB!");
+ return DataCommandUniquePtr();
+ }
- char *rawBuffer;
+ char *rawBuffer;
- va_list args;
- va_start(args, format);
+ va_list args;
+ va_start(args, format);
- if (vasprintf(&rawBuffer, format, args) == -1) {
- rawBuffer = NULL;
- }
+ if (vasprintf(&rawBuffer, format, args) == -1)
+ rawBuffer = NULL;
- va_end(args);
+ va_end(args);
- CharUniquePtr buffer(rawBuffer);
+ CharUniquePtr buffer(rawBuffer);
- if (!buffer) {
- LogPedantic("Failed to allocate statement string");
- return DataCommandAutoPtr();
- }
+ if (!buffer) {
+ LogError("Failed to allocate statement string");
+ return DataCommandUniquePtr();
+ }
- LogPedantic("Executing SQL data command: " << buffer.get());
+ LogPedantic("Executing SQL data command: " << buffer.get());
- return DataCommandAutoPtr(new DataCommand(this, buffer.get()));
+ return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
}
+//LCOV_EXCL_START
SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
{
- return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
+ return static_cast<RowID>(sqlite3_last_insert_rowid(m_connection));
}
+//LCOV_EXCL_STOP
void SqlConnection::TurnOnForeignKeys()
{
- ExecCommand("PRAGMA foreign_keys = ON;");
+ ExecCommand("PRAGMA foreign_keys = ON;");
}
void SqlConnection::BeginTransaction()
{
- ExecCommand("BEGIN;");
+ ExecCommand("BEGIN;");
}
void SqlConnection::RollbackTransaction()
{
- ExecCommand("ROLLBACK;");
+ ExecCommand("ROLLBACK;");
}
void SqlConnection::CommitTransaction()
{
- ExecCommand("COMMIT;");
+ ExecCommand("COMMIT;");
}
SqlConnection::SynchronizationObject *
SqlConnection::AllocDefaultSynchronizationObject()
{
- return new NaiveSynchronizationObject();
+ return new NaiveSynchronizationObject();
}
} // namespace DB
} // namespace CKM