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