Coding style applied according to style checker
[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()
42         {
43                 va_end(args);
44         }
45         va_list args;
46 };
47
48 #define scoped_va_start(name, param) ScopedVaList name; va_start(name.args, param);
49 }
50
51 namespace CKM {
52 namespace DB {
53 namespace { // anonymous
54 class ScopedNotifyAll {
55 private:
56         SqlConnection::SynchronizationObject *m_synchronizationObject;
57
58 public:
59         NONCOPYABLE(ScopedNotifyAll)
60
61         explicit ScopedNotifyAll(
62                 SqlConnection::SynchronizationObject *synchronizationObject) :
63                 m_synchronizationObject(synchronizationObject)
64         {
65         }
66
67         ~ScopedNotifyAll()
68         {
69                 if (!m_synchronizationObject)
70                         return;
71
72                 LogPedantic("Notifying after successful synchronize");
73                 m_synchronizationObject->NotifyAll();
74         }
75 };
76 } // namespace anonymous
77
78 SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
79                                                                                 const char *buffer) :
80         m_masterConnection(connection),
81         m_stmt(NULL)
82 {
83         Assert(connection != NULL);
84
85         // Notify all after potentially synchronized database connection access
86         ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
87
88         for (int i = 0; i < MAX_RETRY; i++) {
89                 int ret = sqlcipher3_prepare_v2(connection->m_connection,
90                                                                                 buffer, strlen(buffer),
91                                                                                 &m_stmt, NULL);
92
93                 if (ret == SQLCIPHER_OK) {
94                         LogPedantic("Prepared data command: " << buffer);
95
96                         // Increment stored data command count
97                         ++m_masterConnection->m_dataCommandsCount;
98                         return;
99                 } else if (ret == SQLCIPHER_BUSY) {
100                         LogPedantic("Collision occurred while preparing SQL command");
101
102                         // Synchronize if synchronization object is available
103                         if (connection->m_synchronizationObject) {
104                                 LogPedantic("Performing synchronization");
105                                 connection->m_synchronizationObject->Synchronize();
106                                 continue;
107                         }
108
109                         // No synchronization object defined. Fail.
110                 }
111
112                 // Fatal error
113                 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
114
115                 LogError("SQL prepare data command failed");
116                 LogError("    Statement: " << buffer);
117                 LogError("    Error: " << error);
118
119                 ThrowMsg(Exception::SyntaxError, error);
120         }
121
122         LogError("sqlite in the state of possible infinite loop");
123         ThrowMsg(Exception::InternalError, "sqlite permanently busy");
124 }
125
126 SqlConnection::DataCommand::~DataCommand()
127 {
128         LogPedantic("SQL data command finalizing");
129
130         if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK)
131                 LogError("Failed to finalize data command");
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 void SqlConnection::DataCommand::BindInt8(
272         SqlConnection::ArgumentIndex position,
273         const boost::optional<int8_t> &value)
274 {
275         if (!value)
276                 BindNull(position);
277         else
278                 BindInt8(position, *value);
279 }
280
281 void SqlConnection::DataCommand::BindInt16(
282         SqlConnection::ArgumentIndex position,
283         const boost::optional<int16_t> &value)
284 {
285         if (!value)
286                 BindNull(position);
287         else
288                 BindInt16(position, *value);
289 }
290
291 void SqlConnection::DataCommand::BindInt32(
292         SqlConnection::ArgumentIndex position,
293         const boost::optional<int32_t> &value)
294 {
295         if (!value)
296                 BindNull(position);
297         else
298                 BindInt32(position, *value);
299 }
300
301 void SqlConnection::DataCommand::BindInt64(
302         SqlConnection::ArgumentIndex position,
303         const boost::optional<int64_t> &value)
304 {
305         if (!value)
306                 BindNull(position);
307         else
308                 BindInt64(position, *value);
309 }
310
311 void SqlConnection::DataCommand::BindFloat(
312         SqlConnection::ArgumentIndex position,
313         const boost::optional<float> &value)
314 {
315         if (!value)
316                 BindNull(position);
317         else
318                 BindFloat(position, *value);
319 }
320
321 void SqlConnection::DataCommand::BindDouble(
322         SqlConnection::ArgumentIndex position,
323         const boost::optional<double> &value)
324 {
325         if (!value)
326                 BindNull(position);
327         else
328                 BindDouble(position, *value);
329 }
330
331 void SqlConnection::DataCommand::BindBlob(
332         SqlConnection::ArgumentIndex position,
333         const boost::optional<RawBuffer> &value)
334 {
335         if (!!value)
336                 BindBlob(position, *value);
337         else
338                 BindNull(position);
339 }
340
341 bool SqlConnection::DataCommand::Step()
342 {
343         // Notify all after potentially synchronized database connection access
344         ScopedNotifyAll notifyAll(
345                 m_masterConnection->m_synchronizationObject.get());
346
347         for (int i = 0; i < MAX_RETRY; i++) {
348                 int ret = sqlcipher3_step(m_stmt);
349
350                 if (ret == SQLCIPHER_ROW) {
351                         LogPedantic("SQL data command step ROW");
352                         return true;
353                 } else if (ret == SQLCIPHER_DONE) {
354                         LogPedantic("SQL data command step DONE");
355                         return false;
356                 } else if (ret == SQLCIPHER_BUSY) {
357                         LogPedantic("Collision occurred while executing SQL command");
358
359                         // Synchronize if synchronization object is available
360                         if (m_masterConnection->m_synchronizationObject) {
361                                 LogPedantic("Performing synchronization");
362
363                                 m_masterConnection->
364                                 m_synchronizationObject->Synchronize();
365
366                                 continue;
367                         }
368
369                         // No synchronization object defined. Fail.
370                 }
371
372                 // Fatal error
373                 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
374
375                 LogError("SQL step data command failed");
376                 LogError("    Error: " << error);
377
378                 ThrowMsg(Exception::InternalError, error);
379         }
380
381         LogError("sqlite in the state of possible infinite loop");
382         ThrowMsg(Exception::InternalError, "sqlite permanently busy");
383 }
384
385 void SqlConnection::DataCommand::Reset()
386 {
387         /*
388          * According to:
389          * http://www.sqllite.org/c3ref/stmt.html
390          *
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.
394          */
395         sqlcipher3_reset(m_stmt);
396
397         LogPedantic("SQL data command reset");
398 }
399
400 void SqlConnection::DataCommand::CheckColumnIndex(
401         SqlConnection::ColumnIndex column)
402 {
403         if (column < 0 || column >= sqlcipher3_column_count(m_stmt))
404                 ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
405 }
406
407 bool SqlConnection::DataCommand::IsColumnNull(
408         SqlConnection::ColumnIndex column)
409 {
410         LogPedantic("SQL data command get column type: [" << column << "]");
411         CheckColumnIndex(column);
412         return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
413 }
414
415 int SqlConnection::DataCommand::GetColumnInteger(
416         SqlConnection::ColumnIndex column)
417 {
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);
422         return value;
423 }
424
425 int8_t SqlConnection::DataCommand::GetColumnInt8(
426         SqlConnection::ColumnIndex column)
427 {
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);
432         return value;
433 }
434
435 int16_t SqlConnection::DataCommand::GetColumnInt16(
436         SqlConnection::ColumnIndex column)
437 {
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);
442         return value;
443 }
444
445 int32_t SqlConnection::DataCommand::GetColumnInt32(
446         SqlConnection::ColumnIndex column)
447 {
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);
452         return value;
453 }
454
455 int64_t SqlConnection::DataCommand::GetColumnInt64(
456         SqlConnection::ColumnIndex column)
457 {
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);
462         return value;
463 }
464
465 float SqlConnection::DataCommand::GetColumnFloat(
466         SqlConnection::ColumnIndex column)
467 {
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);
472         return value;
473 }
474
475 double SqlConnection::DataCommand::GetColumnDouble(
476         SqlConnection::ColumnIndex column)
477 {
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);
482         return value;
483 }
484
485 std::string SqlConnection::DataCommand::GetColumnString(
486         SqlConnection::ColumnIndex column)
487 {
488         LogPedantic("SQL data command get column string: [" << column << "]");
489         CheckColumnIndex(column);
490
491         const char *value = reinterpret_cast<const char *>(
492                                                         sqlcipher3_column_text(m_stmt, column));
493
494         LogPedantic("Value: " << (value ? value : "NULL"));
495
496         if (value == NULL)
497                 return std::string();
498
499         return std::string(value);
500 }
501
502 RawBuffer SqlConnection::DataCommand::GetColumnBlob(
503         SqlConnection::ColumnIndex column)
504 {
505         LogPedantic("SQL data command get column blog: [" << column << "]");
506         CheckColumnIndex(column);
507
508         const unsigned char *value = reinterpret_cast<const unsigned char *>(
509                                                                          sqlcipher3_column_blob(m_stmt, column));
510
511         if (value == NULL)
512                 return RawBuffer();
513
514         int length = sqlcipher3_column_bytes(m_stmt, column);
515         LogPedantic("Got blob of length: " << length);
516
517         return RawBuffer(value, value + length);
518 }
519
520 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
521         SqlConnection::ColumnIndex column)
522 {
523         LogPedantic("SQL data command get column optional integer: ["
524                                 << column << "]");
525         CheckColumnIndex(column);
526
527         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
528                 return boost::optional<int>();
529
530         int value = sqlcipher3_column_int(m_stmt, column);
531         LogPedantic("    Value: " << value);
532         return boost::optional<int>(value);
533 }
534
535 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
536         SqlConnection::ColumnIndex column)
537 {
538         LogPedantic("SQL data command get column optional int8: ["
539                                 << column << "]");
540         CheckColumnIndex(column);
541
542         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
543                 return boost::optional<int8_t>();
544
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);
548 }
549
550 boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
551         SqlConnection::ColumnIndex column)
552 {
553         LogPedantic("SQL data command get column optional int16: ["
554                                 << column << "]");
555         CheckColumnIndex(column);
556
557         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
558                 return boost::optional<int16_t>();
559
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);
563 }
564
565 boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
566         SqlConnection::ColumnIndex column)
567 {
568         LogPedantic("SQL data command get column optional int32: ["
569                                 << column << "]");
570         CheckColumnIndex(column);
571
572         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
573                 return boost::optional<int32_t>();
574
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);
578 }
579
580 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
581         SqlConnection::ColumnIndex column)
582 {
583         LogPedantic("SQL data command get column optional int64: ["
584                                 << column << "]");
585         CheckColumnIndex(column);
586
587         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
588                 return boost::optional<int64_t>();
589
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);
593 }
594
595 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
596         SqlConnection::ColumnIndex column)
597 {
598         LogPedantic("SQL data command get column optional float: ["
599                                 << column << "]");
600         CheckColumnIndex(column);
601
602         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
603                 return boost::optional<float>();
604
605         float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
606         LogPedantic("    Value: " << value);
607         return boost::optional<float>(value);
608 }
609
610 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
611         SqlConnection::ColumnIndex column)
612 {
613         LogPedantic("SQL data command get column optional double: ["
614                                 << column << "]");
615         CheckColumnIndex(column);
616
617         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
618                 return boost::optional<double>();
619
620         double value = sqlcipher3_column_double(m_stmt, column);
621         LogPedantic("    Value: " << value);
622         return boost::optional<double>(value);
623 }
624
625 boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
626         SqlConnection::ColumnIndex column)
627 {
628         LogPedantic("SQL data command get column blog: [" << column << "]");
629         CheckColumnIndex(column);
630
631         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
632                 return boost::optional<RawBuffer>();
633
634         const unsigned char *value = reinterpret_cast<const unsigned char *>(
635                                                                          sqlcipher3_column_blob(m_stmt, column));
636
637         int length = sqlcipher3_column_bytes(m_stmt, column);
638         LogPedantic("Got blob of length: " << length);
639
640         RawBuffer temp(value, value + length);
641         return boost::optional<RawBuffer>(temp);
642 }
643
644 void SqlConnection::Connect(const std::string &address,
645                                                         Flag::Option flag)
646 {
647         if (m_connection != NULL) {
648                 LogPedantic("Already connected.");
649                 return;
650         }
651
652         LogPedantic("Connecting to DB: " << address << "...");
653
654         // Connect to database
655         int result;
656         result = sqlcipher3_open_v2(
657                                  address.c_str(),
658                                  &m_connection,
659                                  flag,
660                                  NULL);
661
662         if (result == SQLCIPHER_OK) {
663                 LogPedantic("Connected to DB");
664         } else {
665                 LogError("Failed to connect to DB!");
666                 ThrowMsg(Exception::ConnectionBroken, address);
667         }
668
669         // Enable foreign keys
670         TurnOnForeignKeys();
671 }
672
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;
676
677 RawBuffer rawToHexString(const RawBuffer &raw)
678 {
679         RawBuffer output;
680
681         for (auto &e : raw) {
682                 char result[3];
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]));
686         }
687
688         return output;
689 }
690
691 RawBuffer createHexPass(const RawBuffer &rawPass)
692 {
693         // We are required to pass 64byte long hex password made out of 32byte raw
694         // binary data
695         RawBuffer output;
696         std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
697                           std::back_inserter(output));
698
699         RawBuffer password = rawToHexString(rawPass);
700
701         std::copy(password.begin(), password.end(),
702                           std::back_inserter(output));
703
704         std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
705                           std::back_inserter(output));
706
707         return output;
708 }
709
710 void SqlConnection::SetKey(const RawBuffer &rawPass)
711 {
712         if (m_connection == NULL) {
713                 LogPedantic("Cannot set key. No connection to DB!");
714                 return;
715         }
716
717         if (rawPass.size() != SQLCIPHER_RAW_DATA_SIZE)
718                 ThrowMsg(Exception::InvalidArguments,
719                                  "Binary data for raw password should be 32 bytes long.");
720
721         RawBuffer pass = createHexPass(rawPass);
722         int result = sqlcipher3_key(m_connection, pass.data(), pass.size());
723
724         if (result == SQLCIPHER_OK) {
725                 LogPedantic("Set key on DB");
726         } else {
727                 //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
728                 //                            key length == 0
729                 LogError("Failed to set key on DB");
730                 ThrowMsg(Exception::InvalidArguments, result);
731         }
732
733         m_isKeySet = true;
734 };
735
736 void SqlConnection::ResetKey(const RawBuffer &rawPassOld,
737                                                          const RawBuffer &rawPassNew)
738 {
739         if (m_connection == NULL) {
740                 LogPedantic("Cannot reset key. No connection to DB!");
741                 return;
742         }
743
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.");
747
748         // sqlcipher3_rekey requires for key to be already set
749         if (!m_isKeySet)
750                 SetKey(rawPassOld);
751
752         RawBuffer pass = createHexPass(rawPassNew);
753         int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
754
755         if (result == SQLCIPHER_OK) {
756                 LogPedantic("Reset key on DB");
757         } else {
758                 //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
759                 //                              key length == 0
760                 LogError("Failed to reset key on DB");
761                 ThrowMsg(Exception::InvalidArguments, result);
762         }
763 }
764
765 void SqlConnection::Disconnect()
766 {
767         if (m_connection == NULL) {
768                 LogPedantic("Already disconnected.");
769                 return;
770         }
771
772         LogPedantic("Disconnecting from DB...");
773
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");
778
779         int result;
780
781         result = sqlcipher3_close(m_connection);
782
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);
788         }
789
790         m_connection = NULL;
791
792         LogPedantic("Disconnected from DB");
793 }
794
795 bool SqlConnection::CheckTableExist(const char *tableName)
796 {
797         if (m_connection == NULL) {
798                 LogPedantic("Cannot execute command. Not connected to DB!");
799                 return false;
800         }
801
802         DataCommandUniquePtr command =
803                 PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
804
805         command->BindString(1, tableName);
806
807         if (!command->Step()) {
808                 LogPedantic("No matching records in table");
809                 return false;
810         }
811
812         return command->GetColumnString(0) == tableName;
813 }
814
815 SqlConnection::SqlConnection(const std::string &address,
816                                                          Flag::Option option,
817                                                          SynchronizationObject *synchronizationObject) :
818         m_connection(NULL),
819         m_dataCommandsCount(0),
820         m_synchronizationObject(synchronizationObject),
821         m_isKeySet(false)
822 {
823         LogPedantic("Opening database connection to: " << address);
824
825         // Connect to DB
826         SqlConnection::Connect(address, option);
827
828         if (!m_synchronizationObject)
829                 LogPedantic("No synchronization object defined");
830 }
831
832 SqlConnection::~SqlConnection()
833 {
834         LogPedantic("Closing database connection");
835
836         // Disconnect from DB
837         try {
838                 SqlConnection::Disconnect();
839         } catch (const Exception::Base &) {
840                 LogError("Failed to disconnect from database");
841         }
842 }
843
844 int SqlConnection::Output::Callback(void *param, int columns, char **values,
845                                                                         char **names)
846 {
847         if (param)
848                 static_cast<Output *>(param)->SetResults(columns, values, names);
849
850         return 0;
851 }
852
853 void SqlConnection::Output::SetResults(int columns, char **values, char **names)
854 {
855         if (m_names.empty()) {
856                 for (int i = 0; i < columns; i++)
857                         m_names.push_back(names[i] ? names[i] : "NULL");
858         }
859
860         Row row;
861
862         for (int i = 0; i < columns; i++)
863                 row.push_back(values[i] ? values[i] : "NULL");
864
865         m_values.push_back(std::move(row));
866 }
867
868 void SqlConnection::ExecCommandHelper(Output *out, const char *format,
869                                                                           va_list args)
870 {
871         if (m_connection == NULL) {
872                 LogError("Cannot execute command. Not connected to DB!");
873                 return;
874         }
875
876         if (format == NULL) {
877                 LogError("Null query!");
878                 ThrowMsg(Exception::SyntaxError, "Null statement");
879         }
880
881         char *query;
882
883         if (vasprintf(&query, format, args) == -1) {
884                 LogError("Failed to allocate statement string");
885                 return;
886         }
887
888         CharUniquePtr queryPtr(query);
889
890         LogPedantic("Executing SQL command: " << queryPtr.get());
891
892         // Notify all after potentially synchronized database connection access
893         ScopedNotifyAll notifyAll(m_synchronizationObject.get());
894
895         for (int i = 0; i < MAX_RETRY; i++) {
896                 char *errorBuffer;
897                 int ret = sqlcipher3_exec(m_connection,
898                                                                   queryPtr.get(),
899                                                                   out ? &Output::Callback : NULL,
900                                                                   out,
901                                                                   &errorBuffer);
902
903                 std::string errorMsg;
904
905                 // Take allocated error buffer
906                 if (errorBuffer != NULL) {
907                         errorMsg = errorBuffer;
908                         sqlcipher3_free(errorBuffer);
909                 }
910
911                 if (ret == SQLCIPHER_OK)
912                         return;
913
914                 if (ret == SQLCIPHER_BUSY) {
915                         LogPedantic("Collision occurred while executing SQL command");
916
917                         // Synchronize if synchronization object is available
918                         if (m_synchronizationObject) {
919                                 LogPedantic("Performing synchronization");
920                                 m_synchronizationObject->Synchronize();
921                                 continue;
922                         }
923
924                         // No synchronization object defined. Fail.
925                 }
926
927                 // Fatal error
928                 LogError("Failed to execute SQL command. Error: " << errorMsg);
929                 ThrowMsg(Exception::SyntaxError, errorMsg);
930         }
931
932         LogError("sqlite in the state of possible infinite loop");
933         ThrowMsg(Exception::InternalError, "sqlite permanently busy");
934 }
935
936 void SqlConnection::ExecCommand(Output *out, const char *format, ...)
937 {
938         scoped_va_start(svl, format);
939
940         ExecCommandHelper(out, format, svl.args);
941 }
942
943 void SqlConnection::ExecCommand(const char *format, ...)
944 {
945         scoped_va_start(svl, format);
946
947         ExecCommandHelper(NULL, format, svl.args);
948 }
949
950 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
951         const char *format,
952         ...)
953 {
954         if (m_connection == NULL) {
955                 LogError("Cannot execute data command. Not connected to DB!");
956                 return DataCommandUniquePtr();
957         }
958
959         char *rawBuffer;
960
961         va_list args;
962         va_start(args, format);
963
964         if (vasprintf(&rawBuffer, format, args) == -1)
965                 rawBuffer = NULL;
966
967         va_end(args);
968
969         CharUniquePtr buffer(rawBuffer);
970
971         if (!buffer) {
972                 LogError("Failed to allocate statement string");
973                 return DataCommandUniquePtr();
974         }
975
976         LogPedantic("Executing SQL data command: " << buffer.get());
977
978         return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
979 }
980
981 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
982 {
983         return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
984 }
985
986 void SqlConnection::TurnOnForeignKeys()
987 {
988         ExecCommand("PRAGMA foreign_keys = ON;");
989 }
990
991 void SqlConnection::BeginTransaction()
992 {
993         ExecCommand("BEGIN;");
994 }
995
996 void SqlConnection::RollbackTransaction()
997 {
998         ExecCommand("ROLLBACK;");
999 }
1000
1001 void SqlConnection::CommitTransaction()
1002 {
1003         ExecCommand("COMMIT;");
1004 }
1005
1006 SqlConnection::SynchronizationObject *
1007 SqlConnection::AllocDefaultSynchronizationObject()
1008 {
1009         return new NaiveSynchronizationObject();
1010 }
1011 } // namespace DB
1012 } // namespace CKM
1013
1014 #pragma GCC diagnostic pop