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