Kannel: Open Source WAP and SMS gateway  svn-r5335
dbpool_sqlite3.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * dbpool_sqlite3.c - implement SQLite3 operations for generic database connection pool
59  *
60  * Stipe Tolj <st@tolj.org>
61  * David Butler <gdb@dbSystems.com> - modeled select and update from dbpool_oracle.c
62  */
63 
64 #ifdef HAVE_SQLITE3
65 #include <sqlite3.h>
66 
67 static void *sqlite3_open_conn(const DBConf *db_conf)
68 {
69  sqlite3 *db = NULL;
70  SQLite3Conf *conf = db_conf->sqlite3; /* make compiler happy */
71 
72  /* sanity check */
73  if (conf == NULL)
74  return NULL;
75 
76  if (sqlite3_open(octstr_get_cstr(conf->file), &db) != SQLITE_OK) {
77  error(0, "SQLite3: can not open or create database file `%s'!",
78  octstr_get_cstr(conf->file));
79  error(0, "SQLite3: %s", sqlite3_errmsg(db));
80  sqlite3_close(db);
81  goto failed;
82  }
83  if (conf->lock_timeout > 0) {
84  info(0, "SQLite3: Setting lock timeout to %d", conf->lock_timeout);
85  sqlite3_busy_timeout(db, conf->lock_timeout);
86  }
87 
88  info(0, "SQLite3: Opened or created database file `%s'.", octstr_get_cstr(conf->file));
89  info(0, "SQLite3: library version %s.", sqlite3_version);
90 
91  return db;
92 
93 failed:
94  return NULL;
95 }
96 
97 
98 static void sqlite3_close_conn(void *conn)
99 {
100  int rc;
101  if (conn == NULL)
102  return;
103 
104  /* in case we are busy, loop until we can close */
105  do {
106  rc = sqlite3_close((sqlite3*) conn);
107  } while (rc == SQLITE_BUSY);
108 
109  if (rc == SQLITE_ERROR) {
110  error(0, "SQLite3: error while closing database file.");
111  }
112 }
113 
114 
115 static int sqlite3_check_conn(void *conn)
116 {
117  if (conn == NULL)
118  return -1;
119 
120  /* There is no such construct in SQLite3,
121  * so return a valid connection indication */
122  return 0;
123 }
124 
125 
126 static void sqlite3_conf_destroy(DBConf *db_conf)
127 {
128  SQLite3Conf *conf = db_conf->sqlite3;
129 
130  octstr_destroy(conf->file);
131 
132  gw_free(conf);
133  gw_free(db_conf);
134 }
135 
136 static int sqlite3_select(void *theconn, const Octstr *sql, List *binds, List **res)
137 {
138  sqlite3 *db = theconn;
139  sqlite3_stmt *stmt;
140  const char *rem;
141  List *row;
142  int status;
143  int columns;
144  int i;
145  int binds_len = (binds ? gwlist_len(binds) : 0);
146 
147  *res = NULL;
148 
149  /* prepare statement */
150 #if SQLITE_VERSION_NUMBER >= 3003009
151  status = sqlite3_prepare_v2(db, octstr_get_cstr(sql), octstr_len(sql) + 1, &stmt, &rem);
152 #else
153  status = sqlite3_prepare(db, octstr_get_cstr(sql), octstr_len(sql) + 1, &stmt, &rem);
154 #endif
155  if (SQLITE_OK != status) {
156  error(0, "SQLite3: %s", sqlite3_errmsg(db));
157  return -1;
158  }
159 
160  /* bind variables */
161  for (i = 0; i < binds_len; i++) {
162  Octstr *bind = gwlist_get(binds, i);
163  status = sqlite3_bind_text(stmt, i + 1, octstr_get_cstr(bind), octstr_len(bind), SQLITE_STATIC);
164  if (SQLITE_OK != status) {
165  error(0, "SQLite3: %s", sqlite3_errmsg(db));
166  sqlite3_finalize(stmt);
167  return -1;
168  }
169  }
170 
171  /* execute our statement */
172  *res = gwlist_create();
173  while ((status = sqlite3_step(stmt)) == SQLITE_ROW) {
174  columns = sqlite3_data_count(stmt);
175  debug("dbpool.sqlite3",0,"SQL has %d columns", columns);
176  row = gwlist_create();
177  for (i = 0; i < columns; i++) {
178  if (sqlite3_column_type(stmt, i) == SQLITE_NULL) {
179  gwlist_insert(row, i, octstr_create(""));
180  } else {
181  gwlist_insert(row, i, octstr_create(sqlite3_column_text(stmt, i)));
182  }
183  /* debug("dbpool.sqlite3",0,"inserted value = '%s'",
184  octstr_get_cstr(gwlist_get(row,i))); */
185  }
186  gwlist_append(*res, row);
187  }
188 
189  if (SQLITE_DONE != status) {
190  error(0, "SQLite3: %s", sqlite3_errmsg(db));
191  while ((row = gwlist_extract_first(*res)) != NULL)
193  gwlist_destroy(*res, NULL);
194  *res = NULL;
195  sqlite3_finalize(stmt);
196  return -1;
197  }
198 
199  sqlite3_finalize(stmt);
200 
201  return 0;
202 }
203 
204 
205 static int sqlite3_update(void *theconn, const Octstr *sql, List *binds)
206 {
207  sqlite3 *db = theconn;
208  sqlite3_stmt *stmt;
209  const char *rem;
210  int status;
211  int rows;
212  int i;
213  int binds_len = (binds ? gwlist_len(binds) : 0);
214 
215  /* prepare statement */
216 #if SQLITE_VERSION_NUMBER >= 3003009
217  status = sqlite3_prepare_v2(db, octstr_get_cstr(sql), octstr_len(sql) + 1, &stmt, &rem);
218 #else
219  status = sqlite3_prepare(db, octstr_get_cstr(sql), octstr_len(sql) + 1, &stmt, &rem);
220 #endif
221  if (SQLITE_OK != status) {
222  error(0, "SQLite3: %s", sqlite3_errmsg(db));
223  return -1;
224  }
225  debug("dbpool.sqlite3",0,"sqlite3_prepare done");
226 
227  /* bind variables */
228  for (i = 0; i < binds_len; i++) {
229  Octstr *bind = gwlist_get(binds, i);
230  status = sqlite3_bind_text(stmt, i + 1, octstr_get_cstr(bind), octstr_len(bind), SQLITE_STATIC);
231  if (SQLITE_OK != status) {
232  error(0, "SQLite3: %s", sqlite3_errmsg(db));
233  sqlite3_finalize(stmt);
234  return -1;
235  }
236  }
237 
238  /* execute our statement */
239  if ((status = sqlite3_step(stmt)) != SQLITE_DONE) {
240  error(0, "SQLite3: %s", sqlite3_errmsg(db));
241  sqlite3_finalize(stmt);
242  return -1;
243  }
244  debug("dbpool.sqlite3",0,"sqlite3_step done");
245 
246  rows = sqlite3_changes(db);
247  debug("dbpool.sqlite3",0,"rows processed = %d", rows);
248 
249  sqlite3_finalize(stmt);
250 
251  return rows;
252 }
253 
254 static struct db_ops sqlite3_ops = {
255  .open = sqlite3_open_conn,
256  .close = sqlite3_close_conn,
257  .check = sqlite3_check_conn,
258  .conf_destroy = sqlite3_conf_destroy,
259  .select = sqlite3_select,
260  .update = sqlite3_update
261 };
262 
263 #endif /* HAVE_SQLITE3 */
264 
void error(int err, const char *fmt,...)
Definition: log.c:648
void info(int err, const char *fmt,...)
Definition: log.c:672
SQLite3Conf * sqlite3
Definition: dbpool.h:170
Octstr * file
Definition: dbpool.h:133
void gwlist_append(List *list, void *item)
Definition: list.c:179
long gwlist_len(List *list)
Definition: list.c:166
void * gwlist_get(List *list, long pos)
Definition: list.c:292
int lock_timeout
Definition: dbpool.h:134
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
void * gwlist_extract_first(List *list)
Definition: list.c:305
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:336
void gwlist_insert(List *list, long pos, void *item)
Definition: list.c:214
Definition: dbpool.h:164
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
#define gwlist_create()
Definition: list.h:136
Definition: list.c:102
void *(* open)(const DBConf *conf)
Definition: dbpool_p.h:73
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.