gsignond first release 0.0.1
[profile/ivi/gsignond.git] / src / common / db / gsignond-db-sql-database.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gsignond
5  *
6  * Copyright (C) 2012 Intel Corporation.
7  *
8  * Contact: Imran Zaman <imran.zaman@linux.intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include <sys/stat.h>
27
28 #include <glib/gstdio.h>
29
30 #include "gsignond/gsignond-log.h"
31 #include "gsignond-db-error.h"
32 #include "gsignond-db-sql-database.h"
33 #include "gsignond-db-sql-database-private.h"
34 #include "config.h"
35
36 #define GSIGNOND_DB_SQL_DATABASE_GET_PRIVATE(obj) \
37                                           (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
38                                            GSIGNOND_DB_TYPE_SQL_DATABASE, \
39                                            GSignondDbSqlDatabasePrivate))
40
41 G_DEFINE_TYPE (GSignondDbSqlDatabase, gsignond_db_sql_database, G_TYPE_OBJECT);
42
43
44 static void
45 _gsignond_db_sql_database_finalize_db (GSignondDbSqlDatabase *self)
46 {
47     if (self->priv->begin_statement) {
48         sqlite3_finalize (self->priv->begin_statement);
49         self->priv->begin_statement = NULL;
50     }
51
52     if (self->priv->commit_statement) {
53         sqlite3_finalize (self->priv->commit_statement);
54         self->priv->commit_statement = NULL;
55     }
56
57     if (self->priv->rollback_statement) {
58         sqlite3_finalize (self->priv->rollback_statement);
59         self->priv->rollback_statement = NULL;
60     }
61 }
62
63 gboolean
64 _gsignond_db_sql_database_is_open (GSignondDbSqlDatabase *self)
65 {
66     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
67     return self->priv->db != NULL;
68 }
69
70 #ifdef ENABLE_SQL_LOG
71 void trace_callback (void *s, const char *stmt)
72 {
73     if (stmt) {
74         DBG ("SQLITE TRACE: %s", stmt);
75     }
76 }
77 #endif
78
79 gboolean
80 _gsignond_db_sql_database_open (
81         GSignondDbSqlDatabase *self,
82         const gchar *filename,
83         int flags)
84 {
85     int ret;
86
87     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
88     g_return_val_if_fail (filename != NULL, FALSE);
89
90     if (_gsignond_db_sql_database_is_open (self)) {
91         return TRUE;
92     }
93
94     ret = sqlite3_open_v2 (filename, &self->priv->db, flags, NULL);
95     if (ret != SQLITE_OK) {
96         if (self->priv->db) {
97             DBG ("Cannot open %s DB: %s", filename,
98                     sqlite3_errmsg (self->priv->db));
99         }
100         gsignond_db_sql_database_update_error_from_db(self);
101         GSIGNOND_DB_SQL_DATABASE_GET_CLASS (self)->close (self);
102         return FALSE;
103     }
104     if (flags & SQLITE_OPEN_CREATE) {
105         if (g_chmod (filename, S_IRUSR | S_IWUSR))
106             WARN ("setting file permissions on %s failed", filename);
107     }
108
109 #ifdef ENABLE_SQL_LOG
110     sqlite3_trace (self->priv->db, trace_callback, NULL);
111 #endif
112
113     if (!GSIGNOND_DB_SQL_DATABASE_GET_CLASS (self)->create (self)) {
114         GSIGNOND_DB_SQL_DATABASE_GET_CLASS (self)->close (self);
115         return FALSE;
116     }
117     return TRUE;
118 }
119
120 gboolean
121 _gsignond_db_sql_database_close (GSignondDbSqlDatabase *self)
122 {
123     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
124     g_return_val_if_fail (self->priv->db != NULL, FALSE);
125
126     _gsignond_db_sql_database_finalize_db (self);
127
128     if (sqlite3_close (self->priv->db) != SQLITE_OK) {
129         DBG ("Unable to close db: %s", sqlite3_errmsg (self->priv->db));
130         gsignond_db_sql_database_update_error_from_db(self);
131     }
132     self->priv->db = NULL;
133     self->priv->db_version = 0;
134
135     return TRUE;
136 }
137
138 static int
139 _prepare_transaction_statement (
140         GSignondDbSqlDatabase *self,
141         sqlite3_stmt **sql_stmt,
142         const gchar *statement)
143 {
144     int ret = SQLITE_OK;
145
146     if (G_UNLIKELY (!*sql_stmt)) {
147         ret = sqlite3_prepare_v2 (self->priv->db, statement, -1,
148                                   sql_stmt, NULL);
149     } else {
150         sqlite3_reset (*sql_stmt);
151     }
152
153     return ret;
154 }
155
156 static void
157 _gsignond_db_sql_database_finalize (GObject *gobject)
158 {
159     GSignondDbSqlDatabase *self = GSIGNOND_DB_SQL_DATABASE (gobject);
160
161     _gsignond_db_sql_database_finalize_db (self);
162
163     if (self->priv->db) {
164         sqlite3_close (self->priv->db);
165         self->priv->db = NULL;
166     }
167
168     if (self->priv->last_error) {
169         g_error_free (self->priv->last_error);
170         self->priv->last_error = NULL;
171     }
172
173     /* Chain up to the parent class */
174     G_OBJECT_CLASS (gsignond_db_sql_database_parent_class)->finalize (gobject);
175 }
176
177 static void
178 gsignond_db_sql_database_class_init (GSignondDbSqlDatabaseClass *klass)
179 {
180     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
181
182     gobject_class->finalize = _gsignond_db_sql_database_finalize;
183
184     /* pure virtual methods */
185     klass->create = NULL;
186     klass->clear = NULL;
187
188     /* virtual methods */
189     klass->open = _gsignond_db_sql_database_open;
190     klass->close = _gsignond_db_sql_database_close;
191     klass->is_open = _gsignond_db_sql_database_is_open;
192
193     g_type_class_add_private (klass, sizeof (GSignondDbSqlDatabasePrivate));
194 }
195
196 static void
197 gsignond_db_sql_database_init (GSignondDbSqlDatabase *self)
198 {
199     self->priv = GSIGNOND_DB_SQL_DATABASE_GET_PRIVATE (self);
200     self->priv->last_error = NULL;
201     self->priv->db = NULL;
202     self->priv->db_version = 0;
203 }
204
205 void
206 gsignond_db_sql_database_update_error_from_db (GSignondDbSqlDatabase *self)
207 {
208     GSignondDbError code;
209     GError *error;
210     int sql_code;
211
212     g_return_if_fail (self->priv != NULL);
213
214     sql_code = sqlite3_errcode (self->priv->db);
215
216     switch (sql_code)
217     {
218     case SQLITE_OK:
219     case SQLITE_DONE:
220         gsignond_db_sql_database_set_last_error (self, NULL);
221         return;
222     case SQLITE_BUSY:
223         code = GSIGNOND_DB_ERROR_LOCKED;
224         break;
225     default:
226         code = GSIGNOND_DB_ERROR_UNKNOWN;
227         break;
228     }
229
230     error = g_error_new (GSIGNOND_DB_ERROR,
231                          code,
232                          "Database (SQLite) error %d: %s",
233                          sqlite3_errcode (self->priv->db),
234                          sqlite3_errmsg (self->priv->db));
235     gsignond_db_sql_database_set_last_error (self, error);
236 }
237
238 int
239 gsignond_db_sql_database_prepare_transaction_statements (
240         GSignondDbSqlDatabase *self)
241 {
242     int ret;
243
244     g_return_val_if_fail (self->priv != NULL, FALSE);
245
246     ret = _prepare_transaction_statement(self, &(self->priv->begin_statement),
247             "BEGIN EXCLUSIVE;");
248     if (ret != SQLITE_OK) return ret;
249
250     ret = _prepare_transaction_statement(self, &(self->priv->commit_statement),
251             "COMMIT;");
252     if (ret != SQLITE_OK) return ret;
253
254     ret = _prepare_transaction_statement(self,&(self->priv->rollback_statement),
255             "ROLLBACK;");
256
257     return ret;
258 }
259
260 /**
261  * gsignond_db_sql_database_open:
262  *
263  * @self: instance of #GSignondDbSqlDatabase
264  * @filename: db filename
265  * @flags: sqlite3_open_v2 flags for opening db
266  *
267  * Opens a connection to DB.
268  *
269  * Returns: TRUE if successful, FALSE otherwise.
270  */
271 gboolean
272 gsignond_db_sql_database_open (
273         GSignondDbSqlDatabase *self,
274         const gchar *filename,
275         int flags)
276 {
277     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
278
279     return GSIGNOND_DB_SQL_DATABASE_GET_CLASS (self)->open (
280             self, filename, flags);
281 }
282
283 /**
284  * gsignond_db_sql_database_close:
285  *
286  * @self: instance of #GSignondDbSqlDatabase
287  *
288  * Closes the connection to DB if it is opened already.
289  *
290  * Returns: TRUE if successful, FALSE otherwise.
291  */
292 gboolean
293 gsignond_db_sql_database_close (GSignondDbSqlDatabase *self)
294 {
295     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
296
297     return GSIGNOND_DB_SQL_DATABASE_GET_CLASS (self)->close (self);
298 }
299
300 /**
301  * gsignond_db_sql_database_is_open:
302  *
303  * @self: instance of #GSignondDbSqlDatabase
304  *
305  * Retrieves the connectivity status to database if it is open or not.
306  *
307  * Returns: TRUE if there exist a valid connection to database,
308  * FALSE otherwise.
309  */
310 gboolean
311 gsignond_db_sql_database_is_open (GSignondDbSqlDatabase *self)
312 {
313     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
314
315     return GSIGNOND_DB_SQL_DATABASE_GET_CLASS (self)->is_open (self);
316 }
317
318 /**
319  * gsignond_db_sql_database_create:
320  *
321  * @self: instance of #GSignondDbSqlDatabase
322  *
323  * Creates database structure/tables if does not already exist.
324  *
325  * Returns: TRUE if successful, FALSE otherwise.
326  */
327 gboolean
328 gsignond_db_sql_database_create (GSignondDbSqlDatabase *self)
329 {
330     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
331
332     return GSIGNOND_DB_SQL_DATABASE_GET_CLASS (self)->create (self);
333 }
334
335 /**
336  * gsignond_db_sql_database_clear:
337  *
338  * @self: instance of #GSignondDbSqlDatabase
339  *
340  * Clear database data as per needed.
341  *
342  * Returns: TRUE if successful, FALSE otherwise.
343  */
344 gboolean
345 gsignond_db_sql_database_clear (GSignondDbSqlDatabase *self)
346 {
347     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
348
349     return GSIGNOND_DB_SQL_DATABASE_GET_CLASS (self)->clear (self);
350 }
351
352 /**
353  * gsignond_db_sql_database_prepare_statement:
354  * @self: instance of #GSignondDbSqlDatabase
355  * @query: query to be prepared
356  *
357  * Prepares the statement from the query.
358  *
359  * Returns: (transfer full) NULL if fails, valid sql statement otherwise.
360  */
361 sqlite3_stmt *
362 gsignond_db_sql_database_prepare_statement (
363         GSignondDbSqlDatabase *self,
364         const gchar *query)
365 {
366     int ret;
367     sqlite3_stmt *sql_stmt = NULL;
368
369     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
370     g_return_val_if_fail (self->priv->db != NULL, 0);
371
372     ret = sqlite3_prepare_v2 (self->priv->db, query, -1, &sql_stmt, NULL);
373     if (ret != SQLITE_OK) {
374         DBG ("statement preparation failed for \"%s\": %s",
375                 query, sqlite3_errmsg (self->priv->db));
376         return NULL;
377     }
378
379     return sql_stmt;
380 }
381
382 /**
383  * gsignond_db_sql_database_exec:
384  * @self: instance of #GSignondDbSqlDatabase
385  * @stmts: sql statements to be executed on the database
386  *
387  * Executes SQL statements. transaction begin and commit statements should be
388  * explicitly called if needed.
389  *
390  * Returns: TRUE if the sql statements executes successfully,
391  * FALSE otherwise.
392  */
393 gboolean
394 gsignond_db_sql_database_exec (
395         GSignondDbSqlDatabase *self,
396         const gchar *statements)
397 {
398     int ret;
399
400     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
401     g_return_val_if_fail (self->priv->db != NULL, FALSE);
402     g_return_val_if_fail (statements != NULL, FALSE);
403
404     /* exec statements */
405     ret = sqlite3_exec (self->priv->db, statements, NULL, NULL, NULL);
406     if (G_UNLIKELY (ret != SQLITE_OK)) {
407         gsignond_db_sql_database_update_error_from_db (self);
408         return FALSE;
409     }
410
411     return TRUE;
412 }
413
414 /**
415  * gsignond_db_sql_database_query_exec:
416  * @self: instance of #GSignondDbSqlDatabase
417  * @query: query to be executed on the database
418  * @callback: callback to be invoked if not NULL for the result of each row
419  * @userdata: user_data to be relayed back through the callback
420  *
421  * Executes an SQL statement, and optionally calls
422  * the callback for every row of the result.
423  * Returns the number of rows fetched.
424  *
425  * Returns: 0 if no row is fetched, number of rows fetched otherwise.
426  */
427 gint
428 gsignond_db_sql_database_query_exec (
429         GSignondDbSqlDatabase *self,
430         const gchar *query,
431         GSignondDbSqlDatabaseQueryCallback callback,
432         gpointer userdata)
433 {
434     sqlite3_stmt *sql_stmt;
435     gint rows = 0;
436
437     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
438     g_return_val_if_fail (self->priv->db != NULL, 0);
439
440     sql_stmt = gsignond_db_sql_database_prepare_statement(self, query);
441     if (sql_stmt) {
442         rows = gsignond_db_sql_database_query_exec_stmt(self, sql_stmt,
443                 callback, userdata);
444     }
445
446     return rows;
447 }
448
449 static gboolean
450 _gsignond_db_read_string (
451         sqlite3_stmt *stmt,
452         gchar **string)
453 {
454     *string = g_strdup ((const gchar *)sqlite3_column_text (stmt, 0));
455     return TRUE;
456 }
457
458 /**
459  * gsignond_db_sql_database_query_exec_string:
460  * @self: instance of #GSignondDbSqlDatabase
461  * @query: query to be executed on the database
462  *
463  * Executes an SQL statement, and returns the fetched integer from the result.
464  *
465  * Returns: (transfer full) string if rows fetched are greater than 0,
466  * NULL otherwise.
467  */
468 gchar *
469 gsignond_db_sql_database_query_exec_string (
470         GSignondDbSqlDatabase *self,
471         const gchar *query)
472 {
473     gchar *str = NULL;
474     gint rows = 0;
475
476     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
477     g_return_val_if_fail (self->priv->db != NULL, 0);
478
479     rows = gsignond_db_sql_database_query_exec (GSIGNOND_DB_SQL_DATABASE (self),
480             query,
481             (GSignondDbSqlDatabaseQueryCallback)
482             _gsignond_db_read_string,
483             &str);
484
485     if (G_UNLIKELY (rows <= 0)) {
486         g_free (str);
487         str = NULL;
488     }
489     return str;
490 }
491
492 static gboolean
493 _gsignond_db_read_strings (
494         sqlite3_stmt *stmt,
495         GList** strings)
496 {
497     *strings = g_list_append (*strings,
498             g_strdup ((const gchar *)sqlite3_column_text (stmt, 0)));
499     return TRUE;
500 }
501
502 /**
503  * gsignond_db_sql_database_query_exec_string_list:
504  * @self: instance of #GSignondDbSqlDatabase
505  * @query: query to be executed on the database
506  *
507  * Executes an SQL statement, and returns the fetched strings from the results
508  * in the list.
509  *
510  * Returns: (transfer full) list if rows fetched are greater than 0,
511  * NULL otherwise. When done with list, it must be freed using
512  * g_list_free_full (list, g_free)
513  */
514 GList *
515 gsignond_db_sql_database_query_exec_string_list (
516         GSignondDbSqlDatabase *self,
517         const gchar *query)
518 {
519     GList *list = NULL;
520     gint rows = 0;
521
522     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
523     g_return_val_if_fail (self->priv->db != NULL, 0);
524
525     rows = gsignond_db_sql_database_query_exec (GSIGNOND_DB_SQL_DATABASE (self),
526             query,
527             (GSignondDbSqlDatabaseQueryCallback)
528             _gsignond_db_read_strings,
529             &list);
530
531     if (G_UNLIKELY (rows <= 0)) {
532         g_list_free_full (list, g_free);
533         list = NULL;
534     }
535     return list;
536 }
537
538 static gboolean
539 _gsignond_db_read_string_tuple (
540         sqlite3_stmt *stmt,
541         GHashTable *tuples)
542 {
543     g_hash_table_insert(tuples,
544             g_strdup ((const gchar *)sqlite3_column_text (stmt, 0)),
545             g_strdup ((const gchar *)sqlite3_column_text (stmt, 1)));
546     return TRUE;
547 }
548
549 /**
550  * gsignond_db_sql_database_query_exec_string_tuple:
551  * @self: instance of #GSignondDbSqlDatabase
552  * @query: query to be executed on the database
553  *
554  * Executes an SQL statement, and returns the fetched string tuples from
555  * the results into the hash table.
556  *
557  * Returns: (transfer full) string tuples if rows fetched are greater than 0,
558  * NULL otherwise. When done with tuples, it must be freed using
559  * g_hash_table_unref (tuples)
560  */
561 GHashTable *
562 gsignond_db_sql_database_query_exec_string_tuple (
563         GSignondDbSqlDatabase *self,
564         const gchar *query)
565 {
566     GHashTable *tuples = NULL;
567     gint rows = 0;
568
569     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
570     g_return_val_if_fail (self->priv->db != NULL, 0);
571
572     tuples = g_hash_table_new_full ((GHashFunc)g_str_hash,
573                                     (GEqualFunc)g_str_equal,
574                                     (GDestroyNotify)g_free,
575                                     (GDestroyNotify)g_free);
576
577     rows = gsignond_db_sql_database_query_exec (GSIGNOND_DB_SQL_DATABASE (self),
578             query,
579             (GSignondDbSqlDatabaseQueryCallback)
580             _gsignond_db_read_string_tuple,
581             tuples);
582
583     if (G_UNLIKELY (rows <= 0)) {
584         g_hash_table_destroy (tuples);
585         tuples = NULL;
586     }
587     return tuples;
588 }
589
590 static gboolean
591 _gsignond_db_read_int_string_tuple (
592         sqlite3_stmt *stmt,
593         GHashTable *tuples)
594 {
595     gint id;
596     const gchar *method = NULL;
597
598     id = sqlite3_column_int (stmt, 0);
599     method = (const gchar *)sqlite3_column_text (stmt, 1);
600     g_hash_table_insert(tuples, GINT_TO_POINTER(id), g_strdup (method));
601     return TRUE;
602 }
603
604 /**
605  * gsignond_db_sql_database_query_exec_int_string_tuple:
606  * @self: instance of #GSignondDbSqlDatabase
607  * @query: query to be executed on the database
608  *
609  * Executes an SQL statement, and returns the fetched int-string tuples from
610  * the results into the hash table.
611  *
612  * Returns: (transfer full) string tuples if rows fetched are greater than 0,
613  * NULL otherwise.
614  */
615 GHashTable *
616 gsignond_db_sql_database_query_exec_int_string_tuple (
617         GSignondDbSqlDatabase *self,
618         const gchar *query)
619 {
620     GHashTable *tuples = NULL;
621     gint rows = 0;
622
623     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
624     g_return_val_if_fail (self->priv->db != NULL, 0);
625
626     tuples = g_hash_table_new_full ((GHashFunc)g_direct_hash,
627                                     (GEqualFunc)g_direct_equal,
628                                     (GDestroyNotify)NULL,
629                                     (GDestroyNotify)g_free);
630
631     rows = gsignond_db_sql_database_query_exec (GSIGNOND_DB_SQL_DATABASE (self),
632             query,
633             (GSignondDbSqlDatabaseQueryCallback)
634             _gsignond_db_read_int_string_tuple,
635             tuples);
636
637     if (G_UNLIKELY (rows <= 0)) {
638         g_hash_table_destroy (tuples);
639         tuples = NULL;
640     }
641     return tuples;
642 }
643
644 static gboolean
645 _gsignond_db_read_int (
646         sqlite3_stmt *stmt,
647         gint *data)
648 {
649     *data = sqlite3_column_int (stmt, 0);
650     return TRUE;
651 }
652
653 /**
654  * gsignond_db_sql_database_query_exec_int:
655  * @self: instance of #GSignondDbSqlDatabase
656  * @query: query to be executed on the database
657  *
658  * Executes an SQL statement, and returns the fetched integer from the result.
659  *
660  * Returns: TRUE if successful, FALSE otherwise.
661  */
662 gboolean
663 gsignond_db_sql_database_query_exec_int (
664         GSignondDbSqlDatabase *self,
665         const gchar *query,
666         gint *result)
667 {
668     gint data;
669     gint rows = 0;
670
671     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
672     g_return_val_if_fail (self->priv->db != NULL, 0);
673
674     rows = gsignond_db_sql_database_query_exec (GSIGNOND_DB_SQL_DATABASE (self),
675             query,
676             (GSignondDbSqlDatabaseQueryCallback)
677             _gsignond_db_read_int,
678             &data);
679     if (G_UNLIKELY (rows <= 0)) {
680         return FALSE;
681     }
682     *result = data;
683     return TRUE;
684 }
685
686 static gboolean
687 _gsignond_db_read_array (
688         sqlite3_stmt *stmt,
689         GArray *array)
690 {
691     int item = 0;
692     item = sqlite3_column_int (stmt, 0);
693     g_array_append_val (array, item);
694     return TRUE;
695 }
696
697 /**
698  * gsignond_db_sql_database_query_exec_int_array:
699  * @self: instance of #GSignondDbSqlDatabase
700  * @query: query to be executed on the database
701  *
702  * Executes an SQL statement, and returns the fetched integers from the results
703  * in the array.
704  *
705  * Returns: (transfer full) list if rows fetched are greater than 0, NULL otherwise.
706  */
707 GArray *
708 gsignond_db_sql_database_query_exec_int_array (
709         GSignondDbSqlDatabase *self,
710         const gchar *query)
711 {
712     GArray *array = NULL;
713     gint rows = 0;
714
715     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
716     g_return_val_if_fail (self->priv->db != NULL, 0);
717
718     array = g_array_new (FALSE, FALSE, sizeof(gint));
719     rows = gsignond_db_sql_database_query_exec (GSIGNOND_DB_SQL_DATABASE (self),
720             query,
721             (GSignondDbSqlDatabaseQueryCallback)
722             _gsignond_db_read_array,
723             array);
724
725     if (G_UNLIKELY (rows <= 0)) {
726         g_array_free (array, TRUE);
727         array = NULL;
728     }
729     return array;
730 }
731
732 /**
733  * gsignond_db_sql_database_query_exec_stmt:
734  * @self: instance of #GSignondDbSqlDatabase
735  * @sql_stmt: (transfer full) sql statement executed on the database
736  * @callback: callback to be invoked if not NULL for the result of each row
737  * @userdata: user_data to be relayed back through the callback
738  *
739  * Executes an SQL statement, and optionally calls
740  * the callback for every row of the result.
741  * Returns the number of rows fetched.
742  *
743  * Returns: 0 if no row is fetched, number of rows fetched otherwise.
744  */
745 gint
746 gsignond_db_sql_database_query_exec_stmt (
747         GSignondDbSqlDatabase *self,
748         sqlite3_stmt *sql_stmt,
749         GSignondDbSqlDatabaseQueryCallback callback,
750         gpointer userdata)
751 {
752     int ret;
753     gint rows = 0;
754
755     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
756     g_return_val_if_fail (self->priv->db != NULL, 0);
757
758     do {
759         ret = sqlite3_step (sql_stmt);
760         if (ret == SQLITE_ROW) {
761             if (callback && !callback (sql_stmt, userdata))  {
762                 /* stop if callback return FALSE */
763                 break;
764             }
765             rows++;
766         } else if (ret != SQLITE_DONE) {
767             gsignond_db_sql_database_update_error_from_db (self);
768             DBG ("error executing query : %s", sqlite3_errmsg (self->priv->db));
769             break;
770         }
771
772     } while (ret != SQLITE_DONE);
773
774     sqlite3_finalize (sql_stmt);
775
776     return rows;
777 }
778
779 /**
780  * gsignond_db_sql_database_start_transaction:
781  * @self: instance of #GSignondDbSqlDatabase
782  *
783  * Starts a transaction.
784  *
785  * Returns: TRUE if the transaction starts successfully,
786  * FALSE otherwise.
787  */
788 gboolean
789 gsignond_db_sql_database_start_transaction (GSignondDbSqlDatabase *self)
790 {
791     int ret;
792
793     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
794     g_return_val_if_fail (self->priv->db != NULL, FALSE);
795
796     /* prepare transaction begin, commit and rollback statements */
797     ret = gsignond_db_sql_database_prepare_transaction_statements (self);
798     if (G_UNLIKELY (ret != SQLITE_OK)) {
799         DBG ("Prepare statement failed");
800         gsignond_db_sql_database_update_error_from_db (self);
801         return FALSE;
802     }
803
804     /* begin statement */
805     ret = sqlite3_step (self->priv->begin_statement);
806     if (G_UNLIKELY (ret != SQLITE_DONE)) {
807         DBG ("Begin statement failed");
808         gsignond_db_sql_database_update_error_from_db (self);
809         return FALSE;
810     }
811     return TRUE;
812 }
813
814 /**
815  * gsignond_db_sql_database_commit_transaction:
816  * @self: instance of #GSignondDbSqlDatabase
817  *
818  * Runs commit statement.
819  *
820  * Returns: TRUE if the transaction is committed successfully,
821  * FALSE otherwise.
822  */
823 gboolean
824 gsignond_db_sql_database_commit_transaction (GSignondDbSqlDatabase *self)
825 {
826     int ret;
827
828     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
829     g_return_val_if_fail (self->priv->db != NULL, FALSE);
830
831     ret = sqlite3_step (self->priv->commit_statement);
832     if (G_UNLIKELY (ret != SQLITE_DONE)) {
833         DBG ("Commit statement failed");
834         gsignond_db_sql_database_update_error_from_db (self);
835         sqlite3_reset (self->priv->commit_statement);
836         return FALSE;
837     }
838     sqlite3_reset (self->priv->commit_statement);
839
840     return TRUE;
841 }
842
843 /**
844  * gsignond_db_sql_database_rollback_transaction:
845  * @self: instance of #GSignondDbSqlDatabase
846  *
847  * Runs rollback statement.
848  *
849  * Returns: TRUE if the transaction rolls back successfully,
850  * FALSE otherwise.
851  */
852 gboolean
853 gsignond_db_sql_database_rollback_transaction (GSignondDbSqlDatabase *self)
854 {
855     int ret;
856
857     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
858     g_return_val_if_fail (self->priv->db != NULL, FALSE);
859
860     ret = sqlite3_step (self->priv->rollback_statement);
861     if (G_UNLIKELY (ret != SQLITE_DONE)) {
862         DBG ("Rollback statement failed");
863         gsignond_db_sql_database_update_error_from_db (self);
864         sqlite3_reset (self->priv->rollback_statement);
865         return FALSE;
866     }
867     sqlite3_reset (self->priv->rollback_statement);
868     return TRUE;
869 }
870
871 /**
872  * gsignond_db_sql_database_transaction_exec:
873  * @self: instance of #GSignondDbSqlDatabase
874  * @stmts: sql statements to be executed on the database
875  *
876  * Executes SQL statements starting with begin statement, and ending with
877  * commit statement. In case of any failures, statements are rolledback.
878  *
879  * Returns: TRUE if the sql statements executes successfully,
880  * FALSE otherwise.
881  */
882 gboolean
883 gsignond_db_sql_database_transaction_exec (
884         GSignondDbSqlDatabase *self,
885         const gchar *statements)
886 {
887     int ret;
888
889     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), FALSE);
890     g_return_val_if_fail (self->priv->db != NULL, FALSE);
891
892     if (!gsignond_db_sql_database_start_transaction (self)) {
893         return FALSE;
894     }
895
896     /* exec statements */
897     ret = sqlite3_exec (self->priv->db, statements, NULL, NULL, NULL);
898     if (G_UNLIKELY (ret != SQLITE_OK)) {
899         gsignond_db_sql_database_update_error_from_db (self);
900         gsignond_db_sql_database_rollback_transaction (self);
901         return FALSE;
902     }
903
904     return gsignond_db_sql_database_commit_transaction (self);
905 }
906
907 /**
908  * gsignond_db_sql_database_get_db_version:
909  * @self: instance of #GSignondDbDefaultStorage
910  * @query: query to be executed on db to get version
911  * e.g. PRAGMA db_version;
912  *
913  * reads the database version from db
914  *
915  */
916 gint
917 gsignond_db_sql_database_get_db_version (
918         GSignondDbSqlDatabase *self,
919         const gchar *query)
920 {
921     int ret;
922     sqlite3_stmt *sql_stmt;
923     gint db_version = 0;
924
925     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), 0);
926     g_return_val_if_fail (self->priv->db != NULL, 0);
927
928     if (self->priv->db_version > 0) {
929         return self->priv->db_version;
930     }
931
932     ret = sqlite3_prepare_v2 (self->priv->db, query, -1, &sql_stmt, NULL);
933
934     if (ret == SQLITE_OK) {
935         ret = sqlite3_step(sql_stmt);
936         if (ret == SQLITE_ROW || ret == SQLITE_DONE) {
937             db_version = sqlite3_column_int(sql_stmt, 0);
938             DBG ("database version %d", db_version);
939             self->priv->db_version = db_version;
940         }
941         sqlite3_finalize(sql_stmt);
942     }
943
944     return db_version;
945 }
946
947 /**
948  * gsignond_db_sql_database_set_last_error:
949  * @self: instance of #GSignondDbDefaultStorage
950  * @error: (transfer full) last occurred #GError
951  *
952  * sets the last occurred error
953  *
954  */
955 void
956 gsignond_db_sql_database_set_last_error (
957         GSignondDbSqlDatabase *self,
958         GError* error)
959 {
960     g_return_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self));
961     gsignond_db_sql_database_clear_last_error(self);
962     self->priv->last_error = error;
963 }
964
965 /**
966  * gsignond_db_sql_database_get_last_error:
967  * @self: instance of #GSignondDbDefaultStorage
968  *
969  * retrieves the last occurred error
970  *
971  * Returns: last occurred #GError
972  *
973  */
974 const GError*
975 gsignond_db_sql_database_get_last_error (GSignondDbSqlDatabase *self)
976 {
977     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), NULL);
978     return self->priv->last_error;
979 }
980
981 /**
982  * gsignond_db_sql_database_clear_last_error:
983  * @self: instance of #GSignondDbDefaultStorage
984  *
985  * clears the last occurred error
986  *
987  */
988 void
989 gsignond_db_sql_database_clear_last_error (GSignondDbSqlDatabase *self)
990 {
991     g_return_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self));
992     if (self->priv->last_error != NULL) {
993         g_error_free(self->priv->last_error);
994         self->priv->last_error = NULL;
995     }
996 }
997
998 /**
999  * gsignond_db_sql_database_get_last_insert_rowid:
1000  * @self: instance of #GSignondDbDefaultStorage
1001  *
1002  * the last inserted row id
1003  *
1004  * Returns: last inserted rowid
1005  */
1006 gint64
1007 gsignond_db_sql_database_get_last_insert_rowid (GSignondDbSqlDatabase *self)
1008 {
1009     g_return_val_if_fail (GSIGNOND_DB_IS_SQL_DATABASE (self), -1);
1010     g_return_val_if_fail (self->priv->db != NULL, 0);
1011
1012     return sqlite3_last_insert_rowid (self->priv->db);
1013 }
1014
1015