2 * Copyright (c) 2014 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
48 SqlConnection::SynchronizationObject *m_synchronizationObject;
51 NONCOPYABLE(ScopedNotifyAll)
53 explicit ScopedNotifyAll(
54 SqlConnection::SynchronizationObject *synchronizationObject) :
55 m_synchronizationObject(synchronizationObject)
60 if (!m_synchronizationObject) {
64 LogPedantic("Notifying after successful synchronize");
65 m_synchronizationObject->NotifyAll();
68 } // namespace anonymous
70 SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
72 m_masterConnection(connection),
75 Assert(connection != NULL);
77 // Notify all after potentially synchronized database connection access
78 ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
80 for (int i = 0; i < MAX_RETRY; i++) {
81 int ret = sqlcipher3_prepare_v2(connection->m_connection,
82 buffer, strlen(buffer),
85 if (ret == SQLCIPHER_OK) {
86 LogPedantic("Prepared data command: " << buffer);
88 // Increment stored data command count
89 ++m_masterConnection->m_dataCommandsCount;
91 } else if (ret == SQLCIPHER_BUSY) {
92 LogPedantic("Collision occurred while preparing SQL command");
94 // Synchronize if synchronization object is available
95 if (connection->m_synchronizationObject) {
96 LogPedantic("Performing synchronization");
97 connection->m_synchronizationObject->Synchronize();
101 // No synchronization object defined. Fail.
105 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
107 LogError("SQL prepare data command failed");
108 LogError(" Statement: " << buffer);
109 LogError(" Error: " << error);
111 ThrowMsg(Exception::SyntaxError, error);
114 LogError("sqlite in the state of possible infinite loop");
115 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
118 SqlConnection::DataCommand::~DataCommand()
120 LogPedantic("SQL data command finalizing");
122 if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK) {
123 LogError("Failed to finalize data command");
126 // Decrement stored data command count
127 --m_masterConnection->m_dataCommandsCount;
130 void SqlConnection::DataCommand::CheckBindResult(int result)
132 if (result != SQLCIPHER_OK) {
133 const char *error = sqlcipher3_errmsg(
134 m_masterConnection->m_connection);
136 LogError("Failed to bind SQL statement parameter");
137 LogError(" Error: " << error);
139 ThrowMsg(Exception::SyntaxError, error);
143 void SqlConnection::DataCommand::BindNull(
144 SqlConnection::ArgumentIndex position)
146 CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
147 LogPedantic("SQL data command bind null: ["
151 void SqlConnection::DataCommand::BindInteger(
152 SqlConnection::ArgumentIndex position,
155 CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
156 LogPedantic("SQL data command bind integer: ["
157 << 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);
219 void SqlConnection::DataCommand::BindString(
220 SqlConnection::ArgumentIndex position,
228 // Assume that text may disappear
229 CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
230 value, strlen(value),
231 SQLCIPHER_TRANSIENT));
233 LogPedantic("SQL data command bind string: ["
234 << position << "] -> " << value);
237 void SqlConnection::DataCommand::BindBlob(
238 SqlConnection::ArgumentIndex position,
239 const RawBuffer &raw)
241 if (raw.size() == 0) {
246 // Assume that blob may dissappear
247 CheckBindResult(sqlcipher3_bind_blob(m_stmt, position,
248 raw.data(), raw.size(),
249 SQLCIPHER_TRANSIENT));
250 LogPedantic("SQL data command bind blob of size: ["
251 << position << "] -> " << raw.size());
254 void SqlConnection::DataCommand::BindInteger(
255 SqlConnection::ArgumentIndex position,
256 const boost::optional<int> &value)
261 BindInteger(position, *value);
265 void SqlConnection::DataCommand::BindInt8(
266 SqlConnection::ArgumentIndex position,
267 const boost::optional<int8_t> &value)
272 BindInt8(position, *value);
276 void SqlConnection::DataCommand::BindInt16(
277 SqlConnection::ArgumentIndex position,
278 const boost::optional<int16_t> &value)
283 BindInt16(position, *value);
287 void SqlConnection::DataCommand::BindInt32(
288 SqlConnection::ArgumentIndex position,
289 const boost::optional<int32_t> &value)
294 BindInt32(position, *value);
298 void SqlConnection::DataCommand::BindInt64(
299 SqlConnection::ArgumentIndex position,
300 const boost::optional<int64_t> &value)
305 BindInt64(position, *value);
309 void SqlConnection::DataCommand::BindFloat(
310 SqlConnection::ArgumentIndex position,
311 const boost::optional<float> &value)
316 BindFloat(position, *value);
320 void SqlConnection::DataCommand::BindDouble(
321 SqlConnection::ArgumentIndex position,
322 const boost::optional<double> &value)
327 BindDouble(position, *value);
331 void SqlConnection::DataCommand::BindBlob(
332 SqlConnection::ArgumentIndex position,
333 const boost::optional<RawBuffer> &value)
336 BindBlob(position, *value);
342 bool SqlConnection::DataCommand::Step()
344 // Notify all after potentially synchronized database connection access
345 ScopedNotifyAll notifyAll(
346 m_masterConnection->m_synchronizationObject.get());
348 for (int i = 0; i < MAX_RETRY; i++) {
349 int ret = sqlcipher3_step(m_stmt);
351 if (ret == SQLCIPHER_ROW) {
352 LogPedantic("SQL data command step ROW");
354 } else if (ret == SQLCIPHER_DONE) {
355 LogPedantic("SQL data command step DONE");
357 } else if (ret == SQLCIPHER_BUSY) {
358 LogPedantic("Collision occurred while executing SQL command");
360 // Synchronize if synchronization object is available
361 if (m_masterConnection->m_synchronizationObject) {
362 LogPedantic("Performing synchronization");
365 m_synchronizationObject->Synchronize();
369 // No synchronization object defined. Fail.
373 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
375 LogError("SQL step data command failed");
376 LogError(" Error: " << error);
378 ThrowMsg(Exception::InternalError, error);
381 LogError("sqlite in the state of possible infinite loop");
382 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
385 void SqlConnection::DataCommand::Reset()
389 * http://www.sqllite.org/c3ref/stmt.html
391 * if last sqlcipher3_step command on this stmt returned an error,
392 * then sqlcipher3_reset will return that error, althought it is not an error.
393 * So sqlcipher3_reset allways succedes.
395 sqlcipher3_reset(m_stmt);
397 LogPedantic("SQL data command reset");
400 void SqlConnection::DataCommand::CheckColumnIndex(
401 SqlConnection::ColumnIndex column)
403 if (column < 0 || column >= sqlcipher3_column_count(m_stmt)) {
404 ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
408 bool SqlConnection::DataCommand::IsColumnNull(
409 SqlConnection::ColumnIndex column)
411 LogPedantic("SQL data command get column type: [" << column << "]");
412 CheckColumnIndex(column);
413 return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
416 int SqlConnection::DataCommand::GetColumnInteger(
417 SqlConnection::ColumnIndex column)
419 LogPedantic("SQL data command get column integer: [" << column << "]");
420 CheckColumnIndex(column);
421 int value = sqlcipher3_column_int(m_stmt, column);
422 LogPedantic(" Value: " << value);
426 int8_t SqlConnection::DataCommand::GetColumnInt8(
427 SqlConnection::ColumnIndex column)
429 LogPedantic("SQL data command get column int8: [" << column << "]");
430 CheckColumnIndex(column);
431 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
432 LogPedantic(" Value: " << value);
436 int16_t SqlConnection::DataCommand::GetColumnInt16(
437 SqlConnection::ColumnIndex column)
439 LogPedantic("SQL data command get column int16: [" << column << "]");
440 CheckColumnIndex(column);
441 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
442 LogPedantic(" Value: " << value);
446 int32_t SqlConnection::DataCommand::GetColumnInt32(
447 SqlConnection::ColumnIndex column)
449 LogPedantic("SQL data command get column int32: [" << column << "]");
450 CheckColumnIndex(column);
451 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
452 LogPedantic(" Value: " << value);
456 int64_t SqlConnection::DataCommand::GetColumnInt64(
457 SqlConnection::ColumnIndex column)
459 LogPedantic("SQL data command get column int64: [" << column << "]");
460 CheckColumnIndex(column);
461 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
462 LogPedantic(" Value: " << value);
466 float SqlConnection::DataCommand::GetColumnFloat(
467 SqlConnection::ColumnIndex column)
469 LogPedantic("SQL data command get column float: [" << column << "]");
470 CheckColumnIndex(column);
471 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
472 LogPedantic(" Value: " << value);
476 double SqlConnection::DataCommand::GetColumnDouble(
477 SqlConnection::ColumnIndex column)
479 LogPedantic("SQL data command get column double: [" << column << "]");
480 CheckColumnIndex(column);
481 double value = sqlcipher3_column_double(m_stmt, column);
482 LogPedantic(" Value: " << value);
486 std::string SqlConnection::DataCommand::GetColumnString(
487 SqlConnection::ColumnIndex column)
489 LogPedantic("SQL data command get column string: [" << column << "]");
490 CheckColumnIndex(column);
492 const char *value = reinterpret_cast<const char *>(
493 sqlcipher3_column_text(m_stmt, column));
495 LogPedantic("Value: " << (value ? value : "NULL"));
498 return std::string();
501 return std::string(value);
504 RawBuffer SqlConnection::DataCommand::GetColumnBlob(
505 SqlConnection::ColumnIndex column)
507 LogPedantic("SQL data command get column blog: [" << column << "]");
508 CheckColumnIndex(column);
510 const unsigned char *value = reinterpret_cast<const unsigned char*>(
511 sqlcipher3_column_blob(m_stmt, column));
517 int length = sqlcipher3_column_bytes(m_stmt, column);
518 LogPedantic("Got blob of length: " << length);
520 return RawBuffer(value, value + length);
523 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
524 SqlConnection::ColumnIndex column)
526 LogPedantic("SQL data command get column optional integer: ["
528 CheckColumnIndex(column);
529 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
530 return boost::optional<int>();
532 int value = sqlcipher3_column_int(m_stmt, column);
533 LogPedantic(" Value: " << value);
534 return boost::optional<int>(value);
537 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
538 SqlConnection::ColumnIndex column)
540 LogPedantic("SQL data command get column optional int8: ["
542 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);
557 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
558 return boost::optional<int16_t>();
560 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
561 LogPedantic(" Value: " << value);
562 return boost::optional<int16_t>(value);
565 boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
566 SqlConnection::ColumnIndex column)
568 LogPedantic("SQL data command get column optional int32: ["
570 CheckColumnIndex(column);
571 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
572 return boost::optional<int32_t>();
574 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
575 LogPedantic(" Value: " << value);
576 return boost::optional<int32_t>(value);
579 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
580 SqlConnection::ColumnIndex column)
582 LogPedantic("SQL data command get column optional int64: ["
584 CheckColumnIndex(column);
585 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
586 return boost::optional<int64_t>();
588 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
589 LogPedantic(" Value: " << value);
590 return boost::optional<int64_t>(value);
593 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
594 SqlConnection::ColumnIndex column)
596 LogPedantic("SQL data command get column optional float: ["
598 CheckColumnIndex(column);
599 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
600 return boost::optional<float>();
602 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
603 LogPedantic(" Value: " << value);
604 return boost::optional<float>(value);
607 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
608 SqlConnection::ColumnIndex column)
610 LogPedantic("SQL data command get column optional double: ["
612 CheckColumnIndex(column);
613 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
614 return boost::optional<double>();
616 double value = sqlcipher3_column_double(m_stmt, column);
617 LogPedantic(" Value: " << value);
618 return boost::optional<double>(value);
621 boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
622 SqlConnection::ColumnIndex column)
624 LogPedantic("SQL data command get column blog: [" << column << "]");
625 CheckColumnIndex(column);
627 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
628 return boost::optional<RawBuffer>();
630 const unsigned char *value = reinterpret_cast<const unsigned char*>(
631 sqlcipher3_column_blob(m_stmt, column));
633 return boost::optional<RawBuffer>();
636 int length = sqlcipher3_column_bytes(m_stmt, column);
637 LogPedantic("Got blob of length: " << length);
639 RawBuffer temp(value, value + length);
640 return boost::optional<RawBuffer>(temp);
643 void SqlConnection::Connect(const std::string &address,
646 if (m_connection != NULL) {
647 LogPedantic("Already connected.");
650 LogPedantic("Connecting to DB: " << address << "...");
652 // Connect to database
654 result = sqlcipher3_open_v2(
660 if (result == SQLCIPHER_OK) {
661 LogPedantic("Connected to DB");
663 LogError("Failed to connect to DB!");
664 ThrowMsg(Exception::ConnectionBroken, address);
667 // Enable foreign keys
671 const std::string SQLCIPHER_RAW_PREFIX="x'";
672 const std::string SQLCIPHER_RAW_SUFIX="'";
673 const std::size_t SQLCIPHER_RAW_DATA_SIZE = 32;
675 RawBuffer rawToHexString(const RawBuffer &raw)
680 snprintf(result, sizeof(result), "%02X", static_cast<unsigned int>(e));
681 output.push_back(static_cast<unsigned char>(result[0]));
682 output.push_back(static_cast<unsigned char>(result[1]));
687 RawBuffer createHexPass(const RawBuffer &rawPass){
688 // We are required to pass 64byte long hex password made out of 32byte raw
691 std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
692 std::back_inserter(output));
694 RawBuffer password = rawToHexString(rawPass);
696 std::copy(password.begin(), password.end(),
697 std::back_inserter(output));
699 std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
700 std::back_inserter(output));
705 void SqlConnection::SetKey(const RawBuffer &rawPass){
706 if (m_connection == NULL) {
707 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.");
713 RawBuffer pass = createHexPass(rawPass);
714 int result = sqlcipher3_key(m_connection, pass.data(), pass.size());
715 if (result == SQLCIPHER_OK) {
716 LogPedantic("Set key on DB");
718 //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
720 LogError("Failed to set key on DB");
721 ThrowMsg(Exception::InvalidArguments, result);
727 void SqlConnection::ResetKey(const RawBuffer &rawPassOld,
728 const RawBuffer &rawPassNew) {
729 if (m_connection == NULL) {
730 LogPedantic("Cannot reset key. No connection to DB!");
733 AssertMsg(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
734 rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE,
735 "Binary data for raw password should be 32 bytes long."
737 // sqlcipher3_rekey requires for key to be already set
741 RawBuffer pass = createHexPass(rawPassNew);
742 int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
743 if (result == SQLCIPHER_OK) {
744 LogPedantic("Reset key on DB");
746 //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
748 LogError("Failed to reset key on DB");
749 ThrowMsg(Exception::InvalidArguments, result);
753 void SqlConnection::Disconnect()
755 if (m_connection == NULL) {
756 LogPedantic("Already disconnected.");
760 LogPedantic("Disconnecting from DB...");
762 // All stored data commands must be deleted before disconnect
763 AssertMsg(m_dataCommandsCount == 0,
764 "All stored procedures must be deleted"
765 " before disconnecting SqlConnection");
769 result = sqlcipher3_close(m_connection);
771 if (result != SQLCIPHER_OK) {
772 const char *error = sqlcipher3_errmsg(m_connection);
773 LogError("SQL close failed");
774 LogError(" Error: " << error);
775 Throw(Exception::InternalError);
780 LogPedantic("Disconnected from DB");
783 bool SqlConnection::CheckTableExist(const char *tableName)
785 if (m_connection == NULL) {
786 LogPedantic("Cannot execute command. Not connected to DB!");
790 DataCommandUniquePtr command =
791 PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
793 command->BindString(1, tableName);
795 if (!command->Step()) {
796 LogPedantic("No matching records in table");
800 return command->GetColumnString(0) == tableName;
803 SqlConnection::SqlConnection(const std::string &address,
805 SynchronizationObject *synchronizationObject) :
807 m_dataCommandsCount(0),
808 m_synchronizationObject(synchronizationObject),
811 LogPedantic("Opening database connection to: " << address);
814 SqlConnection::Connect(address, option);
816 if (!m_synchronizationObject) {
817 LogPedantic("No synchronization object defined");
821 SqlConnection::~SqlConnection()
823 LogPedantic("Closing database connection");
825 // Disconnect from DB
828 SqlConnection::Disconnect();
830 Catch(Exception::Base)
832 LogError("Failed to disconnect from database");
836 void SqlConnection::ExecCommand(const char *format, ...)
838 if (m_connection == NULL) {
839 LogError("Cannot execute command. Not connected to DB!");
843 if (format == NULL) {
844 LogError("Null query!");
845 ThrowMsg(Exception::SyntaxError, "Null statement");
851 va_start(args, format);
853 if (vasprintf(&rawBuffer, format, args) == -1) {
859 CharUniquePtr buffer(rawBuffer);
862 LogError("Failed to allocate statement string");
866 LogPedantic("Executing SQL command: " << buffer.get());
868 // Notify all after potentially synchronized database connection access
869 ScopedNotifyAll notifyAll(m_synchronizationObject.get());
871 for (int i = 0; i < MAX_RETRY; i++) {
874 int ret = sqlcipher3_exec(m_connection,
880 std::string errorMsg;
882 // Take allocated error buffer
883 if (errorBuffer != NULL) {
884 errorMsg = errorBuffer;
885 sqlcipher3_free(errorBuffer);
888 if (ret == SQLCIPHER_OK) {
892 if (ret == SQLCIPHER_BUSY) {
893 LogPedantic("Collision occurred while executing SQL command");
895 // Synchronize if synchronization object is available
896 if (m_synchronizationObject) {
897 LogPedantic("Performing synchronization");
898 m_synchronizationObject->Synchronize();
902 // No synchronization object defined. Fail.
906 LogError("Failed to execute SQL command. Error: " << errorMsg);
907 ThrowMsg(Exception::SyntaxError, errorMsg);
910 LogError("sqlite in the state of possible infinite loop");
911 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
914 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
918 if (m_connection == NULL) {
919 LogError("Cannot execute data command. Not connected to DB!");
920 return DataCommandUniquePtr();
926 va_start(args, format);
928 if (vasprintf(&rawBuffer, format, args) == -1) {
934 CharUniquePtr buffer(rawBuffer);
937 LogError("Failed to allocate statement string");
938 return DataCommandUniquePtr();
941 LogPedantic("Executing SQL data command: " << buffer.get());
943 return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
946 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
948 return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
951 void SqlConnection::TurnOnForeignKeys()
953 ExecCommand("PRAGMA foreign_keys = ON;");
956 void SqlConnection::BeginTransaction()
958 ExecCommand("BEGIN;");
961 void SqlConnection::RollbackTransaction()
963 ExecCommand("ROLLBACK;");
966 void SqlConnection::CommitTransaction()
968 ExecCommand("COMMIT;");
971 SqlConnection::SynchronizationObject *
972 SqlConnection::AllocDefaultSynchronizationObject()
974 return new NaiveSynchronizationObject();
979 #pragma GCC diagnostic pop