Revert "Add functions required during db debug."
[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/assert.h>
29 #include <dpl/scoped_ptr.h>
30 #include <unistd.h>
31 #include <cstdio>
32 #include <cstdarg>
33 #include <memory>
34 #include <noncopyable.h>
35
36
37 namespace {
38 const int MAX_RETRY = 10;
39
40 struct ScopedVaList {
41     ~ScopedVaList() { va_end(args); }
42     va_list args;
43 };
44
45 #define scoped_va_start(name, param) ScopedVaList name; va_start(name.args, param);
46 }
47
48 namespace CKM {
49 namespace DB {
50 namespace // anonymous
51 {
52 class ScopedNotifyAll
53 {
54   private:
55     SqlConnection::SynchronizationObject *m_synchronizationObject;
56
57   public:
58     NONCOPYABLE(ScopedNotifyAll)
59
60     explicit ScopedNotifyAll(
61         SqlConnection::SynchronizationObject *synchronizationObject) :
62         m_synchronizationObject(synchronizationObject)
63     {}
64
65     ~ScopedNotifyAll()
66     {
67         if (!m_synchronizationObject) {
68             return;
69         }
70
71         LogPedantic("Notifying after successful synchronize");
72         m_synchronizationObject->NotifyAll();
73     }
74 };
75 } // namespace anonymous
76
77 SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
78                                         const char *buffer) :
79     m_masterConnection(connection),
80     m_stmt(NULL)
81 {
82     Assert(connection != NULL);
83
84     // Notify all after potentially synchronized database connection access
85     ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
86
87     for (int i = 0; i < MAX_RETRY; i++) {
88         int ret = sqlcipher3_prepare_v2(connection->m_connection,
89                                      buffer, strlen(buffer),
90                                      &m_stmt, NULL);
91
92         if (ret == SQLCIPHER_OK) {
93             LogPedantic("Prepared data command: " << buffer);
94
95             // Increment stored data command count
96             ++m_masterConnection->m_dataCommandsCount;
97             return;
98         } else if (ret == SQLCIPHER_BUSY) {
99             LogPedantic("Collision occurred while preparing SQL command");
100
101             // Synchronize if synchronization object is available
102             if (connection->m_synchronizationObject) {
103                 LogPedantic("Performing synchronization");
104                 connection->m_synchronizationObject->Synchronize();
105                 continue;
106             }
107
108             // No synchronization object defined. Fail.
109         }
110
111         // Fatal error
112         const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
113
114         LogError("SQL prepare data command failed");
115         LogError("    Statement: " << buffer);
116         LogError("    Error: " << error);
117
118         ThrowMsg(Exception::SyntaxError, error);
119     }
120
121     LogError("sqlite in the state of possible infinite loop");
122     ThrowMsg(Exception::InternalError, "sqlite permanently busy");
123 }
124
125 SqlConnection::DataCommand::~DataCommand()
126 {
127     LogPedantic("SQL data command finalizing");
128
129     if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK) {
130         LogError("Failed to finalize data command");
131     }
132
133     // Decrement stored data command count
134     --m_masterConnection->m_dataCommandsCount;
135 }
136
137 void SqlConnection::DataCommand::CheckBindResult(int result)
138 {
139     if (result != SQLCIPHER_OK) {
140         const char *error = sqlcipher3_errmsg(
141                 m_masterConnection->m_connection);
142
143         LogError("Failed to bind SQL statement parameter");
144         LogError("    Error: " << error);
145
146         ThrowMsg(Exception::SyntaxError, error);
147     }
148 }
149
150 void SqlConnection::DataCommand::BindNull(
151     SqlConnection::ArgumentIndex position)
152 {
153     CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
154     LogPedantic("SQL data command bind null: ["
155                 << position << "]");
156 }
157
158 void SqlConnection::DataCommand::BindInteger(
159     SqlConnection::ArgumentIndex position,
160     int value)
161 {
162     CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
163     LogPedantic("SQL data command bind integer: ["
164                 << position << "] -> " << value);
165 }
166
167 void SqlConnection::DataCommand::BindInt8(
168     SqlConnection::ArgumentIndex position,
169     int8_t value)
170 {
171     CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
172                                      static_cast<int>(value)));
173     LogPedantic("SQL data command bind int8: ["
174                 << position << "] -> " << value);
175 }
176
177 void SqlConnection::DataCommand::BindInt16(
178     SqlConnection::ArgumentIndex position,
179     int16_t value)
180 {
181     CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
182                                      static_cast<int>(value)));
183     LogPedantic("SQL data command bind int16: ["
184                 << position << "] -> " << value);
185 }
186
187 void SqlConnection::DataCommand::BindInt32(
188     SqlConnection::ArgumentIndex position,
189     int32_t value)
190 {
191     CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
192                                      static_cast<int>(value)));
193     LogPedantic("SQL data command bind int32: ["
194                 << position << "] -> " << value);
195 }
196
197 void SqlConnection::DataCommand::BindInt64(
198     SqlConnection::ArgumentIndex position,
199     int64_t value)
200 {
201     CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
202                                        static_cast<sqlcipher3_int64>(value)));
203     LogPedantic("SQL data command bind int64: ["
204                 << position << "] -> " << value);
205 }
206
207 void SqlConnection::DataCommand::BindFloat(
208     SqlConnection::ArgumentIndex position,
209     float value)
210 {
211     CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
212                                         static_cast<double>(value)));
213     LogPedantic("SQL data command bind float: ["
214                 << position << "] -> " << value);
215 }
216
217 void SqlConnection::DataCommand::BindDouble(
218     SqlConnection::ArgumentIndex position,
219     double value)
220 {
221     CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
222     LogPedantic("SQL data command bind double: ["
223                 << position << "] -> " << value);
224 }
225
226 void SqlConnection::DataCommand::BindString(
227     SqlConnection::ArgumentIndex position,
228     const char *value)
229 {
230     if (!value) {
231         BindNull(position);
232         return;
233     }
234
235     // Assume that text may disappear
236     CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
237                                       value, strlen(value),
238                                       SQLCIPHER_TRANSIENT));
239
240     LogPedantic("SQL data command bind string: ["
241                 << position << "] -> " << value);
242 }
243
244 void SqlConnection::DataCommand::BindBlob(
245     SqlConnection::ArgumentIndex position,
246     const RawBuffer &raw)
247 {
248     if (raw.size() == 0) {
249         BindNull(position);
250         return;
251     }
252
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());
259 }
260
261 void SqlConnection::DataCommand::BindInteger(
262     SqlConnection::ArgumentIndex position,
263     const boost::optional<int> &value)
264 {
265     if (!value) {
266         BindNull(position);
267     } else {
268         BindInteger(position, *value);
269     }
270 }
271
272 void SqlConnection::DataCommand::BindInt8(
273     SqlConnection::ArgumentIndex position,
274     const boost::optional<int8_t> &value)
275 {
276     if (!value) {
277         BindNull(position);
278     } else {
279         BindInt8(position, *value);
280     }
281 }
282
283 void SqlConnection::DataCommand::BindInt16(
284     SqlConnection::ArgumentIndex position,
285     const boost::optional<int16_t> &value)
286 {
287     if (!value) {
288         BindNull(position);
289     } else {
290         BindInt16(position, *value);
291     }
292 }
293
294 void SqlConnection::DataCommand::BindInt32(
295     SqlConnection::ArgumentIndex position,
296     const boost::optional<int32_t> &value)
297 {
298     if (!value) {
299         BindNull(position);
300     } else {
301         BindInt32(position, *value);
302     }
303 }
304
305 void SqlConnection::DataCommand::BindInt64(
306     SqlConnection::ArgumentIndex position,
307     const boost::optional<int64_t> &value)
308 {
309     if (!value) {
310         BindNull(position);
311     } else {
312         BindInt64(position, *value);
313     }
314 }
315
316 void SqlConnection::DataCommand::BindFloat(
317     SqlConnection::ArgumentIndex position,
318     const boost::optional<float> &value)
319 {
320     if (!value) {
321         BindNull(position);
322     } else {
323         BindFloat(position, *value);
324     }
325 }
326
327 void SqlConnection::DataCommand::BindDouble(
328     SqlConnection::ArgumentIndex position,
329     const boost::optional<double> &value)
330 {
331     if (!value) {
332         BindNull(position);
333     } else {
334         BindDouble(position, *value);
335     }
336 }
337
338 void SqlConnection::DataCommand::BindBlob(
339     SqlConnection::ArgumentIndex position,
340     const boost::optional<RawBuffer> &value)
341 {
342     if (!!value) {
343         BindBlob(position, *value);
344     } else {
345         BindNull(position);
346     }
347 }
348
349 bool SqlConnection::DataCommand::Step()
350 {
351     // Notify all after potentially synchronized database connection access
352     ScopedNotifyAll notifyAll(
353         m_masterConnection->m_synchronizationObject.get());
354
355     for (int i = 0; i < MAX_RETRY; i++) {
356         int ret = sqlcipher3_step(m_stmt);
357
358         if (ret == SQLCIPHER_ROW) {
359             LogPedantic("SQL data command step ROW");
360             return true;
361         } else if (ret == SQLCIPHER_DONE) {
362             LogPedantic("SQL data command step DONE");
363             return false;
364         } else if (ret == SQLCIPHER_BUSY) {
365             LogPedantic("Collision occurred while executing SQL command");
366
367             // Synchronize if synchronization object is available
368             if (m_masterConnection->m_synchronizationObject) {
369                 LogPedantic("Performing synchronization");
370
371                 m_masterConnection->
372                     m_synchronizationObject->Synchronize();
373
374                 continue;
375             }
376             // No synchronization object defined. Fail.
377         }
378
379         // Fatal error
380         const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
381
382         LogError("SQL step data command failed");
383         LogError("    Error: " << error);
384
385         ThrowMsg(Exception::InternalError, error);
386     }
387
388     LogError("sqlite in the state of possible infinite loop");
389     ThrowMsg(Exception::InternalError, "sqlite permanently busy");
390 }
391
392 void SqlConnection::DataCommand::Reset()
393 {
394     /*
395      * According to:
396      * http://www.sqllite.org/c3ref/stmt.html
397      *
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.
401      */
402     sqlcipher3_reset(m_stmt);
403
404     LogPedantic("SQL data command reset");
405 }
406
407 void SqlConnection::DataCommand::CheckColumnIndex(
408     SqlConnection::ColumnIndex column)
409 {
410     if (column < 0 || column >= sqlcipher3_column_count(m_stmt)) {
411         ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
412     }
413 }
414
415 bool SqlConnection::DataCommand::IsColumnNull(
416     SqlConnection::ColumnIndex column)
417 {
418     LogPedantic("SQL data command get column type: [" << column << "]");
419     CheckColumnIndex(column);
420     return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
421 }
422
423 int SqlConnection::DataCommand::GetColumnInteger(
424     SqlConnection::ColumnIndex column)
425 {
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);
430     return value;
431 }
432
433 int8_t SqlConnection::DataCommand::GetColumnInt8(
434     SqlConnection::ColumnIndex column)
435 {
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);
440     return value;
441 }
442
443 int16_t SqlConnection::DataCommand::GetColumnInt16(
444     SqlConnection::ColumnIndex column)
445 {
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);
450     return value;
451 }
452
453 int32_t SqlConnection::DataCommand::GetColumnInt32(
454     SqlConnection::ColumnIndex column)
455 {
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);
460     return value;
461 }
462
463 int64_t SqlConnection::DataCommand::GetColumnInt64(
464     SqlConnection::ColumnIndex column)
465 {
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);
470     return value;
471 }
472
473 float SqlConnection::DataCommand::GetColumnFloat(
474     SqlConnection::ColumnIndex column)
475 {
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);
480     return value;
481 }
482
483 double SqlConnection::DataCommand::GetColumnDouble(
484     SqlConnection::ColumnIndex column)
485 {
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);
490     return value;
491 }
492
493 std::string SqlConnection::DataCommand::GetColumnString(
494     SqlConnection::ColumnIndex column)
495 {
496     LogPedantic("SQL data command get column string: [" << column << "]");
497     CheckColumnIndex(column);
498
499     const char *value = reinterpret_cast<const char *>(
500             sqlcipher3_column_text(m_stmt, column));
501
502     LogPedantic("Value: " << (value ? value : "NULL"));
503
504     if (value == NULL) {
505         return std::string();
506     }
507
508     return std::string(value);
509 }
510
511 RawBuffer SqlConnection::DataCommand::GetColumnBlob(
512     SqlConnection::ColumnIndex column)
513 {
514     LogPedantic("SQL data command get column blog: [" << column << "]");
515     CheckColumnIndex(column);
516
517     const unsigned char *value = reinterpret_cast<const unsigned char*>(
518             sqlcipher3_column_blob(m_stmt, column));
519
520     if (value == NULL) {
521         return RawBuffer();
522     }
523
524     int length = sqlcipher3_column_bytes(m_stmt, column);
525     LogPedantic("Got blob of length: " << length);
526
527     return RawBuffer(value, value + length);
528 }
529
530 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
531     SqlConnection::ColumnIndex column)
532 {
533     LogPedantic("SQL data command get column optional integer: ["
534                 << column << "]");
535     CheckColumnIndex(column);
536     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
537         return boost::optional<int>();
538     }
539     int value = sqlcipher3_column_int(m_stmt, column);
540     LogPedantic("    Value: " << value);
541     return boost::optional<int>(value);
542 }
543
544 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
545     SqlConnection::ColumnIndex column)
546 {
547     LogPedantic("SQL data command get column optional int8: ["
548                 << column << "]");
549     CheckColumnIndex(column);
550     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
551         return boost::optional<int8_t>();
552     }
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);
556 }
557
558 boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
559     SqlConnection::ColumnIndex column)
560 {
561     LogPedantic("SQL data command get column optional int16: ["
562                 << column << "]");
563     CheckColumnIndex(column);
564     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
565         return boost::optional<int16_t>();
566     }
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);
570 }
571
572 boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
573     SqlConnection::ColumnIndex column)
574 {
575     LogPedantic("SQL data command get column optional int32: ["
576                 << column << "]");
577     CheckColumnIndex(column);
578     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
579         return boost::optional<int32_t>();
580     }
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);
584 }
585
586 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
587     SqlConnection::ColumnIndex column)
588 {
589     LogPedantic("SQL data command get column optional int64: ["
590                 << column << "]");
591     CheckColumnIndex(column);
592     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
593         return boost::optional<int64_t>();
594     }
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);
598 }
599
600 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
601     SqlConnection::ColumnIndex column)
602 {
603     LogPedantic("SQL data command get column optional float: ["
604                 << column << "]");
605     CheckColumnIndex(column);
606     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
607         return boost::optional<float>();
608     }
609     float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
610     LogPedantic("    Value: " << value);
611     return boost::optional<float>(value);
612 }
613
614 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
615     SqlConnection::ColumnIndex column)
616 {
617     LogPedantic("SQL data command get column optional double: ["
618                 << column << "]");
619     CheckColumnIndex(column);
620     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
621         return boost::optional<double>();
622     }
623     double value = sqlcipher3_column_double(m_stmt, column);
624     LogPedantic("    Value: " << value);
625     return boost::optional<double>(value);
626 }
627
628 boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
629     SqlConnection::ColumnIndex column)
630 {
631     LogPedantic("SQL data command get column blog: [" << column << "]");
632     CheckColumnIndex(column);
633
634     if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL) {
635         return boost::optional<RawBuffer>();
636     }
637     const unsigned char *value = reinterpret_cast<const unsigned char*>(
638             sqlcipher3_column_blob(m_stmt, column));
639
640     int length = sqlcipher3_column_bytes(m_stmt, column);
641     LogPedantic("Got blob of length: " << length);
642
643     RawBuffer temp(value, value + length);
644     return boost::optional<RawBuffer>(temp);
645 }
646
647 void SqlConnection::Connect(const std::string &address,
648                             Flag::Option flag)
649 {
650     if (m_connection != NULL) {
651         LogPedantic("Already connected.");
652         return;
653     }
654     LogPedantic("Connecting to DB: " << address << "...");
655
656     // Connect to database
657     int result;
658     result = sqlcipher3_open_v2(
659             address.c_str(),
660             &m_connection,
661             flag,
662             NULL);
663
664     if (result == SQLCIPHER_OK) {
665         LogPedantic("Connected to DB");
666     } else {
667         LogError("Failed to connect to DB!");
668         ThrowMsg(Exception::ConnectionBroken, address);
669     }
670
671     // Enable foreign keys
672     TurnOnForeignKeys();
673 }
674
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;
678
679 RawBuffer rawToHexString(const RawBuffer &raw)
680 {
681     RawBuffer output;
682     for(auto &e: raw) {
683         char result[3];
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]));
687     }
688     return output;
689 }
690
691 RawBuffer createHexPass(const RawBuffer &rawPass){
692     // We are required to pass 64byte long hex password made out of 32byte raw
693     // binary data
694     RawBuffer output;
695     std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
696         std::back_inserter(output));
697
698     RawBuffer password = rawToHexString(rawPass);
699
700     std::copy(password.begin(), password.end(),
701         std::back_inserter(output));
702
703     std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
704         std::back_inserter(output));
705
706     return output;
707 }
708
709 void SqlConnection::SetKey(const RawBuffer &rawPass){
710     if (m_connection == NULL) {
711         LogPedantic("Cannot set key. No connection to DB!");
712         return;
713     }
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");
721     } else {
722         //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
723         //                            key length == 0
724         LogError("Failed to set key on DB");
725         ThrowMsg(Exception::InvalidArguments, result);
726     }
727
728     m_isKeySet = true;
729 };
730
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!");
735         return;
736     }
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."
740              );
741     // sqlcipher3_rekey requires for key to be already set
742     if (!m_isKeySet)
743         SetKey(rawPassOld);
744
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");
749     } else {
750         //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
751         //                              key length == 0
752         LogError("Failed to reset key on DB");
753         ThrowMsg(Exception::InvalidArguments, result);
754     }
755 }
756
757 void SqlConnection::Disconnect()
758 {
759     if (m_connection == NULL) {
760         LogPedantic("Already disconnected.");
761         return;
762     }
763
764     LogPedantic("Disconnecting from DB...");
765
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");
770
771     int result;
772
773     result = sqlcipher3_close(m_connection);
774
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);
780     }
781
782     m_connection = NULL;
783
784     LogPedantic("Disconnected from DB");
785 }
786
787 bool SqlConnection::CheckTableExist(const char *tableName)
788 {
789     if (m_connection == NULL) {
790         LogPedantic("Cannot execute command. Not connected to DB!");
791         return false;
792     }
793
794     DataCommandUniquePtr command =
795         PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
796
797     command->BindString(1, tableName);
798
799     if (!command->Step()) {
800         LogPedantic("No matching records in table");
801         return false;
802     }
803
804     return command->GetColumnString(0) == tableName;
805 }
806
807 SqlConnection::SqlConnection(const std::string &address,
808                              Flag::Option option,
809                              SynchronizationObject *synchronizationObject) :
810     m_connection(NULL),
811     m_dataCommandsCount(0),
812     m_synchronizationObject(synchronizationObject),
813     m_isKeySet(false)
814 {
815     LogPedantic("Opening database connection to: " << address);
816
817     // Connect to DB
818     SqlConnection::Connect(address, option);
819
820     if (!m_synchronizationObject) {
821         LogPedantic("No synchronization object defined");
822     }
823 }
824
825 SqlConnection::~SqlConnection()
826 {
827     LogPedantic("Closing database connection");
828
829     // Disconnect from DB
830     Try
831     {
832         SqlConnection::Disconnect();
833     }
834     Catch(Exception::Base)
835     {
836         LogError("Failed to disconnect from database");
837     }
838 }
839
840 int SqlConnection::Output::Callback(void* param, int columns, char** values, char** names)
841 {
842     if(param)
843         static_cast<Output*>(param)->SetResults(columns, values, names);
844     return 0;
845 }
846
847 void SqlConnection::Output::SetResults(int columns, char** values, char** names)
848 {
849     if (m_names.empty()) {
850         for (int i=0;i<columns;i++)
851             m_names.push_back(names[i] ? names[i] : "NULL");
852     }
853     Row row;
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));
857 }
858
859 void SqlConnection::ExecCommandHelper(Output* out, const char* format, va_list args)
860 {
861     if (m_connection == NULL) {
862         LogError("Cannot execute command. Not connected to DB!");
863         return;
864     }
865
866     if (format == NULL) {
867         LogError("Null query!");
868         ThrowMsg(Exception::SyntaxError, "Null statement");
869     }
870
871     char *query;
872
873     if (vasprintf(&query, format, args) == -1) {
874         LogError("Failed to allocate statement string");
875         return;
876     }
877
878     CharUniquePtr queryPtr(query);
879
880     LogPedantic("Executing SQL command: " << queryPtr.get());
881
882     // Notify all after potentially synchronized database connection access
883     ScopedNotifyAll notifyAll(m_synchronizationObject.get());
884
885     for (int i = 0; i < MAX_RETRY; i++) {
886         char *errorBuffer;
887         int ret = sqlcipher3_exec(m_connection,
888                                   queryPtr.get(),
889                                   out ? &Output::Callback : NULL,
890                                   out,
891                                   &errorBuffer);
892
893         std::string errorMsg;
894
895         // Take allocated error buffer
896         if (errorBuffer != NULL) {
897             errorMsg = errorBuffer;
898             sqlcipher3_free(errorBuffer);
899         }
900
901         if (ret == SQLCIPHER_OK) {
902             return;
903         }
904
905         if (ret == SQLCIPHER_BUSY) {
906             LogPedantic("Collision occurred while executing SQL command");
907
908             // Synchronize if synchronization object is available
909             if (m_synchronizationObject) {
910                 LogPedantic("Performing synchronization");
911                 m_synchronizationObject->Synchronize();
912                 continue;
913             }
914
915             // No synchronization object defined. Fail.
916         }
917
918         // Fatal error
919         LogError("Failed to execute SQL command. Error: " << errorMsg);
920         ThrowMsg(Exception::SyntaxError, errorMsg);
921     }
922
923     LogError("sqlite in the state of possible infinite loop");
924     ThrowMsg(Exception::InternalError, "sqlite permanently busy");
925 }
926
927 void SqlConnection::ExecCommand(Output* out, const char *format, ...)
928 {
929     scoped_va_start(svl, format);
930
931     ExecCommandHelper(out, format, svl.args);
932 }
933
934 void SqlConnection::ExecCommand(const char *format, ...)
935 {
936     scoped_va_start(svl, format);
937
938     ExecCommandHelper(NULL, format, svl.args);
939 }
940
941 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
942     const char *format,
943     ...)
944 {
945     if (m_connection == NULL) {
946         LogError("Cannot execute data command. Not connected to DB!");
947         return DataCommandUniquePtr();
948     }
949
950     char *rawBuffer;
951
952     va_list args;
953     va_start(args, format);
954
955     if (vasprintf(&rawBuffer, format, args) == -1) {
956         rawBuffer = NULL;
957     }
958
959     va_end(args);
960
961     CharUniquePtr buffer(rawBuffer);
962
963     if (!buffer) {
964         LogError("Failed to allocate statement string");
965         return DataCommandUniquePtr();
966     }
967
968     LogPedantic("Executing SQL data command: " << buffer.get());
969
970     return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
971 }
972
973 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
974 {
975     return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
976 }
977
978 void SqlConnection::TurnOnForeignKeys()
979 {
980     ExecCommand("PRAGMA foreign_keys = ON;");
981 }
982
983 void SqlConnection::BeginTransaction()
984 {
985     ExecCommand("BEGIN;");
986 }
987
988 void SqlConnection::RollbackTransaction()
989 {
990     ExecCommand("ROLLBACK;");
991 }
992
993 void SqlConnection::CommitTransaction()
994 {
995     ExecCommand("COMMIT;");
996 }
997
998 SqlConnection::SynchronizationObject *
999 SqlConnection::AllocDefaultSynchronizationObject()
1000 {
1001     return new NaiveSynchronizationObject();
1002 }
1003 } // namespace DB
1004 } // namespace CKM
1005
1006 #pragma GCC diagnostic pop