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