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