Kannel: Open Source WAP and SMS gateway  svn-r5335
sqlbox_sqlite3.c
Go to the documentation of this file.
1 #include "gwlib/gwlib.h"
2 #ifdef HAVE_SQLITE3
3 #include "gwlib/dbpool.h"
4 #include <sqlite3.h>
5 #include "sqlbox_sqlite3.h"
6 
7 #define sql_update sqlite3_update
8 #define sql_select sqlite3_select
9 
10 static Octstr *sqlbox_logtable;
11 static Octstr *sqlbox_insert_table;
12 
13 /*
14  * Our connection pool to sqlite3.
15  */
16 
17 static DBPool *pool = NULL;
18 
19 /*
20  *-------------------------------------------------
21  * sqlite3 thingies
22  *-------------------------------------------------
23 */
24 
25 #define octstr_null_create(x) ((x != NULL) ? octstr_create(x) : octstr_create(""))
26 #define atol_null(x) ((x != NULL) ? atol(x) : -1)
27 
28 static int sqlite3_update(DBPoolConn *conn, const Octstr *sql)
29 {
30  int state;
31  char *errmsg = 0;
32 
33 #if defined(SQLBOX_TRACE)
34  debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql));
35 #endif
36 
37  state = sqlite3_exec(conn->conn, octstr_get_cstr(sql), NULL, 0, &errmsg);
38  if (state != SQLITE_OK) {
39  error(0, "SQLITE3: %s", sqlite3_errmsg(conn->conn));
40  return -1;
41  }
42  return sqlite3_changes(conn->conn);
43 }
44 
45 sqlite3_stmt* sqlite3_select(DBPoolConn *conn, const Octstr *sql)
46 {
47  int res;
48  sqlite3_stmt *stmt = NULL;
49 
50 #if defined(SQLBOX_TRACE)
51  debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql));
52 #endif
53 
54  res = sqlite3_prepare_v2(conn->conn, octstr_get_cstr(sql), -1, &stmt, NULL);
55  if (res != SQLITE_OK) {
56  error(0, "SQLITE3: Could not compile query: %s", sqlite3_errmsg(conn->conn));
57  return NULL;
58  }
59  return stmt;
60 }
61 
62 void sqlbox_configure_sqlite3(Cfg* cfg)
63 {
64  CfgGroup *grp;
65  Octstr *sql;
66  DBPoolConn *pc;
67 
68  if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox"))))
69  panic(0, "SQLBOX: Sqlite3: group 'sqlbox' is not specified!");
70 
71  sqlbox_logtable = cfg_get(grp, octstr_imm("sql-log-table"));
72  if (sqlbox_logtable == NULL) {
73  panic(0, "Parameter 'sql-log-table' configured.");
74  }
75  sqlbox_insert_table = cfg_get(grp, octstr_imm("sql-insert-table"));
76  if (sqlbox_insert_table == NULL) {
77  panic(0, "Parameter 'sql-insert-table' configured.");
78  }
79 
80  pc = dbpool_conn_consume(pool);
81  if (pc == NULL) {
82  error(0, "SQLITE3: Database pool got no connection! DB update failed!");
83  return;
84  }
85 
86  /* create send_sms && sent_sms tables if they do not exist */
87  sql = octstr_format(SQLBOX_SQLITE3_CREATE_LOG_TABLE, sqlbox_logtable);
88  sql_update(pc, sql);
89  octstr_destroy(sql);
90  sql = octstr_format(SQLBOX_SQLITE3_CREATE_LOG_TABLE, sqlbox_insert_table);
91  sql_update(pc, sql);
92  octstr_destroy(sql);
93  /* end table creation */
95 }
96 
97 Msg *sqlite3_fetch_msg()
98 {
99  int state;
100  DBPoolConn *pc;
101  sqlite3_stmt *res = NULL;
102  int rows = 0;
103  Msg *msg = NULL;
104  Octstr *sql, *delet, *id = NULL;
105 
106  pc = dbpool_conn_consume(pool);
107  if (pc == NULL) {
108  error(0, "SQLITE3: Database pool got no connection! DB update failed!");
109  return NULL;
110  }
111 
112  sql = octstr_format(SQLBOX_SQLITE3_SELECT_QUERY, sqlbox_insert_table);
113 #if defined(SQLBOX_TRACE)
114  debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql));
115 #endif
116  res = sql_select(pc, sql);
117  do {
118  state=sqlite3_step(res);
119  if (state==SQLITE_ROW){
120  rows++;
121  id = octstr_null_create((char *)sqlite3_column_text(res, 0));
122  /* save fields in this row as msg struct */
123  msg = msg_create(sms);
124  msg->sms.sender = octstr_null_create((char *)sqlite3_column_text(res, 2));
125  msg->sms.receiver = octstr_null_create((char *)sqlite3_column_text(res, 3));
126  msg->sms.udhdata = octstr_null_create((char *)sqlite3_column_text(res, 4));
127  msg->sms.msgdata = octstr_null_create((char *)sqlite3_column_text(res, 5));
128  msg->sms.time = atol_null((char *)sqlite3_column_text(res,6));
129  msg->sms.smsc_id = octstr_null_create((char *)sqlite3_column_text(res, 7));
130  msg->sms.service = octstr_null_create((char *)sqlite3_column_text(res, 8));
131  msg->sms.account = octstr_null_create((char *)sqlite3_column_text(res, 9));
132  /* msg->sms.id = atol_null((char *)sqlite3_column_text(res, 10)); */
133  msg->sms.sms_type = atol_null((char *)sqlite3_column_text(res, 11));
134  msg->sms.mclass = atol_null((char *)sqlite3_column_text(res, 12));
135  msg->sms.mwi = atol_null((char *)sqlite3_column_text(res, 13));
136  msg->sms.coding = atol_null((char *)sqlite3_column_text(res, 14));
137  msg->sms.compress = atol_null((char *)sqlite3_column_text(res, 15));
138  msg->sms.validity = atol_null((char *)sqlite3_column_text(res, 16));
139  msg->sms.deferred = atol_null((char *)sqlite3_column_text(res, 17));
140  msg->sms.dlr_mask = atol_null((char *)sqlite3_column_text(res, 18));
141  msg->sms.dlr_url = octstr_null_create((char *)sqlite3_column_text(res, 19));
142  msg->sms.pid = atol_null((char *)sqlite3_column_text(res, 20));
143  msg->sms.alt_dcs = atol_null((char *)sqlite3_column_text(res, 21));
144  msg->sms.rpi = atol_null((char *)sqlite3_column_text(res, 22));
145  msg->sms.charset = octstr_null_create((char *)sqlite3_column_text(res, 23));
146  msg->sms.binfo = octstr_null_create((char *)sqlite3_column_text(res, 25));
147  msg->sms.meta_data = octstr_null_create((char *)sqlite3_column_text(res, 26));
148  msg->sms.boxc_id = (sqlite3_column_text(res, 24) == NULL) ? octstr_duplicate(sqlbox_id):octstr_null_create((char *)sqlite3_column_text(res, 24));
149  }
150  } while (state==SQLITE_ROW);
151  sqlite3_finalize(res);
152 
153  if ( rows > 0) {
154  /* delete current row */
155  delet = octstr_format(SQLBOX_SQLITE3_DELETE_QUERY, sqlbox_insert_table, id);
156 #if defined(SQLBOX_TRACE)
157  debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(delet));
158 #endif
159  sql_update(pc, delet);
160  octstr_destroy(id);
161  octstr_destroy(delet);
162  }
163 
164  octstr_destroy(sql);
166  return msg;
167 }
168 
169 static Octstr *get_numeric_value_or_return_null(long int num)
170 {
171  if (num == -1) {
172  return octstr_create("NULL");
173  }
174  return octstr_format("%ld", num);
175 }
176 
177 static Octstr *get_string_value_or_return_null(Octstr *str)
178 {
179  if (str == NULL) {
180  return octstr_create("NULL");
181  }
182  if (octstr_compare(str, octstr_imm("")) == 0) {
183  return octstr_create("NULL");
184  }
185  octstr_replace(str, octstr_imm("\\"), octstr_imm("\\\\"));
186  octstr_replace(str, octstr_imm("\'"), octstr_imm("\\\'"));
187  return octstr_format("\'%S\'", str);
188 }
189 
190 #define st_num(x) (stuffer[stuffcount++] = get_numeric_value_or_return_null(x))
191 #define st_str(x) (stuffer[stuffcount++] = get_string_value_or_return_null(x))
192 
193 void sqlite3_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */)
194 {
195  Octstr *sql;
196  Octstr *stuffer[30];
197  int stuffcount = 0;
198  DBPoolConn *pc;
199 
200  pc = dbpool_conn_consume(pool);
201  if (pc == NULL) {
202  error(0, "SQLITE3: Database pool got no connection! DB update failed!");
203  return;
204  }
205 
206  sql = octstr_format(SQLBOX_SQLITE3_INSERT_QUERY, sqlbox_logtable, st_str(momt), st_str(msg->sms.sender),
207  st_str(msg->sms.receiver), st_str(msg->sms.udhdata), st_str(msg->sms.msgdata), st_num(msg->sms.time),
208  st_str(msg->sms.smsc_id), st_str(msg->sms.service), st_str(msg->sms.account), st_num(msg->sms.sms_type),
209  st_num(msg->sms.mclass), st_num(msg->sms.mwi), st_num(msg->sms.coding), st_num(msg->sms.compress),
210  st_num(msg->sms.validity), st_num(msg->sms.deferred), st_num(msg->sms.dlr_mask), st_str(msg->sms.dlr_url),
211  st_num(msg->sms.pid), st_num(msg->sms.alt_dcs), st_num(msg->sms.rpi), st_str(msg->sms.charset),
212  st_str(msg->sms.boxc_id), st_str(msg->sms.binfo), st_str(msg->sms.meta_data));
213  sql_update(pc, sql);
214  while (stuffcount > 0) {
215  octstr_destroy(stuffer[--stuffcount]);
216  }
217  octstr_destroy(sql);
219 }
220 
221 void sqlite3_leave()
222 {
223  dbpool_destroy(pool);
224 }
225 
226 struct server_type *sqlbox_init_sqlite3(Cfg* cfg)
227 {
228  CfgGroup *grp;
229  List *grplist;
230  Octstr *sqlite3_db, *sqlite3_id;
231  Octstr *p = NULL;
232  long pool_size, lock_timeout;
233  DBConf *db_conf = NULL;
234  struct server_type *res = NULL;
235 
236  /*
237  * check for all mandatory directives that specify the field names
238  * of the used Sqlite3 table
239  */
240  if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox"))))
241  panic(0, "SQLBOX: Sqlite3: group 'sqlbox' is not specified!");
242 
243  if (!(sqlite3_id = cfg_get(grp, octstr_imm("id"))))
244  panic(0, "SQLBOX: Sqlite3: directive 'id' is not specified!");
245 
246  /*
247  * now grap the required information from the 'sqlite3-connection' group
248  * with the sqlite3-id we just obtained
249  *
250  * we have to loop through all available Sqlite3 connection definitions
251  * and search for the one we are looking for
252  */
253 
254  grplist = cfg_get_multi_group(cfg, octstr_imm("sqlite3-connection"));
255  while (grplist && (grp = (CfgGroup *)gwlist_extract_first(grplist)) != NULL) {
256  p = cfg_get(grp, octstr_imm("id"));
257  if (p != NULL && octstr_compare(p, sqlite3_id) == 0) {
258  goto found;
259  }
260  if (p != NULL) octstr_destroy(p);
261  }
262  panic(0, "SQLBOX: Sqlite3: connection settings for id '%s' are not specified!",
263  octstr_get_cstr(sqlite3_id));
264 
265 found:
266  octstr_destroy(p);
267  gwlist_destroy(grplist, NULL);
268 
269  if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0)
270  pool_size = 1;
271 
272  if (!(sqlite3_db = cfg_get(grp, octstr_imm("database"))))
273  panic(0, "SQLBOX: Sqlite3: directive 'database' is not specified!");
274 
275  if (cfg_get_integer(&lock_timeout, grp, octstr_imm("lock-timeout")) == -1 || lock_timeout == 0 )
276  lock_timeout = 0;
277  /*
278  * ok, ready to connect to Sqlite3
279  */
280  db_conf = gw_malloc(sizeof(DBConf));
281  gw_assert(db_conf != NULL);
282 
283  db_conf->sqlite3 = gw_malloc(sizeof(SQLite3Conf));
284  gw_assert(db_conf->sqlite3 != NULL);
285 
286  db_conf->sqlite3->file = sqlite3_db;
287  db_conf->sqlite3->lock_timeout = lock_timeout;
288 
289  pool = dbpool_create(DBPOOL_SQLITE3, db_conf, pool_size);
290  gw_assert(pool != NULL);
291 
292  /*
293  * XXX should a failing connect throw panic?!
294  */
295  if (dbpool_conn_count(pool) == 0)
296  panic(0,"SQLBOX: Sqlite3: database pool has no connections!");
297 
298  octstr_destroy(sqlite3_id);
299 
300  res = gw_malloc(sizeof(struct server_type));
301  gw_assert(res != NULL);
302 
303  res->type = octstr_create("Sqlite3");
304  res->sql_enter = sqlbox_configure_sqlite3;
305  res->sql_leave = sqlite3_leave;
306  res->sql_fetch_msg = sqlite3_fetch_msg;
307  res->sql_save_msg = sqlite3_save_msg;
308  return res;
309 }
310 #endif
void error(int err, const char *fmt,...)
Definition: log.c:648
void octstr_replace(Octstr *haystack, Octstr *needle, Octstr *repl)
Definition: octstr.c:2649
long dbpool_conn_count(DBPool *p)
SQLite3Conf * sqlite3
Definition: dbpool.h:170
DBPool * dbpool_create(enum db_type db_type, DBConf *conf, unsigned int connections)
Octstr * file
Definition: dbpool.h:133
gw_assert(wtls_machine->packet_to_send !=NULL)
#define cfg_get(grp, varname)
Definition: cfg.h:86
#define msg_create(type)
Definition: msg.h:136
int lock_timeout
Definition: dbpool.h:134
static Cfg * cfg
Definition: opensmppbox.c:95
void(* sql_leave)()
Definition: sqlbox_sql.h:16
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static struct pid_list * found
void(* sql_enter)(Cfg *)
Definition: sqlbox_sql.h:15
void dbpool_conn_produce(DBPoolConn *conn)
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
Definition: msg.h:79
Definition: cfg.c:164
void * gwlist_extract_first(List *list)
Definition: list.c:305
Msg *(* sql_fetch_msg)()
Definition: sqlbox_sql.h:17
#define octstr_duplicate(ostr)
Definition: octstr.h:187
List * cfg_get_multi_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:645
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define octstr_create(cstr)
Definition: octstr.h:125
Definition: dbpool.h:164
void dbpool_destroy(DBPool *p)
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:742
#define panic
Definition: log.h:87
Definition: cfg.c:73
DBPoolConn * dbpool_conn_consume(DBPool *p)
Octstr * type
Definition: sqlbox_sql.h:14
void * conn
Definition: dbpool.h:95
CfgGroup * cfg_get_single_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:639
Octstr * sqlbox_id
Definition: sqlbox.c:95
Definition: list.c:102
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
void(* sql_save_msg)(Msg *, Octstr *)
Definition: sqlbox_sql.h:18
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:871
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.