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
54 SqlConnection::SynchronizationObject *m_synchronizationObject;
57 NONCOPYABLE(ScopedNotifyAll)
59 explicit ScopedNotifyAll(
60 SqlConnection::SynchronizationObject *synchronizationObject) :
61 m_synchronizationObject(synchronizationObject)
67 if (!m_synchronizationObject)
70 LogPedantic("Notifying after successful synchronize");
71 m_synchronizationObject->NotifyAll();
74 } // namespace anonymous
76 SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
78 m_masterConnection(connection),
81 Assert(connection != NULL);
83 // Notify all after potentially synchronized database connection access
84 ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
86 for (int i = 0; i < MAX_RETRY; i++) {
87 int ret = sqlcipher3_prepare_v2(connection->m_connection,
88 buffer, strlen(buffer),
91 if (ret == SQLCIPHER_OK) {
92 LogPedantic("Prepared data command: " << buffer);
94 // Increment stored data command count
95 ++m_masterConnection->m_dataCommandsCount;
97 } else if (ret == SQLCIPHER_BUSY) {
98 LogPedantic("Collision occurred while preparing SQL command");
100 // Synchronize if synchronization object is available
101 if (connection->m_synchronizationObject) {
102 LogPedantic("Performing synchronization");
103 connection->m_synchronizationObject->Synchronize();
107 // No synchronization object defined. Fail.
111 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
113 LogError("SQL prepare data command failed");
114 LogError(" Statement: " << buffer);
115 LogError(" Error: " << error);
117 ThrowMsg(Exception::SyntaxError, error);
120 LogError("sqlite in the state of possible infinite loop");
121 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
124 SqlConnection::DataCommand::~DataCommand()
126 LogPedantic("SQL data command finalizing");
128 if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK)
129 LogError("Failed to finalize data command");
131 // Decrement stored data command count
132 --m_masterConnection->m_dataCommandsCount;
135 void SqlConnection::DataCommand::CheckBindResult(int result)
137 if (result != SQLCIPHER_OK) {
138 const char *error = sqlcipher3_errmsg(
139 m_masterConnection->m_connection);
141 LogError("Failed to bind SQL statement parameter");
142 LogError(" Error: " << error);
144 ThrowMsg(Exception::SyntaxError, error);
148 void SqlConnection::DataCommand::BindNull(
149 SqlConnection::ArgumentIndex position)
151 CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
152 LogPedantic("SQL data command bind null: ["
156 void SqlConnection::DataCommand::BindInteger(
157 SqlConnection::ArgumentIndex position,
160 CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
161 LogPedantic("SQL data command bind integer: ["
162 << position << "] -> " << value);
165 void SqlConnection::DataCommand::BindInt8(
166 SqlConnection::ArgumentIndex position,
169 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
170 static_cast<int>(value)));
171 LogPedantic("SQL data command bind int8: ["
172 << position << "] -> " << value);
175 void SqlConnection::DataCommand::BindInt16(
176 SqlConnection::ArgumentIndex position,
179 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
180 static_cast<int>(value)));
181 LogPedantic("SQL data command bind int16: ["
182 << position << "] -> " << value);
185 void SqlConnection::DataCommand::BindInt32(
186 SqlConnection::ArgumentIndex position,
189 CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
190 static_cast<int>(value)));
191 LogPedantic("SQL data command bind int32: ["
192 << position << "] -> " << value);
195 void SqlConnection::DataCommand::BindInt64(
196 SqlConnection::ArgumentIndex position,
199 CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
200 static_cast<sqlcipher3_int64>(value)));
201 LogPedantic("SQL data command bind int64: ["
202 << position << "] -> " << value);
205 void SqlConnection::DataCommand::BindFloat(
206 SqlConnection::ArgumentIndex position,
209 CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
210 static_cast<double>(value)));
211 LogPedantic("SQL data command bind float: ["
212 << position << "] -> " << value);
215 void SqlConnection::DataCommand::BindDouble(
216 SqlConnection::ArgumentIndex position,
219 CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
220 LogPedantic("SQL data command bind double: ["
221 << position << "] -> " << value);
224 void SqlConnection::DataCommand::BindString(
225 SqlConnection::ArgumentIndex position,
233 // Assume that text may disappear
234 CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
235 value, strlen(value),
236 SQLCIPHER_TRANSIENT));
238 LogPedantic("SQL data command bind string: ["
239 << position << "] -> " << value);
242 void SqlConnection::DataCommand::BindBlob(
243 SqlConnection::ArgumentIndex position,
244 const RawBuffer &raw)
246 if (raw.size() == 0) {
251 // Assume that blob may dissappear
252 CheckBindResult(sqlcipher3_bind_blob(m_stmt, position,
253 raw.data(), raw.size(),
254 SQLCIPHER_TRANSIENT));
255 LogPedantic("SQL data command bind blob of size: ["
256 << position << "] -> " << raw.size());
259 void SqlConnection::DataCommand::BindInteger(
260 SqlConnection::ArgumentIndex position,
261 const boost::optional<int> &value)
266 BindInteger(position, *value);
269 void SqlConnection::DataCommand::BindInt8(
270 SqlConnection::ArgumentIndex position,
271 const boost::optional<int8_t> &value)
276 BindInt8(position, *value);
279 void SqlConnection::DataCommand::BindInt16(
280 SqlConnection::ArgumentIndex position,
281 const boost::optional<int16_t> &value)
286 BindInt16(position, *value);
289 void SqlConnection::DataCommand::BindInt32(
290 SqlConnection::ArgumentIndex position,
291 const boost::optional<int32_t> &value)
296 BindInt32(position, *value);
299 void SqlConnection::DataCommand::BindInt64(
300 SqlConnection::ArgumentIndex position,
301 const boost::optional<int64_t> &value)
306 BindInt64(position, *value);
309 void SqlConnection::DataCommand::BindFloat(
310 SqlConnection::ArgumentIndex position,
311 const boost::optional<float> &value)
316 BindFloat(position, *value);
319 void SqlConnection::DataCommand::BindDouble(
320 SqlConnection::ArgumentIndex position,
321 const boost::optional<double> &value)
326 BindDouble(position, *value);
329 void SqlConnection::DataCommand::BindBlob(
330 SqlConnection::ArgumentIndex position,
331 const boost::optional<RawBuffer> &value)
334 BindBlob(position, *value);
339 bool SqlConnection::DataCommand::Step()
341 // Notify all after potentially synchronized database connection access
342 ScopedNotifyAll notifyAll(
343 m_masterConnection->m_synchronizationObject.get());
345 for (int i = 0; i < MAX_RETRY; i++) {
346 int ret = sqlcipher3_step(m_stmt);
348 if (ret == SQLCIPHER_ROW) {
349 LogPedantic("SQL data command step ROW");
351 } else if (ret == SQLCIPHER_DONE) {
352 LogPedantic("SQL data command step DONE");
354 } else if (ret == SQLCIPHER_BUSY) {
355 LogPedantic("Collision occurred while executing SQL command");
357 // Synchronize if synchronization object is available
358 if (m_masterConnection->m_synchronizationObject) {
359 LogPedantic("Performing synchronization");
362 m_synchronizationObject->Synchronize();
366 // No synchronization object defined. Fail.
370 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
372 LogError("SQL step data command failed");
373 LogError(" Error: " << error);
375 ThrowMsg(Exception::InternalError, error);
378 LogError("sqlite in the state of possible infinite loop");
379 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
382 void SqlConnection::DataCommand::Reset()
386 * http://www.sqllite.org/c3ref/stmt.html
388 * if last sqlcipher3_step command on this stmt returned an error,
389 * then sqlcipher3_reset will return that error, althought it is not an error.
390 * So sqlcipher3_reset allways succedes.
392 sqlcipher3_reset(m_stmt);
394 LogPedantic("SQL data command reset");
397 void SqlConnection::DataCommand::CheckColumnIndex(
398 SqlConnection::ColumnIndex column)
400 if (column < 0 || column >= sqlcipher3_column_count(m_stmt))
401 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;
412 int SqlConnection::DataCommand::GetColumnInteger(
413 SqlConnection::ColumnIndex column)
415 LogPedantic("SQL data command get column integer: [" << column << "]");
416 CheckColumnIndex(column);
417 int value = sqlcipher3_column_int(m_stmt, column);
418 LogPedantic(" Value: " << value);
422 int8_t SqlConnection::DataCommand::GetColumnInt8(
423 SqlConnection::ColumnIndex column)
425 LogPedantic("SQL data command get column int8: [" << column << "]");
426 CheckColumnIndex(column);
427 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
428 LogPedantic(" Value: " << value);
432 int16_t SqlConnection::DataCommand::GetColumnInt16(
433 SqlConnection::ColumnIndex column)
435 LogPedantic("SQL data command get column int16: [" << column << "]");
436 CheckColumnIndex(column);
437 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
438 LogPedantic(" Value: " << value);
442 int32_t SqlConnection::DataCommand::GetColumnInt32(
443 SqlConnection::ColumnIndex column)
445 LogPedantic("SQL data command get column int32: [" << column << "]");
446 CheckColumnIndex(column);
447 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
448 LogPedantic(" Value: " << value);
452 int64_t SqlConnection::DataCommand::GetColumnInt64(
453 SqlConnection::ColumnIndex column)
455 LogPedantic("SQL data command get column int64: [" << column << "]");
456 CheckColumnIndex(column);
457 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
458 LogPedantic(" Value: " << value);
462 float SqlConnection::DataCommand::GetColumnFloat(
463 SqlConnection::ColumnIndex column)
465 LogPedantic("SQL data command get column float: [" << column << "]");
466 CheckColumnIndex(column);
467 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
468 LogPedantic(" Value: " << value);
472 double SqlConnection::DataCommand::GetColumnDouble(
473 SqlConnection::ColumnIndex column)
475 LogPedantic("SQL data command get column double: [" << column << "]");
476 CheckColumnIndex(column);
477 double value = sqlcipher3_column_double(m_stmt, column);
478 LogPedantic(" Value: " << value);
482 std::string SqlConnection::DataCommand::GetColumnString(
483 SqlConnection::ColumnIndex column)
485 LogPedantic("SQL data command get column string: [" << column << "]");
486 CheckColumnIndex(column);
488 const char *value = reinterpret_cast<const char *>(
489 sqlcipher3_column_text(m_stmt, column));
491 LogPedantic("Value: " << (value ? value : "NULL"));
494 return std::string();
496 return std::string(value);
499 RawBuffer SqlConnection::DataCommand::GetColumnBlob(
500 SqlConnection::ColumnIndex column)
502 LogPedantic("SQL data command get column blog: [" << column << "]");
503 CheckColumnIndex(column);
505 const unsigned char *value = reinterpret_cast<const unsigned char*>(
506 sqlcipher3_column_blob(m_stmt, column));
511 int length = sqlcipher3_column_bytes(m_stmt, column);
512 LogPedantic("Got blob of length: " << length);
514 return RawBuffer(value, value + length);
517 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
518 SqlConnection::ColumnIndex column)
520 LogPedantic("SQL data command get column optional integer: ["
522 CheckColumnIndex(column);
523 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
524 return boost::optional<int>();
526 int value = sqlcipher3_column_int(m_stmt, column);
527 LogPedantic(" Value: " << value);
528 return boost::optional<int>(value);
531 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
532 SqlConnection::ColumnIndex column)
534 LogPedantic("SQL data command get column optional int8: ["
536 CheckColumnIndex(column);
537 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
538 return boost::optional<int8_t>();
540 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
541 LogPedantic(" Value: " << value);
542 return boost::optional<int8_t>(value);
545 boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
546 SqlConnection::ColumnIndex column)
548 LogPedantic("SQL data command get column optional int16: ["
550 CheckColumnIndex(column);
551 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
552 return boost::optional<int16_t>();
554 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
555 LogPedantic(" Value: " << value);
556 return boost::optional<int16_t>(value);
559 boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
560 SqlConnection::ColumnIndex column)
562 LogPedantic("SQL data command get column optional int32: ["
564 CheckColumnIndex(column);
565 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
566 return boost::optional<int32_t>();
568 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
569 LogPedantic(" Value: " << value);
570 return boost::optional<int32_t>(value);
573 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
574 SqlConnection::ColumnIndex column)
576 LogPedantic("SQL data command get column optional int64: ["
578 CheckColumnIndex(column);
579 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
580 return boost::optional<int64_t>();
582 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
583 LogPedantic(" Value: " << value);
584 return boost::optional<int64_t>(value);
587 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
588 SqlConnection::ColumnIndex column)
590 LogPedantic("SQL data command get column optional float: ["
592 CheckColumnIndex(column);
593 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
594 return boost::optional<float>();
596 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
597 LogPedantic(" Value: " << value);
598 return boost::optional<float>(value);
601 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
602 SqlConnection::ColumnIndex column)
604 LogPedantic("SQL data command get column optional double: ["
606 CheckColumnIndex(column);
607 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
608 return boost::optional<double>();
610 double value = sqlcipher3_column_double(m_stmt, column);
611 LogPedantic(" Value: " << value);
612 return boost::optional<double>(value);
615 boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
616 SqlConnection::ColumnIndex column)
618 LogPedantic("SQL data command get column blog: [" << column << "]");
619 CheckColumnIndex(column);
621 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
622 return boost::optional<RawBuffer>();
624 const unsigned char *value = reinterpret_cast<const unsigned char*>(
625 sqlcipher3_column_blob(m_stmt, column));
627 int length = sqlcipher3_column_bytes(m_stmt, column);
628 LogPedantic("Got blob of length: " << length);
630 RawBuffer temp(value, value + length);
631 return boost::optional<RawBuffer>(temp);
634 void SqlConnection::Connect(const std::string &address,
637 if (m_connection != NULL) {
638 LogPedantic("Already connected.");
641 LogPedantic("Connecting to DB: " << address << "...");
643 // Connect to database
645 result = sqlcipher3_open_v2(
651 if (result == SQLCIPHER_OK) {
652 LogPedantic("Connected to DB");
654 LogError("Failed to connect to DB!");
655 ThrowMsg(Exception::ConnectionBroken, address);
658 // Enable foreign keys
662 const std::string SQLCIPHER_RAW_PREFIX = "x'";
663 const std::string SQLCIPHER_RAW_SUFIX = "'";
664 const std::size_t SQLCIPHER_RAW_DATA_SIZE = 32;
666 RawBuffer rawToHexString(const RawBuffer &raw)
671 snprintf(result, sizeof(result), "%02X", static_cast<unsigned int>(e));
672 output.push_back(static_cast<unsigned char>(result[0]));
673 output.push_back(static_cast<unsigned char>(result[1]));
678 RawBuffer createHexPass(const RawBuffer &rawPass)
680 // We are required to pass 64byte long hex password made out of 32byte raw
683 std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
684 std::back_inserter(output));
686 RawBuffer password = rawToHexString(rawPass);
688 std::copy(password.begin(), password.end(),
689 std::back_inserter(output));
691 std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
692 std::back_inserter(output));
697 void SqlConnection::SetKey(const RawBuffer &rawPass){
698 if (m_connection == NULL) {
699 LogPedantic("Cannot set key. No connection to DB!");
702 if (rawPass.size() != SQLCIPHER_RAW_DATA_SIZE)
703 ThrowMsg(Exception::InvalidArguments,
704 "Binary data for raw password should be 32 bytes long.");
705 RawBuffer pass = createHexPass(rawPass);
706 int result = sqlcipher3_key(m_connection, pass.data(), pass.size());
707 if (result == SQLCIPHER_OK) {
708 LogPedantic("Set key on DB");
710 //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
712 LogError("Failed to set key on DB");
713 ThrowMsg(Exception::InvalidArguments, result);
719 void SqlConnection::ResetKey(const RawBuffer &rawPassOld,
720 const RawBuffer &rawPassNew) {
721 if (m_connection == NULL) {
722 LogPedantic("Cannot reset key. No connection to DB!");
725 AssertMsg(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
726 rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE,
727 "Binary data for raw password should be 32 bytes long.");
728 // sqlcipher3_rekey requires for key to be already set
732 RawBuffer pass = createHexPass(rawPassNew);
733 int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
734 if (result == SQLCIPHER_OK) {
735 LogPedantic("Reset key on DB");
737 //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
739 LogError("Failed to reset key on DB");
740 ThrowMsg(Exception::InvalidArguments, result);
744 void SqlConnection::Disconnect()
746 if (m_connection == NULL) {
747 LogPedantic("Already disconnected.");
751 LogPedantic("Disconnecting from DB...");
753 // All stored data commands must be deleted before disconnect
754 AssertMsg(m_dataCommandsCount == 0,
755 "All stored procedures must be deleted"
756 " before disconnecting SqlConnection");
760 result = sqlcipher3_close(m_connection);
762 if (result != SQLCIPHER_OK) {
763 const char *error = sqlcipher3_errmsg(m_connection);
764 LogError("SQL close failed");
765 LogError(" Error: " << error);
766 Throw(Exception::InternalError);
771 LogPedantic("Disconnected from DB");
774 bool SqlConnection::CheckTableExist(const char *tableName)
776 if (m_connection == NULL) {
777 LogPedantic("Cannot execute command. Not connected to DB!");
781 DataCommandUniquePtr command =
782 PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
784 command->BindString(1, tableName);
786 if (!command->Step()) {
787 LogPedantic("No matching records in table");
791 return command->GetColumnString(0) == tableName;
794 SqlConnection::SqlConnection(const std::string &address,
796 SynchronizationObject *synchronizationObject) :
798 m_dataCommandsCount(0),
799 m_synchronizationObject(synchronizationObject),
802 LogPedantic("Opening database connection to: " << address);
805 SqlConnection::Connect(address, option);
807 if (!m_synchronizationObject)
808 LogPedantic("No synchronization object defined");
811 SqlConnection::~SqlConnection()
813 LogPedantic("Closing database connection");
815 // Disconnect from DB
818 SqlConnection::Disconnect();
820 Catch(Exception::Base)
822 LogError("Failed to disconnect from database");
826 int SqlConnection::Output::Callback(void* param, int columns, char** values, char** names)
829 static_cast<Output*>(param)->SetResults(columns, values, names);
833 void SqlConnection::Output::SetResults(int columns, char** values, char** names)
835 if (m_names.empty()) {
836 for (int i=0; i < columns; i++)
837 m_names.push_back(names[i] ? names[i] : "NULL");
840 for (int i=0; i < columns; i++)
841 row.push_back(values[i] ? values[i] : "NULL");
842 m_values.push_back(std::move(row));
845 void SqlConnection::ExecCommandHelper(Output* out, const char* format, va_list args)
847 if (m_connection == NULL) {
848 LogError("Cannot execute command. Not connected to DB!");
852 if (format == NULL) {
853 LogError("Null query!");
854 ThrowMsg(Exception::SyntaxError, "Null statement");
859 if (vasprintf(&query, format, args) == -1) {
860 LogError("Failed to allocate statement string");
864 CharUniquePtr queryPtr(query);
866 LogPedantic("Executing SQL command: " << queryPtr.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++) {
873 int ret = sqlcipher3_exec(m_connection,
875 out ? &Output::Callback : NULL,
879 std::string errorMsg;
881 // Take allocated error buffer
882 if (errorBuffer != NULL) {
883 errorMsg = errorBuffer;
884 sqlcipher3_free(errorBuffer);
887 if (ret == SQLCIPHER_OK)
890 if (ret == SQLCIPHER_BUSY) {
891 LogPedantic("Collision occurred while executing SQL command");
893 // Synchronize if synchronization object is available
894 if (m_synchronizationObject) {
895 LogPedantic("Performing synchronization");
896 m_synchronizationObject->Synchronize();
900 // No synchronization object defined. Fail.
904 LogError("Failed to execute SQL command. Error: " << errorMsg);
905 ThrowMsg(Exception::SyntaxError, errorMsg);
908 LogError("sqlite in the state of possible infinite loop");
909 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
912 void SqlConnection::ExecCommand(Output* out, const char *format, ...)
914 scoped_va_start(svl, format);
916 ExecCommandHelper(out, format, svl.args);
919 void SqlConnection::ExecCommand(const char *format, ...)
921 scoped_va_start(svl, format);
923 ExecCommandHelper(NULL, format, svl.args);
926 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
930 if (m_connection == NULL) {
931 LogError("Cannot execute data command. Not connected to DB!");
932 return DataCommandUniquePtr();
938 va_start(args, format);
940 if (vasprintf(&rawBuffer, format, args) == -1)
945 CharUniquePtr buffer(rawBuffer);
948 LogError("Failed to allocate statement string");
949 return DataCommandUniquePtr();
952 LogPedantic("Executing SQL data command: " << buffer.get());
954 return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
957 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
959 return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
962 void SqlConnection::TurnOnForeignKeys()
964 ExecCommand("PRAGMA foreign_keys = ON;");
967 void SqlConnection::BeginTransaction()
969 ExecCommand("BEGIN;");
972 void SqlConnection::RollbackTransaction()
974 ExecCommand("ROLLBACK;");
977 void SqlConnection::CommitTransaction()
979 ExecCommand("COMMIT;");
982 SqlConnection::SynchronizationObject *
983 SqlConnection::AllocDefaultSynchronizationObject()
985 return new NaiveSynchronizationObject();
990 #pragma GCC diagnostic pop