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