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