Adapt SQLConnection to sqlcipher
[platform/core/security/key-manager.git] / src / manager / dpl / db / src / sql_connection.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file        sql_connection.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of SQL connection
21  */
22 #pragma GCC diagnostic push
23 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
24
25 #include <stddef.h>
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 <db-util.h>
32 #include <unistd.h>
33 #include <cstdio>
34 #include <cstdarg>
35 #include <memory>
36
37 namespace CKM {
38 namespace DB {
39 namespace // anonymous
40 {
41 class ScopedNotifyAll :
42     public Noncopyable
43 {
44   private:
45     SqlConnection::SynchronizationObject *m_synchronizationObject;
46
47   public:
48     explicit ScopedNotifyAll(
49         SqlConnection::SynchronizationObject *synchronizationObject) :
50         m_synchronizationObject(synchronizationObject)
51     {}
52
53     ~ScopedNotifyAll()
54     {
55         if (!m_synchronizationObject) {
56             return;
57         }
58
59         LogPedantic("Notifying after successful synchronize");
60         m_synchronizationObject->NotifyAll();
61     }
62 };
63 } // namespace anonymous
64
65 SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
66                                         const char *buffer) :
67     m_masterConnection(connection),
68     m_stmt(NULL)
69 {
70     Assert(connection != NULL);
71
72     // Notify all after potentially synchronized database connection access
73     ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
74
75     for (;;) {
76         int ret = sqlcipher3_prepare_v2(connection->m_connection,
77                                      buffer, strlen(buffer),
78                                      &m_stmt, NULL);
79
80         if (ret == SQLCIPHER_OK) {
81             LogPedantic("Data command prepared successfuly");
82             break;
83         } else if (ret == SQLCIPHER_BUSY) {
84             LogPedantic("Collision occurred while preparing SQL command");
85
86             // Synchronize if synchronization object is available
87             if (connection->m_synchronizationObject) {
88                 LogPedantic("Performing synchronization");
89                 connection->m_synchronizationObject->Synchronize();
90                 continue;
91             }
92
93             // No synchronization object defined. Fail.
94         }
95
96         // Fatal error
97         const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
98
99         LogPedantic("SQL prepare data command failed");
100         LogPedantic("    Statement: " << buffer);
101         LogPedantic("    Error: " << error);
102
103         ThrowMsg(Exception::SyntaxError, error);
104     }
105
106     LogPedantic("Prepared data command: " << buffer);
107
108     // Increment stored data command count
109     ++m_masterConnection->m_dataCommandsCount;
110 }
111
112 SqlConnection::DataCommand::~DataCommand()
113 {
114     LogPedantic("SQL data command finalizing");
115
116     if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK) {
117         LogPedantic("Failed to finalize data command");
118     }
119
120     // Decrement stored data command count
121     --m_masterConnection->m_dataCommandsCount;
122 }
123
124 void SqlConnection::DataCommand::CheckBindResult(int result)
125 {
126     if (result != SQLCIPHER_OK) {
127         const char *error = sqlcipher3_errmsg(
128                 m_masterConnection->m_connection);
129
130         LogPedantic("Failed to bind SQL statement parameter");
131         LogPedantic("    Error: " << error);
132
133         ThrowMsg(Exception::SyntaxError, error);
134     }
135 }
136
137 void SqlConnection::DataCommand::BindNull(
138     SqlConnection::ArgumentIndex position)
139 {
140     CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
141     LogPedantic("SQL data command bind null: ["
142                 << position << "]");
143 }
144
145 void SqlConnection::DataCommand::BindInteger(
146     SqlConnection::ArgumentIndex position,
147     int value)
148 {
149     CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
150     LogPedantic("SQL data command bind integer: ["
151                 << position << "] -> " << value);
152 }
153
154 void SqlConnection::DataCommand::BindInt8(
155     SqlConnection::ArgumentIndex position,
156     int8_t value)
157 {
158     CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
159                                      static_cast<int>(value)));
160     LogPedantic("SQL data command bind int8: ["
161                 << position << "] -> " << value);
162 }
163
164 void SqlConnection::DataCommand::BindInt16(
165     SqlConnection::ArgumentIndex position,
166     int16_t value)
167 {
168     CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
169                                      static_cast<int>(value)));
170     LogPedantic("SQL data command bind int16: ["
171                 << position << "] -> " << value);
172 }
173
174 void SqlConnection::DataCommand::BindInt32(
175     SqlConnection::ArgumentIndex position,
176     int32_t value)
177 {
178     CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
179                                      static_cast<int>(value)));
180     LogPedantic("SQL data command bind int32: ["
181                 << position << "] -> " << value);
182 }
183
184 void SqlConnection::DataCommand::BindInt64(
185     SqlConnection::ArgumentIndex position,
186     int64_t value)
187 {
188     CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
189                                        static_cast<sqlcipher3_int64>(value)));
190     LogPedantic("SQL data command bind int64: ["
191                 << position << "] -> " << value);
192 }
193
194 void SqlConnection::DataCommand::BindFloat(
195     SqlConnection::ArgumentIndex position,
196     float value)
197 {
198     CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
199                                         static_cast<double>(value)));
200     LogPedantic("SQL data command bind float: ["
201                 << position << "] -> " << value);
202 }
203
204 void SqlConnection::DataCommand::BindDouble(
205     SqlConnection::ArgumentIndex position,
206     double value)
207 {
208     CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
209     LogPedantic("SQL data command bind double: ["
210                 << position << "] -> " << value);
211 }
212
213 void SqlConnection::DataCommand::BindString(
214     SqlConnection::ArgumentIndex position,
215     const char *value)
216 {
217     if (!value) {
218         BindNull(position);
219         return;
220     }
221
222     // Assume that text may disappear
223     CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
224                                       value, strlen(value),
225                                       SQLCIPHER_TRANSIENT));
226
227     LogPedantic("SQL data command bind string: ["
228                 << position << "] -> " << value);
229 }
230
231 void SqlConnection::DataCommand::BindString(
232     SqlConnection::ArgumentIndex position,
233     const String &value)
234 {
235     BindString(position, ToUTF8String(value).c_str());
236 }
237
238 void SqlConnection::DataCommand::BindInteger(
239     SqlConnection::ArgumentIndex position,
240     const boost::optional<int> &value)
241 {
242     if (!value) {
243         BindNull(position);
244     } else {
245         BindInteger(position, *value);
246     }
247 }
248
249 void SqlConnection::DataCommand::BindInt8(
250     SqlConnection::ArgumentIndex position,
251     const boost::optional<int8_t> &value)
252 {
253     if (!value) {
254         BindNull(position);
255     } else {
256         BindInt8(position, *value);
257     }
258 }
259
260 void SqlConnection::DataCommand::BindInt16(
261     SqlConnection::ArgumentIndex position,
262     const boost::optional<int16_t> &value)
263 {
264     if (!value) {
265         BindNull(position);
266     } else {
267         BindInt16(position, *value);
268     }
269 }
270
271 void SqlConnection::DataCommand::BindInt32(
272     SqlConnection::ArgumentIndex position,
273     const boost::optional<int32_t> &value)
274 {
275     if (!value) {
276         BindNull(position);
277     } else {
278         BindInt32(position, *value);
279     }
280 }
281
282 void SqlConnection::DataCommand::BindInt64(
283     SqlConnection::ArgumentIndex position,
284     const boost::optional<int64_t> &value)
285 {
286     if (!value) {
287         BindNull(position);
288     } else {
289         BindInt64(position, *value);
290     }
291 }
292
293 void SqlConnection::DataCommand::BindFloat(
294     SqlConnection::ArgumentIndex position,
295     const boost::optional<float> &value)
296 {
297     if (!value) {
298         BindNull(position);
299     } else {
300         BindFloat(position, *value);
301     }
302 }
303
304 void SqlConnection::DataCommand::BindDouble(
305     SqlConnection::ArgumentIndex position,
306     const boost::optional<double> &value)
307 {
308     if (!value) {
309         BindNull(position);
310     } else {
311         BindDouble(position, *value);
312     }
313 }
314
315 void SqlConnection::DataCommand::BindString(
316     SqlConnection::ArgumentIndex position,
317     const boost::optional<String> &value)
318 {
319     if (!!value) {
320         BindString(position, ToUTF8String(*value).c_str());
321     } else {
322         BindNull(position);
323     }
324 }
325
326 bool SqlConnection::DataCommand::Step()
327 {
328     // Notify all after potentially synchronized database connection access
329     ScopedNotifyAll notifyAll(
330         m_masterConnection->m_synchronizationObject.get());
331
332     for (;;) {
333         int ret = sqlcipher3_step(m_stmt);
334
335         if (ret == SQLCIPHER_ROW) {
336             LogPedantic("SQL data command step ROW");
337             return true;
338         } else if (ret == SQLCIPHER_DONE) {
339             LogPedantic("SQL data command step DONE");
340             return false;
341         } else if (ret == SQLCIPHER_BUSY) {
342             LogPedantic("Collision occurred while executing SQL command");
343
344             // Synchronize if synchronization object is available
345             if (m_masterConnection->m_synchronizationObject) {
346                 LogPedantic("Performing synchronization");
347
348                 m_masterConnection->
349                     m_synchronizationObject->Synchronize();
350
351                 continue;
352             }
353
354             // No synchronization object defined. Fail.
355         }
356
357         // Fatal error
358         const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
359
360         LogPedantic("SQL step data command failed");
361         LogPedantic("    Error: " << error);
362
363         ThrowMsg(Exception::InternalError, error);
364     }
365 }
366
367 void SqlConnection::DataCommand::Reset()
368 {
369     /*
370      * According to:
371      * http://www.sqllite.org/c3ref/stmt.html
372      *
373      * if last sqlcipher3_step command on this stmt returned an error,
374      * then sqlcipher3_reset will return that error, althought it is not an error.
375      * So sqlcipher3_reset allways succedes.
376      */
377     sqlcipher3_reset(m_stmt);
378
379     LogPedantic("SQL data command reset");
380 }
381
382 void SqlConnection::DataCommand::CheckColumnIndex(
383     SqlConnection::ColumnIndex column)
384 {
385     if (column < 0 || column >= sqlcipher3_column_count(m_stmt)) {
386         ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
387     }
388 }
389
390 bool SqlConnection::DataCommand::IsColumnNull(
391     SqlConnection::ColumnIndex column)
392 {
393     LogPedantic("SQL data command get column type: [" << column << "]");
394     CheckColumnIndex(column);
395     return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
396 }
397
398 int SqlConnection::DataCommand::GetColumnInteger(
399     SqlConnection::ColumnIndex column)
400 {
401     LogPedantic("SQL data command get column integer: [" << column << "]");
402     CheckColumnIndex(column);
403     int value = sqlcipher3_column_int(m_stmt, column);
404     LogPedantic("    Value: " << value);
405     return value;
406 }
407
408 int8_t SqlConnection::DataCommand::GetColumnInt8(
409     SqlConnection::ColumnIndex column)
410 {
411     LogPedantic("SQL data command get column int8: [" << column << "]");
412     CheckColumnIndex(column);
413     int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
414     LogPedantic("    Value: " << value);
415     return value;
416 }
417
418 int16_t SqlConnection::DataCommand::GetColumnInt16(
419     SqlConnection::ColumnIndex column)
420 {
421     LogPedantic("SQL data command get column int16: [" << column << "]");
422     CheckColumnIndex(column);
423     int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
424     LogPedantic("    Value: " << value);
425     return value;
426 }
427
428 int32_t SqlConnection::DataCommand::GetColumnInt32(
429     SqlConnection::ColumnIndex column)
430 {
431     LogPedantic("SQL data command get column int32: [" << column << "]");
432     CheckColumnIndex(column);
433     int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
434     LogPedantic("    Value: " << value);
435     return value;
436 }
437
438 int64_t SqlConnection::DataCommand::GetColumnInt64(
439     SqlConnection::ColumnIndex column)
440 {
441     LogPedantic("SQL data command get column int64: [" << column << "]");
442     CheckColumnIndex(column);
443     int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
444     LogPedantic("    Value: " << value);
445     return value;
446 }
447
448 float SqlConnection::DataCommand::GetColumnFloat(
449     SqlConnection::ColumnIndex column)
450 {
451     LogPedantic("SQL data command get column float: [" << column << "]");
452     CheckColumnIndex(column);
453     float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
454     LogPedantic("    Value: " << value);
455     return value;
456 }
457
458 double SqlConnection::DataCommand::GetColumnDouble(
459     SqlConnection::ColumnIndex column)
460 {
461     LogPedantic("SQL data command get column double: [" << column << "]");
462     CheckColumnIndex(column);
463     double value = sqlcipher3_column_double(m_stmt, column);
464     LogPedantic("    Value: " << value);
465     return value;
466 }
467
468 std::string SqlConnection::DataCommand::GetColumnString(
469     SqlConnection::ColumnIndex column)
470 {
471     LogPedantic("SQL data command get column string: [" << column << "]");
472     CheckColumnIndex(column);
473
474     const char *value = reinterpret_cast<const char *>(
475             sqlcipher3_column_text(m_stmt, column));
476
477     LogPedantic("Value: " << (value ? value : "NULL"));
478
479     if (value == NULL) {
480         return std::string();
481     }
482
483     return std::string(value);
484 }
485
486 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
487     SqlConnection::ColumnIndex column)
488 {
489     LogPedantic("SQL data command get column optional integer: ["
490                 << column << "]");
491     CheckColumnIndex(column);
492     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
493         return boost::optional<int>();
494     }
495     int value = sqlcipher3_column_int(m_stmt, column);
496     LogPedantic("    Value: " << value);
497     return boost::optional<int>(value);
498 }
499
500 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
501     SqlConnection::ColumnIndex column)
502 {
503     LogPedantic("SQL data command get column optional int8: ["
504                 << column << "]");
505     CheckColumnIndex(column);
506     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
507         return boost::optional<int8_t>();
508     }
509     int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
510     LogPedantic("    Value: " << value);
511     return boost::optional<int8_t>(value);
512 }
513
514 boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
515     SqlConnection::ColumnIndex column)
516 {
517     LogPedantic("SQL data command get column optional int16: ["
518                 << column << "]");
519     CheckColumnIndex(column);
520     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
521         return boost::optional<int16_t>();
522     }
523     int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
524     LogPedantic("    Value: " << value);
525     return boost::optional<int16_t>(value);
526 }
527
528 boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
529     SqlConnection::ColumnIndex column)
530 {
531     LogPedantic("SQL data command get column optional int32: ["
532                 << column << "]");
533     CheckColumnIndex(column);
534     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
535         return boost::optional<int32_t>();
536     }
537     int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
538     LogPedantic("    Value: " << value);
539     return boost::optional<int32_t>(value);
540 }
541
542 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
543     SqlConnection::ColumnIndex column)
544 {
545     LogPedantic("SQL data command get column optional int64: ["
546                 << column << "]");
547     CheckColumnIndex(column);
548     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
549         return boost::optional<int64_t>();
550     }
551     int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
552     LogPedantic("    Value: " << value);
553     return boost::optional<int64_t>(value);
554 }
555
556 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
557     SqlConnection::ColumnIndex column)
558 {
559     LogPedantic("SQL data command get column optional float: ["
560                 << column << "]");
561     CheckColumnIndex(column);
562     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
563         return boost::optional<float>();
564     }
565     float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
566     LogPedantic("    Value: " << value);
567     return boost::optional<float>(value);
568 }
569
570 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
571     SqlConnection::ColumnIndex column)
572 {
573     LogPedantic("SQL data command get column optional double: ["
574                 << column << "]");
575     CheckColumnIndex(column);
576     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
577         return boost::optional<double>();
578     }
579     double value = sqlcipher3_column_double(m_stmt, column);
580     LogPedantic("    Value: " << value);
581     return boost::optional<double>(value);
582 }
583
584 boost::optional<String> SqlConnection::DataCommand::GetColumnOptionalString(
585     SqlConnection::ColumnIndex column)
586 {
587     LogPedantic("SQL data command get column optional string: ["
588                 << column << "]");
589     CheckColumnIndex(column);
590     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
591         return boost::optional<String>();
592     }
593     const char *value = reinterpret_cast<const char *>(
594             sqlcipher3_column_text(m_stmt, column));
595     LogPedantic("Value: " << value);
596     String s = FromUTF8String(value);
597     return boost::optional<String>(s);
598 }
599
600 void SqlConnection::Connect(const std::string &address,
601                             Flag::Option flag)
602 {
603     if (m_connection != NULL) {
604         LogPedantic("Already connected.");
605         return;
606     }
607     LogPedantic("Connecting to DB: " << address << "...");
608
609     // Connect to database
610     int result;
611     result = sqlcipher3_open_v2(
612             address.c_str(),
613             &m_connection,
614             flag,
615             NULL);
616
617     if (result == SQLCIPHER_OK) {
618         LogPedantic("Connected to DB");
619     } else {
620         LogPedantic("Failed to connect to DB!");
621         ThrowMsg(Exception::ConnectionBroken, address);
622     }
623
624     // Enable foreign keys
625     TurnOnForeignKeys();
626 }
627
628 static std::string rawToHexString(const std::vector<unsigned char> &raw) {
629     std::string str(raw.size() * 2, '0');
630     for (std::size_t i = 0; i < raw.size(); i++)
631         sprintf(&str[i*2], "%02X", raw[i]);
632     return str;
633 }
634
635 void SqlConnection::SetKey(const std::vector<unsigned char> &rawPass){
636     if (m_connection == NULL) {
637         LogPedantic("Cannot set key. No connection to DB!");
638         return;
639     }
640     std::string pass = "x'" + rawToHexString(rawPass) + "'";
641     int result = sqlcipher3_key(m_connection, pass.c_str(), pass.length());
642     if (result == SQLCIPHER_OK) {
643         LogPedantic("Set key on DB");
644     } else {
645         //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
646         //                            key length == 0
647         LogPedantic("Failed to set key on DB");
648         ThrowMsg(Exception::InvalidArguments, result);
649     }
650
651     m_isKeySet = true;
652 };
653
654 void SqlConnection::ResetKey(const std::vector<unsigned char> &rawPassOld,
655                              const std::vector<unsigned char> &rawPassNew) {
656     if (m_connection == NULL) {
657         LogPedantic("Cannot reset key. No connection to DB!");
658         return;
659     }
660     // sqlcipher3_rekey requires for key to be already set
661     if (!m_isKeySet)
662         SetKey(rawPassOld);
663
664     std::string pass = "x'" + rawToHexString(rawPassNew) + "'";
665     int result = sqlcipher3_rekey(m_connection, pass.c_str(), pass.length());
666     if (result == SQLCIPHER_OK) {
667         LogPedantic("Reset key on DB");
668     } else {
669         //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
670         //                              key length == 0
671         LogPedantic("Failed to reset key on DB");
672         ThrowMsg(Exception::InvalidArguments, result);
673     }
674     //Wiping out the key (required)
675     pass.assign(pass.length(), '0');
676     for(std::size_t i = 0; i < pass.length(); i++) {
677         if(pass[i] != '0') {
678             LogPedantic("Wiping key failed.");
679             ThrowMsg(Exception::InternalError, "Wiping key failed");
680         }
681     }
682 }
683
684 void SqlConnection::Disconnect()
685 {
686     if (m_connection == NULL) {
687         LogPedantic("Already disconnected.");
688         return;
689     }
690
691     LogPedantic("Disconnecting from DB...");
692
693     // All stored data commands must be deleted before disconnect
694     AssertMsg(m_dataCommandsCount == 0,
695            "All stored procedures must be deleted"
696            " before disconnecting SqlConnection");
697
698     int result;
699
700     result = sqlcipher3_close(m_connection);
701
702     if (result != SQLCIPHER_OK) {
703         const char *error = sqlcipher3_errmsg(m_connection);
704         LogPedantic("SQL close failed");
705         LogPedantic("    Error: " << error);
706         Throw(Exception::InternalError);
707     }
708
709     m_connection = NULL;
710
711     LogPedantic("Disconnected from DB");
712 }
713
714 bool SqlConnection::CheckTableExist(const char *tableName)
715 {
716     if (m_connection == NULL) {
717         LogPedantic("Cannot execute command. Not connected to DB!");
718         return false;
719     }
720
721     DataCommandAutoPtr command =
722         PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
723
724     command->BindString(1, tableName);
725
726     if (!command->Step()) {
727         LogPedantic("No matching records in table");
728         return false;
729     }
730
731     return command->GetColumnString(0) == tableName;
732 }
733
734 SqlConnection::SqlConnection(const std::string &address,
735                              Flag::Option option,
736                              SynchronizationObject *synchronizationObject) :
737     m_connection(NULL),
738     m_dataCommandsCount(0),
739     m_synchronizationObject(synchronizationObject),
740     m_isKeySet(false)
741 {
742     LogPedantic("Opening database connection to: " << address);
743
744     // Connect to DB
745     SqlConnection::Connect(address, option);
746
747     if (!m_synchronizationObject) {
748         LogPedantic("No synchronization object defined");
749     }
750 }
751
752 SqlConnection::~SqlConnection()
753 {
754     LogPedantic("Closing database connection");
755
756     // Disconnect from DB
757     Try
758     {
759         SqlConnection::Disconnect();
760     }
761     Catch(Exception::Base)
762     {
763         LogPedantic("Failed to disconnect from database");
764     }
765 }
766
767 void SqlConnection::ExecCommand(const char *format, ...)
768 {
769     if (m_connection == NULL) {
770         LogPedantic("Cannot execute command. Not connected to DB!");
771         return;
772     }
773
774     if (format == NULL) {
775         LogPedantic("Null query!");
776         ThrowMsg(Exception::SyntaxError, "Null statement");
777     }
778
779     char *rawBuffer;
780
781     va_list args;
782     va_start(args, format);
783
784     if (vasprintf(&rawBuffer, format, args) == -1) {
785         rawBuffer = NULL;
786     }
787
788     va_end(args);
789
790     CharUniquePtr buffer(rawBuffer);
791
792     if (!buffer) {
793         LogPedantic("Failed to allocate statement string");
794         return;
795     }
796
797     LogPedantic("Executing SQL command: " << buffer.get());
798
799     // Notify all after potentially synchronized database connection access
800     ScopedNotifyAll notifyAll(m_synchronizationObject.get());
801
802     for (;;) {
803         char *errorBuffer;
804
805         int ret = sqlcipher3_exec(m_connection,
806                                buffer.get(),
807                                NULL,
808                                NULL,
809                                &errorBuffer);
810
811         std::string errorMsg;
812
813         // Take allocated error buffer
814         if (errorBuffer != NULL) {
815             errorMsg = errorBuffer;
816             sqlcipher3_free(errorBuffer);
817         }
818
819         if (ret == SQLCIPHER_OK) {
820             return;
821         }
822
823         if (ret == SQLCIPHER_BUSY) {
824             LogPedantic("Collision occurred while executing SQL command");
825
826             // Synchronize if synchronization object is available
827             if (m_synchronizationObject) {
828                 LogPedantic("Performing synchronization");
829                 m_synchronizationObject->Synchronize();
830                 continue;
831             }
832
833             // No synchronization object defined. Fail.
834         }
835
836         // Fatal error
837         LogPedantic("Failed to execute SQL command. Error: " << errorMsg);
838         ThrowMsg(Exception::SyntaxError, errorMsg);
839     }
840 }
841
842 SqlConnection::DataCommandAutoPtr SqlConnection::PrepareDataCommand(
843     const char *format,
844     ...)
845 {
846     if (m_connection == NULL) {
847         LogPedantic("Cannot execute data command. Not connected to DB!");
848         return DataCommandAutoPtr();
849     }
850
851     char *rawBuffer;
852
853     va_list args;
854     va_start(args, format);
855
856     if (vasprintf(&rawBuffer, format, args) == -1) {
857         rawBuffer = NULL;
858     }
859
860     va_end(args);
861
862     CharUniquePtr buffer(rawBuffer);
863
864     if (!buffer) {
865         LogPedantic("Failed to allocate statement string");
866         return DataCommandAutoPtr();
867     }
868
869     LogPedantic("Executing SQL data command: " << buffer.get());
870
871     return DataCommandAutoPtr(new DataCommand(this, buffer.get()));
872 }
873
874 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
875 {
876     return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
877 }
878
879 void SqlConnection::TurnOnForeignKeys()
880 {
881     ExecCommand("PRAGMA foreign_keys = ON;");
882 }
883
884 void SqlConnection::BeginTransaction()
885 {
886     ExecCommand("BEGIN;");
887 }
888
889 void SqlConnection::RollbackTransaction()
890 {
891     ExecCommand("ROLLBACK;");
892 }
893
894 void SqlConnection::CommitTransaction()
895 {
896     ExecCommand("COMMIT;");
897 }
898
899 SqlConnection::SynchronizationObject *
900 SqlConnection::AllocDefaultSynchronizationObject()
901 {
902     return new NaiveSynchronizationObject();
903 }
904 } // namespace DB
905 } // namespace CKM
906
907 #pragma GCC diagnostic pop