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;
48 #define scoped_va_start(name, param) ScopedVaList name; va_start(name.args, param);
53 namespace { // anonymous
54 class ScopedNotifyAll {
56 SqlConnection::SynchronizationObject *m_synchronizationObject;
59 NONCOPYABLE(ScopedNotifyAll)
61 explicit ScopedNotifyAll(
62 SqlConnection::SynchronizationObject *synchronizationObject) :
63 m_synchronizationObject(synchronizationObject)
69 if (!m_synchronizationObject)
72 LogPedantic("Notifying after successful synchronize");
73 m_synchronizationObject->NotifyAll();
76 } // namespace anonymous
78 SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
80 m_masterConnection(connection),
83 Assert(connection != NULL);
85 // Notify all after potentially synchronized database connection access
86 ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
88 for (int i = 0; i < MAX_RETRY; i++) {
89 int ret = sqlcipher3_prepare_v2(connection->m_connection,
90 buffer, strlen(buffer),
93 if (ret == SQLCIPHER_OK) {
94 LogPedantic("Prepared data command: " << buffer);
96 // Increment stored data command count
97 ++m_masterConnection->m_dataCommandsCount;
99 } else if (ret == SQLCIPHER_BUSY) {
100 LogPedantic("Collision occurred while preparing SQL command");
102 // Synchronize if synchronization object is available
103 if (connection->m_synchronizationObject) {
104 LogPedantic("Performing synchronization");
105 connection->m_synchronizationObject->Synchronize();
109 // No synchronization object defined. Fail.
113 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
115 LogError("SQL prepare data command failed");
116 LogError(" Statement: " << buffer);
117 LogError(" Error: " << error);
119 ThrowMsg(Exception::SyntaxError, error);
122 LogError("sqlite in the state of possible infinite loop");
123 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
126 SqlConnection::DataCommand::~DataCommand()
128 LogPedantic("SQL data command finalizing");
130 if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK)
131 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);
271 void SqlConnection::DataCommand::BindInt8(
272 SqlConnection::ArgumentIndex position,
273 const boost::optional<int8_t> &value)
278 BindInt8(position, *value);
281 void SqlConnection::DataCommand::BindInt16(
282 SqlConnection::ArgumentIndex position,
283 const boost::optional<int16_t> &value)
288 BindInt16(position, *value);
291 void SqlConnection::DataCommand::BindInt32(
292 SqlConnection::ArgumentIndex position,
293 const boost::optional<int32_t> &value)
298 BindInt32(position, *value);
301 void SqlConnection::DataCommand::BindInt64(
302 SqlConnection::ArgumentIndex position,
303 const boost::optional<int64_t> &value)
308 BindInt64(position, *value);
311 void SqlConnection::DataCommand::BindFloat(
312 SqlConnection::ArgumentIndex position,
313 const boost::optional<float> &value)
318 BindFloat(position, *value);
321 void SqlConnection::DataCommand::BindDouble(
322 SqlConnection::ArgumentIndex position,
323 const boost::optional<double> &value)
328 BindDouble(position, *value);
331 void SqlConnection::DataCommand::BindBlob(
332 SqlConnection::ArgumentIndex position,
333 const boost::optional<RawBuffer> &value)
336 BindBlob(position, *value);
341 bool SqlConnection::DataCommand::Step()
343 // Notify all after potentially synchronized database connection access
344 ScopedNotifyAll notifyAll(
345 m_masterConnection->m_synchronizationObject.get());
347 for (int i = 0; i < MAX_RETRY; i++) {
348 int ret = sqlcipher3_step(m_stmt);
350 if (ret == SQLCIPHER_ROW) {
351 LogPedantic("SQL data command step ROW");
353 } else if (ret == SQLCIPHER_DONE) {
354 LogPedantic("SQL data command step DONE");
356 } else if (ret == SQLCIPHER_BUSY) {
357 LogPedantic("Collision occurred while executing SQL command");
359 // Synchronize if synchronization object is available
360 if (m_masterConnection->m_synchronizationObject) {
361 LogPedantic("Performing synchronization");
364 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");
407 bool SqlConnection::DataCommand::IsColumnNull(
408 SqlConnection::ColumnIndex column)
410 LogPedantic("SQL data command get column type: [" << column << "]");
411 CheckColumnIndex(column);
412 return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
415 int SqlConnection::DataCommand::GetColumnInteger(
416 SqlConnection::ColumnIndex column)
418 LogPedantic("SQL data command get column integer: [" << column << "]");
419 CheckColumnIndex(column);
420 int value = sqlcipher3_column_int(m_stmt, column);
421 LogPedantic(" Value: " << value);
425 int8_t SqlConnection::DataCommand::GetColumnInt8(
426 SqlConnection::ColumnIndex column)
428 LogPedantic("SQL data command get column int8: [" << column << "]");
429 CheckColumnIndex(column);
430 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
431 LogPedantic(" Value: " << value);
435 int16_t SqlConnection::DataCommand::GetColumnInt16(
436 SqlConnection::ColumnIndex column)
438 LogPedantic("SQL data command get column int16: [" << column << "]");
439 CheckColumnIndex(column);
440 int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
441 LogPedantic(" Value: " << value);
445 int32_t SqlConnection::DataCommand::GetColumnInt32(
446 SqlConnection::ColumnIndex column)
448 LogPedantic("SQL data command get column int32: [" << column << "]");
449 CheckColumnIndex(column);
450 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
451 LogPedantic(" Value: " << value);
455 int64_t SqlConnection::DataCommand::GetColumnInt64(
456 SqlConnection::ColumnIndex column)
458 LogPedantic("SQL data command get column int64: [" << column << "]");
459 CheckColumnIndex(column);
460 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
461 LogPedantic(" Value: " << value);
465 float SqlConnection::DataCommand::GetColumnFloat(
466 SqlConnection::ColumnIndex column)
468 LogPedantic("SQL data command get column float: [" << column << "]");
469 CheckColumnIndex(column);
470 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
471 LogPedantic(" Value: " << value);
475 double SqlConnection::DataCommand::GetColumnDouble(
476 SqlConnection::ColumnIndex column)
478 LogPedantic("SQL data command get column double: [" << column << "]");
479 CheckColumnIndex(column);
480 double value = sqlcipher3_column_double(m_stmt, column);
481 LogPedantic(" Value: " << value);
485 std::string SqlConnection::DataCommand::GetColumnString(
486 SqlConnection::ColumnIndex column)
488 LogPedantic("SQL data command get column string: [" << column << "]");
489 CheckColumnIndex(column);
491 const char *value = reinterpret_cast<const char *>(
492 sqlcipher3_column_text(m_stmt, column));
494 LogPedantic("Value: " << (value ? value : "NULL"));
497 return std::string();
499 return std::string(value);
502 RawBuffer SqlConnection::DataCommand::GetColumnBlob(
503 SqlConnection::ColumnIndex column)
505 LogPedantic("SQL data command get column blog: [" << column << "]");
506 CheckColumnIndex(column);
508 const unsigned char *value = reinterpret_cast<const unsigned char *>(
509 sqlcipher3_column_blob(m_stmt, column));
514 int length = sqlcipher3_column_bytes(m_stmt, column);
515 LogPedantic("Got blob of length: " << length);
517 return RawBuffer(value, value + length);
520 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
521 SqlConnection::ColumnIndex column)
523 LogPedantic("SQL data command get column optional integer: ["
525 CheckColumnIndex(column);
527 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
528 return boost::optional<int>();
530 int value = sqlcipher3_column_int(m_stmt, column);
531 LogPedantic(" Value: " << value);
532 return boost::optional<int>(value);
535 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
536 SqlConnection::ColumnIndex column)
538 LogPedantic("SQL data command get column optional int8: ["
540 CheckColumnIndex(column);
542 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
543 return boost::optional<int8_t>();
545 int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
546 LogPedantic(" Value: " << value);
547 return boost::optional<int8_t>(value);
550 boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
551 SqlConnection::ColumnIndex column)
553 LogPedantic("SQL data command get column optional int16: ["
555 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);
572 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
573 return boost::optional<int32_t>();
575 int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
576 LogPedantic(" Value: " << value);
577 return boost::optional<int32_t>(value);
580 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
581 SqlConnection::ColumnIndex column)
583 LogPedantic("SQL data command get column optional int64: ["
585 CheckColumnIndex(column);
587 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
588 return boost::optional<int64_t>();
590 int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
591 LogPedantic(" Value: " << value);
592 return boost::optional<int64_t>(value);
595 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
596 SqlConnection::ColumnIndex column)
598 LogPedantic("SQL data command get column optional float: ["
600 CheckColumnIndex(column);
602 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
603 return boost::optional<float>();
605 float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
606 LogPedantic(" Value: " << value);
607 return boost::optional<float>(value);
610 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
611 SqlConnection::ColumnIndex column)
613 LogPedantic("SQL data command get column optional double: ["
615 CheckColumnIndex(column);
617 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
618 return boost::optional<double>();
620 double value = sqlcipher3_column_double(m_stmt, column);
621 LogPedantic(" Value: " << value);
622 return boost::optional<double>(value);
625 boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
626 SqlConnection::ColumnIndex column)
628 LogPedantic("SQL data command get column blog: [" << column << "]");
629 CheckColumnIndex(column);
631 if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
632 return boost::optional<RawBuffer>();
634 const unsigned char *value = reinterpret_cast<const unsigned char *>(
635 sqlcipher3_column_blob(m_stmt, column));
637 int length = sqlcipher3_column_bytes(m_stmt, column);
638 LogPedantic("Got blob of length: " << length);
640 RawBuffer temp(value, value + length);
641 return boost::optional<RawBuffer>(temp);
644 void SqlConnection::Connect(const std::string &address,
647 if (m_connection != NULL) {
648 LogPedantic("Already connected.");
652 LogPedantic("Connecting to DB: " << address << "...");
654 // Connect to database
656 result = sqlcipher3_open_v2(
662 if (result == SQLCIPHER_OK) {
663 LogPedantic("Connected to DB");
665 LogError("Failed to connect to DB!");
666 ThrowMsg(Exception::ConnectionBroken, address);
669 // Enable foreign keys
673 const std::string SQLCIPHER_RAW_PREFIX = "x'";
674 const std::string SQLCIPHER_RAW_SUFIX = "'";
675 const std::size_t SQLCIPHER_RAW_DATA_SIZE = 32;
677 RawBuffer rawToHexString(const RawBuffer &raw)
681 for (auto &e : raw) {
683 snprintf(result, sizeof(result), "%02X", (e & 0xff));
684 output.push_back(static_cast<unsigned char>(result[0]));
685 output.push_back(static_cast<unsigned char>(result[1]));
691 RawBuffer createHexPass(const RawBuffer &rawPass)
693 // We are required to pass 64byte long hex password made out of 32byte raw
696 std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
697 std::back_inserter(output));
699 RawBuffer password = rawToHexString(rawPass);
701 std::copy(password.begin(), password.end(),
702 std::back_inserter(output));
704 std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
705 std::back_inserter(output));
710 void SqlConnection::SetKey(const RawBuffer &rawPass)
712 if (m_connection == NULL) {
713 LogPedantic("Cannot set key. No connection to DB!");
717 if (rawPass.size() != SQLCIPHER_RAW_DATA_SIZE)
718 ThrowMsg(Exception::InvalidArguments,
719 "Binary data for raw password should be 32 bytes long.");
721 RawBuffer pass = createHexPass(rawPass);
722 int result = sqlcipher3_key(m_connection, pass.data(), pass.size());
724 if (result == SQLCIPHER_OK) {
725 LogPedantic("Set key on DB");
727 //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
729 LogError("Failed to set key on DB");
730 ThrowMsg(Exception::InvalidArguments, result);
736 void SqlConnection::ResetKey(const RawBuffer &rawPassOld,
737 const RawBuffer &rawPassNew)
739 if (m_connection == NULL) {
740 LogPedantic("Cannot reset key. No connection to DB!");
744 AssertMsg(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
745 rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE,
746 "Binary data for raw password should be 32 bytes long.");
748 // sqlcipher3_rekey requires for key to be already set
752 RawBuffer pass = createHexPass(rawPassNew);
753 int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
755 if (result == SQLCIPHER_OK) {
756 LogPedantic("Reset key on DB");
758 //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
760 LogError("Failed to reset key on DB");
761 ThrowMsg(Exception::InvalidArguments, result);
765 void SqlConnection::Disconnect()
767 if (m_connection == NULL) {
768 LogPedantic("Already disconnected.");
772 LogPedantic("Disconnecting from DB...");
774 // All stored data commands must be deleted before disconnect
775 AssertMsg(m_dataCommandsCount == 0,
776 "All stored procedures must be deleted"
777 " before disconnecting SqlConnection");
781 result = sqlcipher3_close(m_connection);
783 if (result != SQLCIPHER_OK) {
784 const char *error = sqlcipher3_errmsg(m_connection);
785 LogError("SQL close failed");
786 LogError(" Error: " << error);
787 Throw(Exception::InternalError);
792 LogPedantic("Disconnected from DB");
795 bool SqlConnection::CheckTableExist(const char *tableName)
797 if (m_connection == NULL) {
798 LogPedantic("Cannot execute command. Not connected to DB!");
802 DataCommandUniquePtr command =
803 PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
805 command->BindString(1, tableName);
807 if (!command->Step()) {
808 LogPedantic("No matching records in table");
812 return command->GetColumnString(0) == tableName;
815 SqlConnection::SqlConnection(const std::string &address,
817 SynchronizationObject *synchronizationObject) :
819 m_dataCommandsCount(0),
820 m_synchronizationObject(synchronizationObject),
823 LogPedantic("Opening database connection to: " << address);
826 SqlConnection::Connect(address, option);
828 if (!m_synchronizationObject)
829 LogPedantic("No synchronization object defined");
832 SqlConnection::~SqlConnection()
834 LogPedantic("Closing database connection");
836 // Disconnect from DB
838 SqlConnection::Disconnect();
839 } catch (const Exception::Base &) {
840 LogError("Failed to disconnect from database");
844 int SqlConnection::Output::Callback(void *param, int columns, char **values,
848 static_cast<Output *>(param)->SetResults(columns, values, names);
853 void SqlConnection::Output::SetResults(int columns, char **values, char **names)
855 if (m_names.empty()) {
856 for (int i = 0; i < columns; i++)
857 m_names.push_back(names[i] ? names[i] : "NULL");
862 for (int i = 0; i < columns; i++)
863 row.push_back(values[i] ? values[i] : "NULL");
865 m_values.push_back(std::move(row));
868 void SqlConnection::ExecCommandHelper(Output *out, const char *format,
871 if (m_connection == NULL) {
872 LogError("Cannot execute command. Not connected to DB!");
876 if (format == NULL) {
877 LogError("Null query!");
878 ThrowMsg(Exception::SyntaxError, "Null statement");
883 if (vasprintf(&query, format, args) == -1) {
884 LogError("Failed to allocate statement string");
888 CharUniquePtr queryPtr(query);
890 LogPedantic("Executing SQL command: " << queryPtr.get());
892 // Notify all after potentially synchronized database connection access
893 ScopedNotifyAll notifyAll(m_synchronizationObject.get());
895 for (int i = 0; i < MAX_RETRY; i++) {
897 int ret = sqlcipher3_exec(m_connection,
899 out ? &Output::Callback : NULL,
903 std::string errorMsg;
905 // Take allocated error buffer
906 if (errorBuffer != NULL) {
907 errorMsg = errorBuffer;
908 sqlcipher3_free(errorBuffer);
911 if (ret == SQLCIPHER_OK)
914 if (ret == SQLCIPHER_BUSY) {
915 LogPedantic("Collision occurred while executing SQL command");
917 // Synchronize if synchronization object is available
918 if (m_synchronizationObject) {
919 LogPedantic("Performing synchronization");
920 m_synchronizationObject->Synchronize();
924 // No synchronization object defined. Fail.
928 LogError("Failed to execute SQL command. Error: " << errorMsg);
929 ThrowMsg(Exception::SyntaxError, errorMsg);
932 LogError("sqlite in the state of possible infinite loop");
933 ThrowMsg(Exception::InternalError, "sqlite permanently busy");
936 void SqlConnection::ExecCommand(Output *out, const char *format, ...)
938 scoped_va_start(svl, format);
940 ExecCommandHelper(out, format, svl.args);
943 void SqlConnection::ExecCommand(const char *format, ...)
945 scoped_va_start(svl, format);
947 ExecCommandHelper(NULL, format, svl.args);
950 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
954 if (m_connection == NULL) {
955 LogError("Cannot execute data command. Not connected to DB!");
956 return DataCommandUniquePtr();
962 va_start(args, format);
964 if (vasprintf(&rawBuffer, format, args) == -1)
969 CharUniquePtr buffer(rawBuffer);
972 LogError("Failed to allocate statement string");
973 return DataCommandUniquePtr();
976 LogPedantic("Executing SQL data command: " << buffer.get());
978 return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
981 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
983 return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
986 void SqlConnection::TurnOnForeignKeys()
988 ExecCommand("PRAGMA foreign_keys = ON;");
991 void SqlConnection::BeginTransaction()
993 ExecCommand("BEGIN;");
996 void SqlConnection::RollbackTransaction()
998 ExecCommand("ROLLBACK;");
1001 void SqlConnection::CommitTransaction()
1003 ExecCommand("COMMIT;");
1006 SqlConnection::SynchronizationObject *
1007 SqlConnection::AllocDefaultSynchronizationObject()
1009 return new NaiveSynchronizationObject();
1014 #pragma GCC diagnostic pop