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;
41 ~ScopedVaList() { va_end(args); }
45 #define scoped_va_start(name, param) ScopedVaList name; va_start(name.args, param);
50 namespace // anonymous
55 SqlConnection::SynchronizationObject *m_synchronizationObject;
58 NONCOPYABLE(ScopedNotifyAll)
60 explicit ScopedNotifyAll(
61 SqlConnection::SynchronizationObject *synchronizationObject) :
62 m_synchronizationObject(synchronizationObject)
67 if (!m_synchronizationObject) {
71 LogPedantic("Notifying after successful synchronize");
72 m_synchronizationObject->NotifyAll();
75 } // namespace anonymous
77 SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
79 m_masterConnection(connection),
82 Assert(connection != NULL);
84 // Notify all after potentially synchronized database connection access
85 ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
87 for (int i = 0; i < MAX_RETRY; i++) {
88 int ret = sqlcipher3_prepare_v2(connection->m_connection,
89 buffer, strlen(buffer),
92 if (ret == SQLCIPHER_OK) {
93 LogPedantic("Prepared data command: " << buffer);
95 // Increment stored data command count
96 ++m_masterConnection->m_dataCommandsCount;
98 } else if (ret == SQLCIPHER_BUSY) {
99 LogPedantic("Collision occurred while preparing SQL command");
101 // Synchronize if synchronization object is available
102 if (connection->m_synchronizationObject) {
103 LogPedantic("Performing synchronization");
104 connection->m_synchronizationObject->Synchronize();
108 // No synchronization object defined. Fail.
112 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
114 LogError("SQL prepare data command failed");
115 LogError(" Statement: " << buffer);
116 LogError(" Error: " << error);
118 ThrowMsg(Exception::SyntaxError, error);
121 LogError("sqlite in the state of possible infinite loop");
122 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
125 SqlConnection::DataCommand::~DataCommand()
127 LogPedantic("SQL data command finalizing");
129 if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK) {
130 LogError("Failed to finalize data command");
133 // Decrement stored data command count
134 --m_masterConnection->m_dataCommandsCount;
137 void SqlConnection::DataCommand::CheckBindResult(int result)
139 if (result != SQLCIPHER_OK) {
140 const char *error = sqlcipher3_errmsg(
141 m_masterConnection->m_connection);
143 LogError("Failed to bind SQL statement parameter");
144 LogError(" Error: " << error);
146 ThrowMsg(Exception::SyntaxError, error);
150 void SqlConnection::DataCommand::BindNull(
151 SqlConnection::ArgumentIndex position)
153 CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
154 LogPedantic("SQL data command bind null: ["
158 void SqlConnection::DataCommand::BindInteger(
159 SqlConnection::ArgumentIndex position,
162 CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
163 LogPedantic("SQL data command bind integer: ["
164 << position << "] -> " << value);
167 void SqlConnection::DataCommand::BindInt8(
168 SqlConnection::ArgumentIndex position,
171 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
172 static_cast<int>(value)));
173 LogPedantic("SQL data command bind int8: ["
174 << position << "] -> " << value);
177 void SqlConnection::DataCommand::BindInt16(
178 SqlConnection::ArgumentIndex position,
181 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
182 static_cast<int>(value)));
183 LogPedantic("SQL data command bind int16: ["
184 << position << "] -> " << value);
187 void SqlConnection::DataCommand::BindInt32(
188 SqlConnection::ArgumentIndex position,
191 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
192 static_cast<int>(value)));
193 LogPedantic("SQL data command bind int32: ["
194 << position << "] -> " << value);
197 void SqlConnection::DataCommand::BindInt64(
198 SqlConnection::ArgumentIndex position,
201 CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
202 static_cast<sqlcipher3_int64>(value)));
203 LogPedantic("SQL data command bind int64: ["
204 << position << "] -> " << value);
207 void SqlConnection::DataCommand::BindFloat(
208 SqlConnection::ArgumentIndex position,
211 CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
212 static_cast<double>(value)));
213 LogPedantic("SQL data command bind float: ["
214 << position << "] -> " << value);
217 void SqlConnection::DataCommand::BindDouble(
218 SqlConnection::ArgumentIndex position,
221 CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
222 LogPedantic("SQL data command bind double: ["
223 << position << "] -> " << value);
226 void SqlConnection::DataCommand::BindString(
227 SqlConnection::ArgumentIndex position,
235 // Assume that text may disappear
236 CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
237 value, strlen(value),
238 SQLCIPHER_TRANSIENT));
240 LogPedantic("SQL data command bind string: ["
241 << position << "] -> " << value);
244 void SqlConnection::DataCommand::BindBlob(
245 SqlConnection::ArgumentIndex position,
246 const RawBuffer &raw)
248 if (raw.size() == 0) {
253 // Assume that blob may dissappear
254 CheckBindResult(sqlcipher3_bind_blob(m_stmt, position,
255 raw.data(), raw.size(),
256 SQLCIPHER_TRANSIENT));
257 LogPedantic("SQL data command bind blob of size: ["
258 << position << "] -> " << raw.size());
261 void SqlConnection::DataCommand::BindInteger(
262 SqlConnection::ArgumentIndex position,
263 const boost::optional<int> &value)
268 BindInteger(position, *value);
272 void SqlConnection::DataCommand::BindInt8(
273 SqlConnection::ArgumentIndex position,
274 const boost::optional<int8_t> &value)
279 BindInt8(position, *value);
283 void SqlConnection::DataCommand::BindInt16(
284 SqlConnection::ArgumentIndex position,
285 const boost::optional<int16_t> &value)
290 BindInt16(position, *value);
294 void SqlConnection::DataCommand::BindInt32(
295 SqlConnection::ArgumentIndex position,
296 const boost::optional<int32_t> &value)
301 BindInt32(position, *value);
305 void SqlConnection::DataCommand::BindInt64(
306 SqlConnection::ArgumentIndex position,
307 const boost::optional<int64_t> &value)
312 BindInt64(position, *value);
316 void SqlConnection::DataCommand::BindFloat(
317 SqlConnection::ArgumentIndex position,
318 const boost::optional<float> &value)
323 BindFloat(position, *value);
327 void SqlConnection::DataCommand::BindDouble(
328 SqlConnection::ArgumentIndex position,
329 const boost::optional<double> &value)
334 BindDouble(position, *value);
338 void SqlConnection::DataCommand::BindBlob(
339 SqlConnection::ArgumentIndex position,
340 const boost::optional<RawBuffer> &value)
343 BindBlob(position, *value);
349 bool SqlConnection::DataCommand::Step()
351 // Notify all after potentially synchronized database connection access
352 ScopedNotifyAll notifyAll(
353 m_masterConnection->m_synchronizationObject.get());
355 for (int i = 0; i < MAX_RETRY; i++) {
356 int ret = sqlcipher3_step(m_stmt);
358 if (ret == SQLCIPHER_ROW) {
359 LogPedantic("SQL data command step ROW");
361 } else if (ret == SQLCIPHER_DONE) {
362 LogPedantic("SQL data command step DONE");
364 } else if (ret == SQLCIPHER_BUSY) {
365 LogPedantic("Collision occurred while executing SQL command");
367 // Synchronize if synchronization object is available
368 if (m_masterConnection->m_synchronizationObject) {
369 LogPedantic("Performing synchronization");
372 m_synchronizationObject->Synchronize();
376 // No synchronization object defined. Fail.
380 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
382 LogError("SQL step data command failed");
383 LogError(" Error: " << error);
385 ThrowMsg(Exception::InternalError, error);
388 LogError("sqlite in the state of possible infinite loop");
389 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
392 void SqlConnection::DataCommand::Reset()
396 * http://www.sqllite.org/c3ref/stmt.html
398 * if last sqlcipher3_step command on this stmt returned an error,
399 * then sqlcipher3_reset will return that error, althought it is not an error.
400 * So sqlcipher3_reset allways succedes.
402 sqlcipher3_reset(m_stmt);
404 LogPedantic("SQL data command reset");
407 void SqlConnection::DataCommand::CheckColumnIndex(
408 SqlConnection::ColumnIndex column)
410 if (column < 0 || column >= sqlcipher3_column_count(m_stmt)) {
411 ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
415 bool SqlConnection::DataCommand::IsColumnNull(
416 SqlConnection::ColumnIndex column)
418 LogPedantic("SQL data command get column type: [" << column << "]");
419 CheckColumnIndex(column);
420 return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
423 int SqlConnection::DataCommand::GetColumnInteger(
424 SqlConnection::ColumnIndex column)
426 LogPedantic("SQL data command get column integer: [" << column << "]");
427 CheckColumnIndex(column);
428 int value = sqlcipher3_column_int(m_stmt, column);
429 LogPedantic(" Value: " << value);
433 int8_t SqlConnection::DataCommand::GetColumnInt8(
434 SqlConnection::ColumnIndex column)
436 LogPedantic("SQL data command get column int8: [" << column << "]");
437 CheckColumnIndex(column);
438 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
439 LogPedantic(" Value: " << value);
443 int16_t SqlConnection::DataCommand::GetColumnInt16(
444 SqlConnection::ColumnIndex column)
446 LogPedantic("SQL data command get column int16: [" << column << "]");
447 CheckColumnIndex(column);
448 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
449 LogPedantic(" Value: " << value);
453 int32_t SqlConnection::DataCommand::GetColumnInt32(
454 SqlConnection::ColumnIndex column)
456 LogPedantic("SQL data command get column int32: [" << column << "]");
457 CheckColumnIndex(column);
458 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
459 LogPedantic(" Value: " << value);
463 int64_t SqlConnection::DataCommand::GetColumnInt64(
464 SqlConnection::ColumnIndex column)
466 LogPedantic("SQL data command get column int64: [" << column << "]");
467 CheckColumnIndex(column);
468 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
469 LogPedantic(" Value: " << value);
473 float SqlConnection::DataCommand::GetColumnFloat(
474 SqlConnection::ColumnIndex column)
476 LogPedantic("SQL data command get column float: [" << column << "]");
477 CheckColumnIndex(column);
478 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
479 LogPedantic(" Value: " << value);
483 double SqlConnection::DataCommand::GetColumnDouble(
484 SqlConnection::ColumnIndex column)
486 LogPedantic("SQL data command get column double: [" << column << "]");
487 CheckColumnIndex(column);
488 double value = sqlcipher3_column_double(m_stmt, column);
489 LogPedantic(" Value: " << value);
493 std::string SqlConnection::DataCommand::GetColumnString(
494 SqlConnection::ColumnIndex column)
496 LogPedantic("SQL data command get column string: [" << column << "]");
497 CheckColumnIndex(column);
499 const char *value = reinterpret_cast<const char *>(
500 sqlcipher3_column_text(m_stmt, column));
502 LogPedantic("Value: " << (value ? value : "NULL"));
505 return std::string();
508 return std::string(value);
511 RawBuffer SqlConnection::DataCommand::GetColumnBlob(
512 SqlConnection::ColumnIndex column)
514 LogPedantic("SQL data command get column blog: [" << column << "]");
515 CheckColumnIndex(column);
517 const unsigned char *value = reinterpret_cast<const unsigned char*>(
518 sqlcipher3_column_blob(m_stmt, column));
524 int length = sqlcipher3_column_bytes(m_stmt, column);
525 LogPedantic("Got blob of length: " << length);
527 return RawBuffer(value, value + length);
530 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
531 SqlConnection::ColumnIndex column)
533 LogPedantic("SQL data command get column optional integer: ["
535 CheckColumnIndex(column);
536 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
537 return boost::optional<int>();
539 int value = sqlcipher3_column_int(m_stmt, column);
540 LogPedantic(" Value: " << value);
541 return boost::optional<int>(value);
544 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
545 SqlConnection::ColumnIndex column)
547 LogPedantic("SQL data command get column optional int8: ["
549 CheckColumnIndex(column);
550 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
551 return boost::optional<int8_t>();
553 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
554 LogPedantic(" Value: " << value);
555 return boost::optional<int8_t>(value);
558 boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
559 SqlConnection::ColumnIndex column)
561 LogPedantic("SQL data command get column optional int16: ["
563 CheckColumnIndex(column);
564 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
565 return boost::optional<int16_t>();
567 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
568 LogPedantic(" Value: " << value);
569 return boost::optional<int16_t>(value);
572 boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
573 SqlConnection::ColumnIndex column)
575 LogPedantic("SQL data command get column optional int32: ["
577 CheckColumnIndex(column);
578 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
579 return boost::optional<int32_t>();
581 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
582 LogPedantic(" Value: " << value);
583 return boost::optional<int32_t>(value);
586 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
587 SqlConnection::ColumnIndex column)
589 LogPedantic("SQL data command get column optional int64: ["
591 CheckColumnIndex(column);
592 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
593 return boost::optional<int64_t>();
595 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
596 LogPedantic(" Value: " << value);
597 return boost::optional<int64_t>(value);
600 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
601 SqlConnection::ColumnIndex column)
603 LogPedantic("SQL data command get column optional float: ["
605 CheckColumnIndex(column);
606 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
607 return boost::optional<float>();
609 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
610 LogPedantic(" Value: " << value);
611 return boost::optional<float>(value);
614 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
615 SqlConnection::ColumnIndex column)
617 LogPedantic("SQL data command get column optional double: ["
619 CheckColumnIndex(column);
620 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
621 return boost::optional<double>();
623 double value = sqlcipher3_column_double(m_stmt, column);
624 LogPedantic(" Value: " << value);
625 return boost::optional<double>(value);
628 boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
629 SqlConnection::ColumnIndex column)
631 LogPedantic("SQL data command get column blog: [" << column << "]");
632 CheckColumnIndex(column);
634 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
635 return boost::optional<RawBuffer>();
637 const unsigned char *value = reinterpret_cast<const unsigned char*>(
638 sqlcipher3_column_blob(m_stmt, column));
640 int length = sqlcipher3_column_bytes(m_stmt, column);
641 LogPedantic("Got blob of length: " << length);
643 RawBuffer temp(value, value + length);
644 return boost::optional<RawBuffer>(temp);
647 void SqlConnection::Connect(const std::string &address,
650 if (m_connection != NULL) {
651 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)
684 snprintf(result, sizeof(result), "%02X", static_cast<unsigned int>(e));
685 output.push_back(static_cast<unsigned char>(result[0]));
686 output.push_back(static_cast<unsigned char>(result[1]));
691 RawBuffer createHexPass(const RawBuffer &rawPass){
692 // We are required to pass 64byte long hex password made out of 32byte raw
695 std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
696 std::back_inserter(output));
698 RawBuffer password = rawToHexString(rawPass);
700 std::copy(password.begin(), password.end(),
701 std::back_inserter(output));
703 std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
704 std::back_inserter(output));
709 void SqlConnection::SetKey(const RawBuffer &rawPass){
710 if (m_connection == NULL) {
711 LogPedantic("Cannot set key. No connection to DB!");
714 if (rawPass.size() != SQLCIPHER_RAW_DATA_SIZE)
715 ThrowMsg(Exception::InvalidArguments,
716 "Binary data for raw password should be 32 bytes long.");
717 RawBuffer pass = createHexPass(rawPass);
718 int result = sqlcipher3_key(m_connection, pass.data(), pass.size());
719 if (result == SQLCIPHER_OK) {
720 LogPedantic("Set key on DB");
722 //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
724 LogError("Failed to set key on DB");
725 ThrowMsg(Exception::InvalidArguments, result);
731 void SqlConnection::ResetKey(const RawBuffer &rawPassOld,
732 const RawBuffer &rawPassNew) {
733 if (m_connection == NULL) {
734 LogPedantic("Cannot reset key. No connection to DB!");
737 AssertMsg(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
738 rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE,
739 "Binary data for raw password should be 32 bytes long."
741 // sqlcipher3_rekey requires for key to be already set
745 RawBuffer pass = createHexPass(rawPassNew);
746 int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
747 if (result == SQLCIPHER_OK) {
748 LogPedantic("Reset key on DB");
750 //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
752 LogError("Failed to reset key on DB");
753 ThrowMsg(Exception::InvalidArguments, result);
757 void SqlConnection::Disconnect()
759 if (m_connection == NULL) {
760 LogPedantic("Already disconnected.");
764 LogPedantic("Disconnecting from DB...");
766 // All stored data commands must be deleted before disconnect
767 AssertMsg(m_dataCommandsCount == 0,
768 "All stored procedures must be deleted"
769 " before disconnecting SqlConnection");
773 result = sqlcipher3_close(m_connection);
775 if (result != SQLCIPHER_OK) {
776 const char *error = sqlcipher3_errmsg(m_connection);
777 LogError("SQL close failed");
778 LogError(" Error: " << error);
779 Throw(Exception::InternalError);
784 LogPedantic("Disconnected from DB");
787 bool SqlConnection::CheckTableExist(const char *tableName)
789 if (m_connection == NULL) {
790 LogPedantic("Cannot execute command. Not connected to DB!");
794 DataCommandUniquePtr command =
795 PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
797 command->BindString(1, tableName);
799 if (!command->Step()) {
800 LogPedantic("No matching records in table");
804 return command->GetColumnString(0) == tableName;
807 SqlConnection::SqlConnection(const std::string &address,
809 SynchronizationObject *synchronizationObject) :
811 m_dataCommandsCount(0),
812 m_synchronizationObject(synchronizationObject),
815 LogPedantic("Opening database connection to: " << address);
818 SqlConnection::Connect(address, option);
820 if (!m_synchronizationObject) {
821 LogPedantic("No synchronization object defined");
825 SqlConnection::~SqlConnection()
827 LogPedantic("Closing database connection");
829 // Disconnect from DB
832 SqlConnection::Disconnect();
834 Catch(Exception::Base)
836 LogError("Failed to disconnect from database");
840 int SqlConnection::Output::Callback(void* param, int columns, char** values, char** names)
843 static_cast<Output*>(param)->SetResults(columns, values, names);
847 void SqlConnection::Output::SetResults(int columns, char** values, char** names)
849 if (m_names.empty()) {
850 for (int i=0;i<columns;i++)
851 m_names.push_back(names[i] ? names[i] : "NULL");
854 for (int i=0;i<columns;i++)
855 row.push_back(values[i] ? values[i] : "NULL");
856 m_values.push_back(std::move(row));
859 void SqlConnection::ExecCommandHelper(Output* out, const char* format, va_list args)
861 if (m_connection == NULL) {
862 LogError("Cannot execute command. Not connected to DB!");
866 if (format == NULL) {
867 LogError("Null query!");
868 ThrowMsg(Exception::SyntaxError, "Null statement");
873 if (vasprintf(&query, format, args) == -1) {
874 LogError("Failed to allocate statement string");
878 CharUniquePtr queryPtr(query);
880 LogPedantic("Executing SQL command: " << queryPtr.get());
882 // Notify all after potentially synchronized database connection access
883 ScopedNotifyAll notifyAll(m_synchronizationObject.get());
885 for (int i = 0; i < MAX_RETRY; i++) {
887 int ret = sqlcipher3_exec(m_connection,
889 out ? &Output::Callback : NULL,
893 std::string errorMsg;
895 // Take allocated error buffer
896 if (errorBuffer != NULL) {
897 errorMsg = errorBuffer;
898 sqlcipher3_free(errorBuffer);
901 if (ret == SQLCIPHER_OK) {
905 if (ret == SQLCIPHER_BUSY) {
906 LogPedantic("Collision occurred while executing SQL command");
908 // Synchronize if synchronization object is available
909 if (m_synchronizationObject) {
910 LogPedantic("Performing synchronization");
911 m_synchronizationObject->Synchronize();
915 // No synchronization object defined. Fail.
919 LogError("Failed to execute SQL command. Error: " << errorMsg);
920 ThrowMsg(Exception::SyntaxError, errorMsg);
923 LogError("sqlite in the state of possible infinite loop");
924 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
927 void SqlConnection::ExecCommand(Output* out, const char *format, ...)
929 scoped_va_start(svl, format);
931 ExecCommandHelper(out, format, svl.args);
934 void SqlConnection::ExecCommand(const char *format, ...)
936 scoped_va_start(svl, format);
938 ExecCommandHelper(NULL, format, svl.args);
941 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
945 if (m_connection == NULL) {
946 LogError("Cannot execute data command. Not connected to DB!");
947 return DataCommandUniquePtr();
953 va_start(args, format);
955 if (vasprintf(&rawBuffer, format, args) == -1) {
961 CharUniquePtr buffer(rawBuffer);
964 LogError("Failed to allocate statement string");
965 return DataCommandUniquePtr();
968 LogPedantic("Executing SQL data command: " << buffer.get());
970 return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
973 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
975 return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
978 void SqlConnection::TurnOnForeignKeys()
980 ExecCommand("PRAGMA foreign_keys = ON;");
983 void SqlConnection::BeginTransaction()
985 ExecCommand("BEGIN;");
988 void SqlConnection::RollbackTransaction()
990 ExecCommand("ROLLBACK;");
993 void SqlConnection::CommitTransaction()
995 ExecCommand("COMMIT;");
998 SqlConnection::SynchronizationObject *
999 SqlConnection::AllocDefaultSynchronizationObject()
1001 return new NaiveSynchronizationObject();
1006 #pragma GCC diagnostic pop