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/noncopyable.h>
29 #include <dpl/assert.h>
30 #include <dpl/scoped_ptr.h>
31 #include <dpl/TransitoryString.h>
38 #include <safe-buffer.h>
42 namespace // anonymous
44 class ScopedNotifyAll :
48 SqlConnection::SynchronizationObject *m_synchronizationObject;
51 explicit ScopedNotifyAll(
52 SqlConnection::SynchronizationObject *synchronizationObject) :
53 m_synchronizationObject(synchronizationObject)
58 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());
79 int ret = sqlcipher3_prepare_v2(connection->m_connection,
80 buffer, strlen(buffer),
83 if (ret == SQLCIPHER_OK) {
84 LogPedantic("Data command prepared successfuly");
86 } else if (ret == SQLCIPHER_BUSY) {
87 LogPedantic("Collision occurred while preparing SQL command");
89 // Synchronize if synchronization object is available
90 if (connection->m_synchronizationObject) {
91 LogPedantic("Performing synchronization");
92 connection->m_synchronizationObject->Synchronize();
96 // No synchronization object defined. Fail.
100 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
102 LogError("SQL prepare data command failed");
103 LogError(" Statement: " << buffer);
104 LogError(" Error: " << error);
106 ThrowMsg(Exception::SyntaxError, error);
109 LogPedantic("Prepared data command: " << buffer);
111 // Increment stored data command count
112 ++m_masterConnection->m_dataCommandsCount;
115 SqlConnection::DataCommand::~DataCommand()
117 LogPedantic("SQL data command finalizing");
119 if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK) {
120 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);
140 void SqlConnection::DataCommand::BindNull(
141 SqlConnection::ArgumentIndex position)
143 CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
144 LogPedantic("SQL data command bind null: ["
148 void SqlConnection::DataCommand::BindInteger(
149 SqlConnection::ArgumentIndex position,
152 CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
153 LogPedantic("SQL data command bind integer: ["
154 << position << "] -> " << value);
157 void SqlConnection::DataCommand::BindInt8(
158 SqlConnection::ArgumentIndex position,
161 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
162 static_cast<int>(value)));
163 LogPedantic("SQL data command bind int8: ["
164 << position << "] -> " << value);
167 void SqlConnection::DataCommand::BindInt16(
168 SqlConnection::ArgumentIndex position,
171 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
172 static_cast<int>(value)));
173 LogPedantic("SQL data command bind int16: ["
174 << position << "] -> " << value);
177 void SqlConnection::DataCommand::BindInt32(
178 SqlConnection::ArgumentIndex position,
181 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
182 static_cast<int>(value)));
183 LogPedantic("SQL data command bind int32: ["
184 << position << "] -> " << value);
187 void SqlConnection::DataCommand::BindInt64(
188 SqlConnection::ArgumentIndex position,
191 CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
192 static_cast<sqlcipher3_int64>(value)));
193 LogPedantic("SQL data command bind int64: ["
194 << position << "] -> " << value);
197 void SqlConnection::DataCommand::BindFloat(
198 SqlConnection::ArgumentIndex position,
201 CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
202 static_cast<double>(value)));
203 LogPedantic("SQL data command bind float: ["
204 << position << "] -> " << value);
207 void SqlConnection::DataCommand::BindDouble(
208 SqlConnection::ArgumentIndex position,
211 CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
212 LogPedantic("SQL data command bind double: ["
213 << position << "] -> " << value);
216 void SqlConnection::DataCommand::BindString(
217 SqlConnection::ArgumentIndex position,
225 // Assume that text may disappear
226 CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
227 value, strlen(value),
228 SQLCIPHER_TRANSIENT));
230 LogPedantic("SQL data command bind string: ["
231 << position << "] -> " << value);
234 void SqlConnection::DataCommand::BindBlob(
235 SqlConnection::ArgumentIndex position,
236 const SafeBuffer &raw)
238 if (raw.size() == 0) {
243 // Assume that blob may dissappear
244 CheckBindResult(sqlcipher3_bind_blob(m_stmt, position,
245 raw.data(), raw.size(),
246 SQLCIPHER_TRANSIENT));
247 LogPedantic("SQL data command bind blob of size: ["
248 << position << "] -> " << raw.size());
251 void SqlConnection::DataCommand::BindString(
252 SqlConnection::ArgumentIndex position,
255 BindString(position, ToUTF8String(value).c_str());
258 void SqlConnection::DataCommand::BindInteger(
259 SqlConnection::ArgumentIndex position,
260 const boost::optional<int> &value)
265 BindInteger(position, *value);
269 void SqlConnection::DataCommand::BindInt8(
270 SqlConnection::ArgumentIndex position,
271 const boost::optional<int8_t> &value)
276 BindInt8(position, *value);
280 void SqlConnection::DataCommand::BindInt16(
281 SqlConnection::ArgumentIndex position,
282 const boost::optional<int16_t> &value)
287 BindInt16(position, *value);
291 void SqlConnection::DataCommand::BindInt32(
292 SqlConnection::ArgumentIndex position,
293 const boost::optional<int32_t> &value)
298 BindInt32(position, *value);
302 void SqlConnection::DataCommand::BindInt64(
303 SqlConnection::ArgumentIndex position,
304 const boost::optional<int64_t> &value)
309 BindInt64(position, *value);
313 void SqlConnection::DataCommand::BindFloat(
314 SqlConnection::ArgumentIndex position,
315 const boost::optional<float> &value)
320 BindFloat(position, *value);
324 void SqlConnection::DataCommand::BindDouble(
325 SqlConnection::ArgumentIndex position,
326 const boost::optional<double> &value)
331 BindDouble(position, *value);
335 void SqlConnection::DataCommand::BindString(
336 SqlConnection::ArgumentIndex position,
337 const boost::optional<String> &value)
340 BindString(position, ToUTF8String(*value).c_str());
346 void SqlConnection::DataCommand::BindBlob(
347 SqlConnection::ArgumentIndex position,
348 const boost::optional<SafeBuffer> &value)
351 BindBlob(position, *value);
357 bool SqlConnection::DataCommand::Step()
359 // Notify all after potentially synchronized database connection access
360 ScopedNotifyAll notifyAll(
361 m_masterConnection->m_synchronizationObject.get());
364 int ret = sqlcipher3_step(m_stmt);
366 if (ret == SQLCIPHER_ROW) {
367 LogPedantic("SQL data command step ROW");
369 } else if (ret == SQLCIPHER_DONE) {
370 LogPedantic("SQL data command step DONE");
372 } else if (ret == SQLCIPHER_BUSY) {
373 LogPedantic("Collision occurred while executing SQL command");
375 // Synchronize if synchronization object is available
376 if (m_masterConnection->m_synchronizationObject) {
377 LogPedantic("Performing synchronization");
380 m_synchronizationObject->Synchronize();
385 // No synchronization object defined. Fail.
389 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
391 LogError("SQL step data command failed");
392 LogError(" Error: " << error);
394 ThrowMsg(Exception::InternalError, error);
398 void SqlConnection::DataCommand::Reset()
402 * http://www.sqllite.org/c3ref/stmt.html
404 * if last sqlcipher3_step command on this stmt returned an error,
405 * then sqlcipher3_reset will return that error, althought it is not an error.
406 * So sqlcipher3_reset allways succedes.
408 sqlcipher3_reset(m_stmt);
410 LogPedantic("SQL data command reset");
413 void SqlConnection::DataCommand::CheckColumnIndex(
414 SqlConnection::ColumnIndex column)
416 if (column < 0 || column >= sqlcipher3_column_count(m_stmt)) {
417 ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
421 bool SqlConnection::DataCommand::IsColumnNull(
422 SqlConnection::ColumnIndex column)
424 LogPedantic("SQL data command get column type: [" << column << "]");
425 CheckColumnIndex(column);
426 return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
429 int SqlConnection::DataCommand::GetColumnInteger(
430 SqlConnection::ColumnIndex column)
432 LogPedantic("SQL data command get column integer: [" << column << "]");
433 CheckColumnIndex(column);
434 int value = sqlcipher3_column_int(m_stmt, column);
435 LogPedantic(" Value: " << value);
439 int8_t SqlConnection::DataCommand::GetColumnInt8(
440 SqlConnection::ColumnIndex column)
442 LogPedantic("SQL data command get column int8: [" << column << "]");
443 CheckColumnIndex(column);
444 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
445 LogPedantic(" Value: " << value);
449 int16_t SqlConnection::DataCommand::GetColumnInt16(
450 SqlConnection::ColumnIndex column)
452 LogPedantic("SQL data command get column int16: [" << column << "]");
453 CheckColumnIndex(column);
454 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
455 LogPedantic(" Value: " << value);
459 int32_t SqlConnection::DataCommand::GetColumnInt32(
460 SqlConnection::ColumnIndex column)
462 LogPedantic("SQL data command get column int32: [" << column << "]");
463 CheckColumnIndex(column);
464 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
465 LogPedantic(" Value: " << value);
469 int64_t SqlConnection::DataCommand::GetColumnInt64(
470 SqlConnection::ColumnIndex column)
472 LogPedantic("SQL data command get column int64: [" << column << "]");
473 CheckColumnIndex(column);
474 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
475 LogPedantic(" Value: " << value);
479 float SqlConnection::DataCommand::GetColumnFloat(
480 SqlConnection::ColumnIndex column)
482 LogPedantic("SQL data command get column float: [" << column << "]");
483 CheckColumnIndex(column);
484 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
485 LogPedantic(" Value: " << value);
489 double SqlConnection::DataCommand::GetColumnDouble(
490 SqlConnection::ColumnIndex column)
492 LogPedantic("SQL data command get column double: [" << column << "]");
493 CheckColumnIndex(column);
494 double value = sqlcipher3_column_double(m_stmt, column);
495 LogPedantic(" Value: " << value);
499 std::string SqlConnection::DataCommand::GetColumnString(
500 SqlConnection::ColumnIndex column)
502 LogPedantic("SQL data command get column string: [" << column << "]");
503 CheckColumnIndex(column);
505 const char *value = reinterpret_cast<const char *>(
506 sqlcipher3_column_text(m_stmt, column));
508 LogPedantic("Value: " << (value ? value : "NULL"));
511 return std::string();
514 return std::string(value);
517 SafeBuffer SqlConnection::DataCommand::GetColumnBlob(
518 SqlConnection::ColumnIndex column)
520 LogPedantic("SQL data command get column blog: [" << column << "]");
521 CheckColumnIndex(column);
523 const unsigned char *value = reinterpret_cast<const unsigned char*>(
524 sqlcipher3_column_blob(m_stmt, column));
530 int length = sqlcipher3_column_bytes(m_stmt, column);
531 LogPedantic("Got blob of length: " << length);
533 return SafeBuffer(value, value + length);
536 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
537 SqlConnection::ColumnIndex column)
539 LogPedantic("SQL data command get column optional integer: ["
541 CheckColumnIndex(column);
542 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
543 return boost::optional<int>();
545 int value = sqlcipher3_column_int(m_stmt, column);
546 LogPedantic(" Value: " << value);
547 return boost::optional<int>(value);
550 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
551 SqlConnection::ColumnIndex column)
553 LogPedantic("SQL data command get column optional int8: ["
555 CheckColumnIndex(column);
556 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
557 return boost::optional<int8_t>();
559 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
560 LogPedantic(" Value: " << value);
561 return boost::optional<int8_t>(value);
564 boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
565 SqlConnection::ColumnIndex column)
567 LogPedantic("SQL data command get column optional int16: ["
569 CheckColumnIndex(column);
570 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
571 return boost::optional<int16_t>();
573 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
574 LogPedantic(" Value: " << value);
575 return boost::optional<int16_t>(value);
578 boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
579 SqlConnection::ColumnIndex column)
581 LogPedantic("SQL data command get column optional int32: ["
583 CheckColumnIndex(column);
584 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
585 return boost::optional<int32_t>();
587 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
588 LogPedantic(" Value: " << value);
589 return boost::optional<int32_t>(value);
592 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
593 SqlConnection::ColumnIndex column)
595 LogPedantic("SQL data command get column optional int64: ["
597 CheckColumnIndex(column);
598 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
599 return boost::optional<int64_t>();
601 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
602 LogPedantic(" Value: " << value);
603 return boost::optional<int64_t>(value);
606 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
607 SqlConnection::ColumnIndex column)
609 LogPedantic("SQL data command get column optional float: ["
611 CheckColumnIndex(column);
612 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
613 return boost::optional<float>();
615 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
616 LogPedantic(" Value: " << value);
617 return boost::optional<float>(value);
620 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
621 SqlConnection::ColumnIndex column)
623 LogPedantic("SQL data command get column optional double: ["
625 CheckColumnIndex(column);
626 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
627 return boost::optional<double>();
629 double value = sqlcipher3_column_double(m_stmt, column);
630 LogPedantic(" Value: " << value);
631 return boost::optional<double>(value);
634 boost::optional<String> SqlConnection::DataCommand::GetColumnOptionalString(
635 SqlConnection::ColumnIndex column)
637 LogPedantic("SQL data command get column optional string: ["
639 CheckColumnIndex(column);
640 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
641 return boost::optional<String>();
643 const char *value = reinterpret_cast<const char *>(
644 sqlcipher3_column_text(m_stmt, column));
645 LogPedantic("Value: " << value);
646 String s = FromUTF8String(value);
647 return boost::optional<String>(s);
650 boost::optional<SafeBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
651 SqlConnection::ColumnIndex column)
653 LogPedantic("SQL data command get column blog: [" << column << "]");
654 CheckColumnIndex(column);
656 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
657 return boost::optional<SafeBuffer>();
659 const unsigned char *value = reinterpret_cast<const unsigned char*>(
660 sqlcipher3_column_blob(m_stmt, column));
662 int length = sqlcipher3_column_bytes(m_stmt, column);
663 LogPedantic("Got blob of length: " << length);
665 SafeBuffer temp(value, value + length);
666 return boost::optional<SafeBuffer>(temp);
669 void SqlConnection::Connect(const std::string &address,
672 if (m_connection != NULL) {
673 LogPedantic("Already connected.");
676 LogPedantic("Connecting to DB: " << address << "...");
678 // Connect to database
680 result = sqlcipher3_open_v2(
686 if (result == SQLCIPHER_OK) {
687 LogPedantic("Connected to DB");
689 LogError("Failed to connect to DB!");
690 ThrowMsg(Exception::ConnectionBroken, address);
693 // Enable foreign keys
697 const std::string SQLCIPHER_RAW_PREFIX="x'";
698 const std::string SQLCIPHER_RAW_SUFIX="'";
699 const std::size_t SQLCIPHER_RAW_DATA_SIZE = 32;
701 void rawToHexString(TransitoryString& str,
703 const SafeBuffer &raw) {
704 for (std::size_t i = 0; i < raw.size(); i++)
705 sprintf(&str[offset + i*2], "%02X", raw[i]);
708 TransitoryString createHexPass(const SafeBuffer &rawPass){
709 TransitoryString pass = TransitoryString('0', SQLCIPHER_RAW_PREFIX.length() +
710 //We are required to pass 64byte
711 //long hex password made out of
712 //32byte raw binary data
714 SQLCIPHER_RAW_SUFIX.length());
715 for(std::size_t i = 0; i < SQLCIPHER_RAW_PREFIX.size(); i++)
716 pass[i] = SQLCIPHER_RAW_PREFIX[i];
717 rawToHexString(pass, SQLCIPHER_RAW_PREFIX.size(), rawPass);
718 for(std::size_t i = 0; i < SQLCIPHER_RAW_SUFIX.size(); i++)
719 pass[i + SQLCIPHER_RAW_PREFIX.size() + rawPass.size() * 2]
720 = SQLCIPHER_RAW_SUFIX[i];
725 void SqlConnection::SetKey(const SafeBuffer &rawPass){
726 if (m_connection == NULL) {
727 LogPedantic("Cannot set key. No connection to DB!");
730 if (rawPass.size() != SQLCIPHER_RAW_DATA_SIZE)
731 ThrowMsg(Exception::InvalidArguments,
732 "Binary data for raw password should be 32 bytes long.");
733 TransitoryString pass = createHexPass(rawPass);
734 int result = sqlcipher3_key(m_connection, pass.c_str(), pass.length());
735 if (result == SQLCIPHER_OK) {
736 LogPedantic("Set key on DB");
738 //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
740 LogError("Failed to set key on DB");
741 ThrowMsg(Exception::InvalidArguments, result);
747 void SqlConnection::ResetKey(const SafeBuffer &rawPassOld,
748 const SafeBuffer &rawPassNew)
750 if (m_connection == NULL) {
751 LogPedantic("Cannot reset key. No connection to DB!");
754 AssertMsg(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
755 rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE,
756 "Binary data for raw password should be 32 bytes long."
758 // sqlcipher3_rekey requires for key to be already set
762 TransitoryString pass = createHexPass(rawPassNew);
763 int result = sqlcipher3_rekey(m_connection, pass.c_str(), pass.length());
764 if (result == SQLCIPHER_OK) {
765 LogPedantic("Reset key on DB");
767 //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
769 LogError("Failed to reset key on DB");
770 ThrowMsg(Exception::InvalidArguments, result);
774 void SqlConnection::Disconnect()
776 if (m_connection == NULL) {
777 LogPedantic("Already disconnected.");
781 LogPedantic("Disconnecting from DB...");
783 // All stored data commands must be deleted before disconnect
784 AssertMsg(m_dataCommandsCount == 0,
785 "All stored procedures must be deleted"
786 " before disconnecting SqlConnection");
790 result = sqlcipher3_close(m_connection);
792 if (result != SQLCIPHER_OK) {
793 const char *error = sqlcipher3_errmsg(m_connection);
794 LogError("SQL close failed");
795 LogError(" Error: " << error);
796 Throw(Exception::InternalError);
801 LogPedantic("Disconnected from DB");
804 bool SqlConnection::CheckTableExist(const char *tableName)
806 if (m_connection == NULL) {
807 LogPedantic("Cannot execute command. Not connected to DB!");
811 DataCommandUniquePtr command =
812 PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
814 command->BindString(1, tableName);
816 if (!command->Step()) {
817 LogPedantic("No matching records in table");
821 return command->GetColumnString(0) == tableName;
824 SqlConnection::SqlConnection(const std::string &address,
826 SynchronizationObject *synchronizationObject) :
828 m_dataCommandsCount(0),
829 m_synchronizationObject(synchronizationObject),
832 LogPedantic("Opening database connection to: " << address);
835 SqlConnection::Connect(address, option);
837 if (!m_synchronizationObject) {
838 LogPedantic("No synchronization object defined");
842 SqlConnection::~SqlConnection()
844 LogPedantic("Closing database connection");
846 // Disconnect from DB
849 SqlConnection::Disconnect();
851 Catch(Exception::Base)
853 LogError("Failed to disconnect from database");
857 void SqlConnection::ExecCommand(const char *format, ...)
859 if (m_connection == NULL) {
860 LogError("Cannot execute command. Not connected to DB!");
864 if (format == NULL) {
865 LogError("Null query!");
866 ThrowMsg(Exception::SyntaxError, "Null statement");
872 va_start(args, format);
874 if (vasprintf(&rawBuffer, format, args) == -1) {
880 CharUniquePtr buffer(rawBuffer);
883 LogError("Failed to allocate statement string");
887 LogPedantic("Executing SQL command: " << buffer.get());
889 // Notify all after potentially synchronized database connection access
890 ScopedNotifyAll notifyAll(m_synchronizationObject.get());
895 int ret = sqlcipher3_exec(m_connection,
901 std::string errorMsg;
903 // Take allocated error buffer
904 if (errorBuffer != NULL) {
905 errorMsg = errorBuffer;
906 sqlcipher3_free(errorBuffer);
909 if (ret == SQLCIPHER_OK) {
913 if (ret == SQLCIPHER_BUSY) {
914 LogPedantic("Collision occurred while executing SQL command");
916 // Synchronize if synchronization object is available
917 if (m_synchronizationObject) {
918 LogPedantic("Performing synchronization");
919 m_synchronizationObject->Synchronize();
923 // No synchronization object defined. Fail.
927 LogError("Failed to execute SQL command. Error: " << errorMsg);
928 ThrowMsg(Exception::SyntaxError, errorMsg);
932 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
936 if (m_connection == NULL) {
937 LogError("Cannot execute data command. Not connected to DB!");
938 return DataCommandUniquePtr();
944 va_start(args, format);
946 if (vasprintf(&rawBuffer, format, args) == -1) {
952 CharUniquePtr buffer(rawBuffer);
955 LogError("Failed to allocate statement string");
956 return DataCommandUniquePtr();
959 LogPedantic("Executing SQL data command: " << buffer.get());
961 return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
964 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
966 return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
969 void SqlConnection::TurnOnForeignKeys()
971 ExecCommand("PRAGMA foreign_keys = ON;");
974 void SqlConnection::BeginTransaction()
976 ExecCommand("BEGIN;");
979 void SqlConnection::RollbackTransaction()
981 ExecCommand("ROLLBACK;");
984 void SqlConnection::CommitTransaction()
986 ExecCommand("COMMIT;");
989 SqlConnection::SynchronizationObject *
990 SqlConnection::AllocDefaultSynchronizationObject()
992 return new NaiveSynchronizationObject();
997 #pragma GCC diagnostic pop