Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_mobile / 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;
608     if (type & Flag::UseLucene) {
609         result = db_util_open_with_options(
610                 address.c_str(),
611                 &m_connection,
612                 flag,
613                 NULL);
614
615         m_usingLucene = true;
616         LogPedantic("Lucene index enabled");
617     } else {
618         result = sqlite3_open_v2(
619                 address.c_str(),
620                 &m_connection,
621                 flag,
622                 NULL);
623
624         m_usingLucene = false;
625         LogPedantic("Lucene index disabled");
626     }
627
628     if (result == SQLITE_OK) {
629         LogPedantic("Connected to DB");
630     } else {
631         LogPedantic("Failed to connect to DB!");
632         ThrowMsg(Exception::ConnectionBroken, address);
633     }
634
635     // Enable foreign keys
636     TurnOnForeignKeys();
637 }
638
639 void SqlConnection::Disconnect()
640 {
641     if (m_connection == NULL) {
642         LogPedantic("Already disconnected.");
643         return;
644     }
645
646     LogPedantic("Disconnecting from DB...");
647
648     // All stored data commands must be deleted before disconnect
649     Assert(m_dataCommandsCount == 0 &&
650            "All stored procedures must be deleted"
651            " before disconnecting SqlConnection");
652
653     int result;
654
655     if (m_usingLucene) {
656         result = db_util_close(m_connection);
657     } else {
658         result = sqlite3_close(m_connection);
659     }
660
661     if (result != SQLITE_OK) {
662         const char *error = sqlite3_errmsg(m_connection);
663         LogPedantic("SQL close failed");
664         LogPedantic("    Error: " << error);
665         Throw(Exception::InternalError);
666     }
667
668     m_connection = NULL;
669
670     LogPedantic("Disconnected from DB");
671 }
672
673 bool SqlConnection::CheckTableExist(const char *tableName)
674 {
675     if (m_connection == NULL) {
676         LogPedantic("Cannot execute command. Not connected to DB!");
677         return false;
678     }
679
680     DataCommandAutoPtr command =
681         PrepareDataCommand("select tbl_name from sqlite_master where name=?;");
682
683     command->BindString(1, tableName);
684
685     if (!command->Step()) {
686         LogPedantic("No matching records in table");
687         return false;
688     }
689
690     return command->GetColumnString(0) == tableName;
691 }
692
693 SqlConnection::SqlConnection(const std::string &address,
694                              Flag::Type flag,
695                              Flag::Option option,
696                              SynchronizationObject *synchronizationObject) :
697     m_connection(NULL),
698     m_usingLucene(false),
699     m_dataCommandsCount(0),
700     m_synchronizationObject(synchronizationObject)
701 {
702     LogPedantic("Opening database connection to: " << address);
703
704     // Connect to DB
705     SqlConnection::Connect(address, flag, option);
706
707     if (!m_synchronizationObject) {
708         LogPedantic("No synchronization object defined");
709     }
710 }
711
712 SqlConnection::~SqlConnection()
713 {
714     LogPedantic("Closing database connection");
715
716     // Disconnect from DB
717     Try
718     {
719         SqlConnection::Disconnect();
720     }
721     Catch(Exception::Base)
722     {
723         LogPedantic("Failed to disconnect from database");
724     }
725 }
726
727 void SqlConnection::ExecCommand(const char *format, ...)
728 {
729     if (m_connection == NULL) {
730         LogPedantic("Cannot execute command. Not connected to DB!");
731         return;
732     }
733
734     if (format == NULL) {
735         LogPedantic("Null query!");
736         ThrowMsg(Exception::SyntaxError, "Null statement");
737     }
738
739     char *rawBuffer;
740
741     va_list args;
742     va_start(args, format);
743
744     if (vasprintf(&rawBuffer, format, args) == -1) {
745         rawBuffer = NULL;
746     }
747
748     va_end(args);
749
750     ScopedFree<char> buffer(rawBuffer);
751
752     if (!buffer) {
753         LogPedantic("Failed to allocate statement string");
754         return;
755     }
756
757     LogPedantic("Executing SQL command: " << buffer.Get());
758
759     // Notify all after potentially synchronized database connection access
760     ScopedNotifyAll notifyAll(m_synchronizationObject.get());
761
762     for (;;) {
763         char *errorBuffer;
764
765         int ret = sqlite3_exec(m_connection,
766                                buffer.Get(),
767                                NULL,
768                                NULL,
769                                &errorBuffer);
770
771         std::string errorMsg;
772
773         // Take allocated error buffer
774         if (errorBuffer != NULL) {
775             errorMsg = errorBuffer;
776             sqlite3_free(errorBuffer);
777         }
778
779         if (ret == SQLITE_OK) {
780             return;
781         }
782
783         if (ret == SQLITE_BUSY) {
784             LogPedantic("Collision occurred while executing SQL command");
785
786             // Synchronize if synchronization object is available
787             if (m_synchronizationObject) {
788                 LogPedantic("Performing synchronization");
789                 m_synchronizationObject->Synchronize();
790                 continue;
791             }
792
793             // No synchronization object defined. Fail.
794         }
795
796         // Fatal error
797         LogPedantic("Failed to execute SQL command. Error: " << errorMsg);
798         ThrowMsg(Exception::SyntaxError, errorMsg);
799     }
800 }
801
802 SqlConnection::DataCommandAutoPtr SqlConnection::PrepareDataCommand(
803     const char *format,
804     ...)
805 {
806     if (m_connection == NULL) {
807         LogPedantic("Cannot execute data command. Not connected to DB!");
808         return DataCommandAutoPtr();
809     }
810
811     char *rawBuffer;
812
813     va_list args;
814     va_start(args, format);
815
816     if (vasprintf(&rawBuffer, format, args) == -1) {
817         rawBuffer = NULL;
818     }
819
820     va_end(args);
821
822     ScopedFree<char> buffer(rawBuffer);
823
824     if (!buffer) {
825         LogPedantic("Failed to allocate statement string");
826         return DataCommandAutoPtr();
827     }
828
829     LogPedantic("Executing SQL data command: " << buffer.Get());
830
831     return DataCommandAutoPtr(new DataCommand(this, buffer.Get()));
832 }
833
834 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
835 {
836     return static_cast<RowID>(sqlite3_last_insert_rowid(m_connection));
837 }
838
839 void SqlConnection::TurnOnForeignKeys()
840 {
841     ExecCommand("PRAGMA foreign_keys = ON;");
842 }
843
844 SqlConnection::SynchronizationObject *
845 SqlConnection::AllocDefaultSynchronizationObject()
846 {
847     return new NaiveSynchronizationObject();
848 }
849 } // namespace DB
850 } // namespace DPL