2 * Copyright (c) 2014-2019 Samsung Electronics Co., Ltd. All rights reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file sql_connection.cpp
18 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20 * @brief This file is the implementation file of SQL connection
22 #pragma GCC diagnostic push
23 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
26 #include <dpl/db/sql_connection.h>
27 #include <dpl/db/naive_synchronization_object.h>
28 #include <dpl/assert.h>
29 #include <dpl/scoped_ptr.h>
34 #include <noncopyable.h>
38 const int MAX_RETRY = 10;
43 namespace { // anonymous
44 class ScopedNotifyAll {
46 SqlConnection::SynchronizationObject *m_synchronizationObject;
49 NONCOPYABLE(ScopedNotifyAll)
51 explicit ScopedNotifyAll(
52 SqlConnection::SynchronizationObject *synchronizationObject) :
53 m_synchronizationObject(synchronizationObject)
59 if (!m_synchronizationObject)
62 LogPedantic("Notifying after successful synchronize");
63 m_synchronizationObject->NotifyAll();
66 } // namespace anonymous
68 SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
70 m_masterConnection(connection),
73 Assert(connection != NULL);
75 // Notify all after potentially synchronized database connection access
76 ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
78 for (int i = 0; i < MAX_RETRY; i++) {
79 int ret = sqlcipher3_prepare_v2(connection->m_connection,
80 buffer, strlen(buffer),
83 if (ret == SQLCIPHER_OK) {
84 LogPedantic("Prepared data command: " << buffer);
86 // Increment stored data command count
87 ++m_masterConnection->m_dataCommandsCount;
89 } else if (ret == SQLCIPHER_BUSY) {
90 LogPedantic("Collision occurred while preparing SQL command");
92 // Synchronize if synchronization object is available
93 if (connection->m_synchronizationObject) {
94 LogPedantic("Performing synchronization");
95 connection->m_synchronizationObject->Synchronize();
99 // No synchronization object defined. Fail.
103 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
105 LogError("SQL prepare data command failed");
106 LogError(" Statement: " << buffer);
107 LogError(" Error: " << error);
109 ThrowMsg(Exception::SyntaxError, error);
112 LogError("sqlite in the state of possible infinite loop");
113 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
116 SqlConnection::DataCommand::~DataCommand()
118 LogPedantic("SQL data command finalizing");
120 if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK)
121 LogError("Failed to finalize data command");
123 // Decrement stored data command count
124 --m_masterConnection->m_dataCommandsCount;
127 void SqlConnection::DataCommand::CheckBindResult(int result)
129 if (result != SQLCIPHER_OK) {
130 const char *error = sqlcipher3_errmsg(
131 m_masterConnection->m_connection);
133 LogError("Failed to bind SQL statement parameter");
134 LogError(" Error: " << error);
136 ThrowMsg(Exception::SyntaxError, error);
141 void SqlConnection::DataCommand::BindNull(
142 SqlConnection::ArgumentIndex position)
144 CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
145 LogPedantic("SQL data command bind null: ["
150 void SqlConnection::DataCommand::BindInteger(
151 SqlConnection::ArgumentIndex position,
154 CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
155 LogPedantic("SQL data command bind integer: ["
156 << position << "] -> " << value);
160 void SqlConnection::DataCommand::BindInt8(
161 SqlConnection::ArgumentIndex position,
164 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
165 static_cast<int>(value)));
166 LogPedantic("SQL data command bind int8: ["
167 << position << "] -> " << value);
170 void SqlConnection::DataCommand::BindInt16(
171 SqlConnection::ArgumentIndex position,
174 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
175 static_cast<int>(value)));
176 LogPedantic("SQL data command bind int16: ["
177 << position << "] -> " << value);
180 void SqlConnection::DataCommand::BindInt32(
181 SqlConnection::ArgumentIndex position,
184 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
185 static_cast<int>(value)));
186 LogPedantic("SQL data command bind int32: ["
187 << position << "] -> " << value);
190 void SqlConnection::DataCommand::BindInt64(
191 SqlConnection::ArgumentIndex position,
194 CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
195 static_cast<sqlcipher3_int64>(value)));
196 LogPedantic("SQL data command bind int64: ["
197 << position << "] -> " << value);
200 void SqlConnection::DataCommand::BindFloat(
201 SqlConnection::ArgumentIndex position,
204 CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
205 static_cast<double>(value)));
206 LogPedantic("SQL data command bind float: ["
207 << position << "] -> " << value);
210 void SqlConnection::DataCommand::BindDouble(
211 SqlConnection::ArgumentIndex position,
214 CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
215 LogPedantic("SQL data command bind double: ["
216 << position << "] -> " << value);
220 void SqlConnection::DataCommand::BindString(
221 SqlConnection::ArgumentIndex position,
229 // Assume that text may disappear
230 CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
231 value, strlen(value),
232 SQLCIPHER_TRANSIENT));
234 LogPedantic("SQL data command bind string: ["
235 << position << "] -> " << value);
238 void SqlConnection::DataCommand::BindBlob(
239 SqlConnection::ArgumentIndex position,
240 const RawBuffer &raw)
242 if (raw.size() == 0) {
247 // Assume that blob may dissappear
248 CheckBindResult(sqlcipher3_bind_blob(m_stmt, position,
249 raw.data(), raw.size(),
250 SQLCIPHER_TRANSIENT));
251 LogPedantic("SQL data command bind blob of size: ["
252 << position << "] -> " << raw.size());
256 void SqlConnection::DataCommand::BindInteger(
257 SqlConnection::ArgumentIndex position,
258 const boost::optional<int> &value)
263 BindInteger(position, *value);
266 void SqlConnection::DataCommand::BindInt8(
267 SqlConnection::ArgumentIndex position,
268 const boost::optional<int8_t> &value)
273 BindInt8(position, *value);
276 void SqlConnection::DataCommand::BindInt16(
277 SqlConnection::ArgumentIndex position,
278 const boost::optional<int16_t> &value)
283 BindInt16(position, *value);
286 void SqlConnection::DataCommand::BindInt32(
287 SqlConnection::ArgumentIndex position,
288 const boost::optional<int32_t> &value)
293 BindInt32(position, *value);
296 void SqlConnection::DataCommand::BindInt64(
297 SqlConnection::ArgumentIndex position,
298 const boost::optional<int64_t> &value)
303 BindInt64(position, *value);
306 void SqlConnection::DataCommand::BindFloat(
307 SqlConnection::ArgumentIndex position,
308 const boost::optional<float> &value)
313 BindFloat(position, *value);
316 void SqlConnection::DataCommand::BindDouble(
317 SqlConnection::ArgumentIndex position,
318 const boost::optional<double> &value)
323 BindDouble(position, *value);
326 void SqlConnection::DataCommand::BindBlob(
327 SqlConnection::ArgumentIndex position,
328 const boost::optional<RawBuffer> &value)
331 BindBlob(position, *value);
337 bool SqlConnection::DataCommand::Step()
339 // Notify all after potentially synchronized database connection access
340 ScopedNotifyAll notifyAll(
341 m_masterConnection->m_synchronizationObject.get());
343 for (int i = 0; i < MAX_RETRY; i++) {
344 int ret = sqlcipher3_step(m_stmt);
346 if (ret == SQLCIPHER_ROW) {
347 LogPedantic("SQL data command step ROW");
349 } else if (ret == SQLCIPHER_DONE) {
350 LogPedantic("SQL data command step DONE");
352 } else if (ret == SQLCIPHER_BUSY) {
353 LogPedantic("Collision occurred while executing SQL command");
355 // Synchronize if synchronization object is available
356 if (m_masterConnection->m_synchronizationObject) {
357 LogPedantic("Performing synchronization");
360 m_synchronizationObject->Synchronize();
365 // No synchronization object defined. Fail.
369 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
371 LogError("SQL step data command failed");
372 LogError(" Error: " << error);
374 ThrowMsg(Exception::InternalError, error);
377 LogError("sqlite in the state of possible infinite loop");
378 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
381 void SqlConnection::DataCommand::Reset()
385 * http://www.sqllite.org/c3ref/stmt.html
387 * if last sqlcipher3_step command on this stmt returned an error,
388 * then sqlcipher3_reset will return that error, althought it is not an error.
389 * So sqlcipher3_reset allways succedes.
391 sqlcipher3_reset(m_stmt);
393 LogPedantic("SQL data command reset");
396 void SqlConnection::DataCommand::CheckColumnIndex(
397 SqlConnection::ColumnIndex column)
399 if (column < 0 || column >= sqlcipher3_column_count(m_stmt))
400 ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
404 bool SqlConnection::DataCommand::IsColumnNull(
405 SqlConnection::ColumnIndex column)
407 LogPedantic("SQL data command get column type: [" << column << "]");
408 CheckColumnIndex(column);
409 return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
413 int SqlConnection::DataCommand::GetColumnInteger(
414 SqlConnection::ColumnIndex column)
416 LogPedantic("SQL data command get column integer: [" << column << "]");
417 CheckColumnIndex(column);
418 int value = sqlcipher3_column_int(m_stmt, column);
419 LogPedantic(" Value: " << value);
424 int8_t SqlConnection::DataCommand::GetColumnInt8(
425 SqlConnection::ColumnIndex column)
427 LogPedantic("SQL data command get column int8: [" << column << "]");
428 CheckColumnIndex(column);
429 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
430 LogPedantic(" Value: " << value);
434 int16_t SqlConnection::DataCommand::GetColumnInt16(
435 SqlConnection::ColumnIndex column)
437 LogPedantic("SQL data command get column int16: [" << column << "]");
438 CheckColumnIndex(column);
439 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
440 LogPedantic(" Value: " << value);
444 int32_t SqlConnection::DataCommand::GetColumnInt32(
445 SqlConnection::ColumnIndex column)
447 LogPedantic("SQL data command get column int32: [" << column << "]");
448 CheckColumnIndex(column);
449 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
450 LogPedantic(" Value: " << value);
454 int64_t SqlConnection::DataCommand::GetColumnInt64(
455 SqlConnection::ColumnIndex column)
457 LogPedantic("SQL data command get column int64: [" << column << "]");
458 CheckColumnIndex(column);
459 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
460 LogPedantic(" Value: " << value);
464 float SqlConnection::DataCommand::GetColumnFloat(
465 SqlConnection::ColumnIndex column)
467 LogPedantic("SQL data command get column float: [" << column << "]");
468 CheckColumnIndex(column);
469 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
470 LogPedantic(" Value: " << value);
474 double SqlConnection::DataCommand::GetColumnDouble(
475 SqlConnection::ColumnIndex column)
477 LogPedantic("SQL data command get column double: [" << column << "]");
478 CheckColumnIndex(column);
479 double value = sqlcipher3_column_double(m_stmt, column);
480 LogPedantic(" Value: " << value);
485 std::string SqlConnection::DataCommand::GetColumnString(
486 SqlConnection::ColumnIndex column)
488 LogPedantic("SQL data command get column string: [" << column << "]");
489 CheckColumnIndex(column);
491 const char *value = reinterpret_cast<const char *>(
492 sqlcipher3_column_text(m_stmt, column));
494 LogPedantic("Value: " << (value ? value : "NULL"));
497 return std::string();
499 return std::string(value);
502 RawBuffer SqlConnection::DataCommand::GetColumnBlob(
503 SqlConnection::ColumnIndex column)
505 LogPedantic("SQL data command get column blog: [" << column << "]");
506 CheckColumnIndex(column);
508 const unsigned char *value = reinterpret_cast<const unsigned char *>(
509 sqlcipher3_column_blob(m_stmt, column));
514 int length = sqlcipher3_column_bytes(m_stmt, column);
515 LogPedantic("Got blob of length: " << length);
517 return RawBuffer(value, value + length);
521 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
522 SqlConnection::ColumnIndex column)
524 LogPedantic("SQL data command get column optional integer: ["
526 CheckColumnIndex(column);
528 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
529 return boost::optional<int>();
531 int value = sqlcipher3_column_int(m_stmt, column);
532 LogPedantic(" Value: " << value);
533 return boost::optional<int>(value);
536 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
537 SqlConnection::ColumnIndex column)
539 LogPedantic("SQL data command get column optional int8: ["
541 CheckColumnIndex(column);
543 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
544 return boost::optional<int8_t>();
546 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
547 LogPedantic(" Value: " << value);
548 return boost::optional<int8_t>(value);
551 boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
552 SqlConnection::ColumnIndex column)
554 LogPedantic("SQL data command get column optional int16: ["
556 CheckColumnIndex(column);
558 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
559 return boost::optional<int16_t>();
561 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
562 LogPedantic(" Value: " << value);
563 return boost::optional<int16_t>(value);
566 boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
567 SqlConnection::ColumnIndex column)
569 LogPedantic("SQL data command get column optional int32: ["
571 CheckColumnIndex(column);
573 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
574 return boost::optional<int32_t>();
576 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
577 LogPedantic(" Value: " << value);
578 return boost::optional<int32_t>(value);
581 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
582 SqlConnection::ColumnIndex column)
584 LogPedantic("SQL data command get column optional int64: ["
586 CheckColumnIndex(column);
588 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
589 return boost::optional<int64_t>();
591 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
592 LogPedantic(" Value: " << value);
593 return boost::optional<int64_t>(value);
596 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
597 SqlConnection::ColumnIndex column)
599 LogPedantic("SQL data command get column optional float: ["
601 CheckColumnIndex(column);
603 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
604 return boost::optional<float>();
606 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
607 LogPedantic(" Value: " << value);
608 return boost::optional<float>(value);
611 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
612 SqlConnection::ColumnIndex column)
614 LogPedantic("SQL data command get column optional double: ["
616 CheckColumnIndex(column);
618 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
619 return boost::optional<double>();
621 double value = sqlcipher3_column_double(m_stmt, column);
622 LogPedantic(" Value: " << value);
623 return boost::optional<double>(value);
626 boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
627 SqlConnection::ColumnIndex column)
629 LogPedantic("SQL data command get column blog: [" << column << "]");
630 CheckColumnIndex(column);
632 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
633 return boost::optional<RawBuffer>();
635 const unsigned char *value = reinterpret_cast<const unsigned char *>(
636 sqlcipher3_column_blob(m_stmt, column));
638 int length = sqlcipher3_column_bytes(m_stmt, column);
639 LogPedantic("Got blob of length: " << length);
641 RawBuffer temp(value, value + length);
642 return boost::optional<RawBuffer>(temp);
646 void SqlConnection::Connect(const std::string &address,
649 if (m_connection != NULL) {
650 LogPedantic("Already connected.");
654 LogPedantic("Connecting to DB: " << address << "...");
656 // Connect to database
658 result = sqlcipher3_open_v2(
664 if (result == SQLCIPHER_OK) {
665 LogPedantic("Connected to DB");
667 LogError("Failed to connect to DB!");
668 ThrowMsg(Exception::ConnectionBroken, address);
671 // Enable foreign keys
675 const std::string SQLCIPHER_RAW_PREFIX = "x'";
676 const std::string SQLCIPHER_RAW_SUFIX = "'";
677 const std::size_t SQLCIPHER_RAW_DATA_SIZE = 32;
679 RawBuffer rawToHexString(const RawBuffer &raw)
681 return hexDump<RawBuffer, true>(raw);
684 RawBuffer createHexPass(const RawBuffer &rawPass)
686 // We are required to pass 64byte long hex password made out of 32byte raw
689 std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
690 std::back_inserter(output));
692 RawBuffer password = rawToHexString(rawPass);
694 std::copy(password.begin(), password.end(),
695 std::back_inserter(output));
697 std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
698 std::back_inserter(output));
703 void SqlConnection::SetKey(const RawBuffer &rawPass)
705 if (m_connection == NULL) {
706 LogPedantic("Cannot set key. No connection to DB!");
710 if (rawPass.size() != SQLCIPHER_RAW_DATA_SIZE)
711 ThrowMsg(Exception::InvalidArguments,
712 "Binary data for raw password should be 32 bytes long.");
714 RawBuffer pass = createHexPass(rawPass);
715 int result = sqlcipher3_key(m_connection, pass.data(), pass.size());
717 if (result == SQLCIPHER_OK) {
718 LogPedantic("Set key on DB");
720 //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
722 LogError("Failed to set key on DB");
723 ThrowMsg(Exception::InvalidArguments, result);
730 void SqlConnection::ResetKey(const RawBuffer &rawPassOld,
731 const RawBuffer &rawPassNew)
733 if (m_connection == NULL) {
734 LogPedantic("Cannot reset key. No connection to DB!");
738 AssertMsg(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
739 rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE,
740 "Binary data for raw password should be 32 bytes long.");
742 // sqlcipher3_rekey requires for key to be already set
746 RawBuffer pass = createHexPass(rawPassNew);
747 int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
749 if (result == SQLCIPHER_OK) {
750 LogPedantic("Reset key on DB");
752 //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
754 LogError("Failed to reset key on DB");
755 ThrowMsg(Exception::InvalidArguments, result);
760 void SqlConnection::Disconnect()
762 if (m_connection == NULL) {
763 LogPedantic("Already disconnected.");
767 LogPedantic("Disconnecting from DB...");
769 // All stored data commands must be deleted before disconnect
770 AssertMsg(m_dataCommandsCount == 0,
771 "All stored procedures must be deleted"
772 " before disconnecting SqlConnection");
776 result = sqlcipher3_close(m_connection);
778 if (result != SQLCIPHER_OK) {
779 const char *error = sqlcipher3_errmsg(m_connection);
780 LogError("SQL close failed");
781 LogError(" Error: " << error);
782 Throw(Exception::InternalError);
787 LogPedantic("Disconnected from DB");
790 bool SqlConnection::CheckTableExist(const char *tableName)
792 if (m_connection == NULL) {
793 LogPedantic("Cannot execute command. Not connected to DB!");
797 DataCommandUniquePtr command =
798 PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
800 command->BindString(1, tableName);
802 if (!command->Step()) {
803 LogPedantic("No matching records in table");
807 return command->GetColumnString(0) == tableName;
810 SqlConnection::SqlConnection(const std::string &address,
812 SynchronizationObject *synchronizationObject) :
814 m_dataCommandsCount(0),
815 m_synchronizationObject(synchronizationObject),
818 LogPedantic("Opening database connection to: " << address);
821 SqlConnection::Connect(address, option);
823 if (!m_synchronizationObject)
824 LogPedantic("No synchronization object defined");
827 SqlConnection::~SqlConnection()
829 LogPedantic("Closing database connection");
831 // Disconnect from DB
833 SqlConnection::Disconnect();
834 } catch (const Exception::Base &) {
835 LogError("Failed to disconnect from database");
840 int SqlConnection::Output::Callback(void *param, int columns, char **values,
844 static_cast<Output *>(param)->SetResults(columns, values, names);
849 void SqlConnection::Output::SetResults(int columns, char **values, char **names)
851 if (m_names.empty()) {
852 for (int i = 0; i < columns; i++)
853 m_names.push_back(names[i] ? names[i] : "NULL");
858 for (int i = 0; i < columns; i++)
859 row.push_back(values[i] ? values[i] : "NULL");
861 m_values.push_back(std::move(row));
865 void SqlConnection::ExecCommandHelper(Output *out, const char *format,
868 if (m_connection == NULL) {
869 LogError("Cannot execute command. Not connected to DB!");
873 if (format == NULL) {
874 LogError("Null query!");
875 ThrowMsg(Exception::SyntaxError, "Null statement");
880 if (vasprintf(&query, format, args) == -1) {
881 LogError("Failed to allocate statement string");
885 CharUniquePtr queryPtr(query);
887 LogPedantic("Executing SQL command: " << queryPtr.get());
889 // Notify all after potentially synchronized database connection access
890 ScopedNotifyAll notifyAll(m_synchronizationObject.get());
892 for (int i = 0; i < MAX_RETRY; i++) {
894 int ret = sqlcipher3_exec(m_connection,
896 out ? &Output::Callback : NULL,
900 std::string errorMsg;
902 // Take allocated error buffer
903 if (errorBuffer != NULL) {
904 errorMsg = errorBuffer;
905 sqlcipher3_free(errorBuffer);
908 if (ret == SQLCIPHER_OK)
911 if (ret == SQLCIPHER_BUSY) {
912 LogPedantic("Collision occurred while executing SQL command");
914 // Synchronize if synchronization object is available
915 if (m_synchronizationObject) {
916 LogPedantic("Performing synchronization");
917 m_synchronizationObject->Synchronize();
921 // No synchronization object defined. Fail.
925 LogError("Failed to execute SQL command. Error: " << errorMsg);
926 ThrowMsg(Exception::SyntaxError, errorMsg);
929 LogError("sqlite in the state of possible infinite loop");
930 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
934 void SqlConnection::ExecCommand(Output *out, const char *format, ...)
937 va_start(args, format);
939 ExecCommandHelper(out, format, args);
948 void SqlConnection::ExecCommand(const char *format, ...)
951 va_start(args, format);
953 ExecCommandHelper(NULL, format, args);
961 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
965 if (m_connection == NULL) {
966 LogError("Cannot execute data command. Not connected to DB!");
967 return DataCommandUniquePtr();
973 va_start(args, format);
975 if (vasprintf(&rawBuffer, format, args) == -1)
980 CharUniquePtr buffer(rawBuffer);
983 LogError("Failed to allocate statement string");
984 return DataCommandUniquePtr();
987 LogPedantic("Executing SQL data command: " << buffer.get());
989 return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
993 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
995 return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
999 void SqlConnection::TurnOnForeignKeys()
1001 ExecCommand("PRAGMA foreign_keys = ON;");
1004 void SqlConnection::BeginTransaction()
1006 ExecCommand("BEGIN;");
1009 void SqlConnection::RollbackTransaction()
1011 ExecCommand("ROLLBACK;");
1014 void SqlConnection::CommitTransaction()
1016 ExecCommand("COMMIT;");
1019 SqlConnection::SynchronizationObject *
1020 SqlConnection::AllocDefaultSynchronizationObject()
1022 return new NaiveSynchronizationObject();
1027 #pragma GCC diagnostic pop