Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
dbpool_mssql.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 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_mssql.c - implement MS SQL operations for generic database connection pool
59  *
60  * Alejandro Guerrieri <aguerrieri at kannel dot org>
61  *
62  */
63 
64 #ifdef HAVE_MSSQL
65 
66 #include <ctpublic.h>
67 
68 static int mssql_select(void *theconn, const Octstr *sql, List *binds, List **res);
69 static int mssql_update(void *theconn, const Octstr *sql, List *binds);
70 
71 /*
72  * Macros to set the CT-Lib column format structure
73  */
74 
75 #define mssql_undef_colfmt(cols) \
76  for (j = 0; j < cols; j++) { gw_free(data[j].format); }
77 
78 #define mssql_undef_coldata(cols) \
79  mssql_undef_colfmt(cols); \
80  for (j = 0; j < cols; j++) { gw_free(data[j].data); } \
81  gw_free(data);
82 
83 struct mssql_conn {
84  CS_CONTEXT *context;
85  CS_CONNECTION *connection;
86  CS_COMMAND *command;
87 };
88 
89 static void mssql_checkerr(int err)
90 {
91  switch (err) {
92  case CS_CMD_SUCCEED:
93  case CS_CMD_DONE:
94  case CS_END_RESULTS:
95  break;
96  case CS_CMD_FAIL:
97  error(0, "Command Failed");
98  break;
99  default:
100  error(0, "Unknown Command Error");
101  }
102 }
103 
104 static void* mssql_open_conn(const DBConf *db_conf)
105 {
106  Octstr *sql;
107  int ret;
108 
109  MSSQLConf *cfg = db_conf->mssql;
110  struct mssql_conn *conn = gw_malloc(sizeof(struct mssql_conn));
111 
112  gw_assert(conn != NULL);
113  memset(conn, 0, sizeof(struct mssql_conn));
114 
115  cs_ctx_alloc(CS_VERSION_100, &conn->context);
116 
117  ct_init(conn->context, CS_VERSION_100);
118 
119  ct_con_alloc(conn->context, &conn->connection);
120  ct_con_props(conn->connection, CS_SET, CS_USERNAME, octstr_get_cstr(cfg->username),
121  CS_NULLTERM, NULL);
122  ct_con_props(conn->connection, CS_SET, CS_PASSWORD, octstr_get_cstr(cfg->password),
123  CS_NULLTERM, NULL);
124 
125  ct_connect(conn->connection, octstr_get_cstr(cfg->server), CS_NULLTERM);
126  ct_cmd_alloc(conn->connection, &conn->command);
127 
128  sql = octstr_format("USE %S", cfg->database);
129  ret = mssql_update(conn, sql, NULL);
130  octstr_destroy(sql);
131  if (ret < 0 )
132  error(0, "MSSQL: DB selection failed!");
133  return conn;
134 }
135 
136 void mssql_close_conn(void *theconn)
137 {
138  struct mssql_conn *conn = (struct mssql_conn*) theconn;
139 
140  gw_assert(conn != NULL);
141 
142  ct_cmd_drop(conn->command);
143  ct_close(conn->connection, CS_UNUSED);
144  ct_con_drop(conn->connection);
145  ct_exit(conn->context, CS_UNUSED);
146  cs_ctx_drop(conn->context);
147 }
148 
149 static int mssql_check_conn(void *theconn)
150 {
151  int status;
152  CS_INT *outlen;
153 
154  struct mssql_conn *conn = (struct mssql_conn*) theconn;
155 
156  if (ct_con_props(conn->connection, CS_GET, CS_CON_STATUS,
157  &status, CS_UNUSED, outlen) != CS_SUCCEED)
158  return 1;
159 
160  return (status & CS_CONSTAT_CONNECTED) ? 0:1;
161 }
162 
163 static void mssql_conf_destroy(DBConf *theconf)
164 {
165  MSSQLConf *conf = theconf->mssql;
166 
167  octstr_destroy(conf->username);
168  octstr_destroy(conf->password);
169  octstr_destroy(conf->server);
170 
171  gw_free(conf);
172  gw_free(theconf);
173 }
174 
175 struct data_s {
176  CS_TEXT *data;
177  CS_DATAFMT *format;
178  CS_INT size;
179  CS_SMALLINT ind;
180 };
181 
182 static int mssql_select(void *theconn, const Octstr *sql, List *binds, List **res)
183 {
184  List *row;
185  int columns;
186  CS_RETCODE ret, res_type;
187  int num_rows, count, i, j;
188  struct data_s *data;
189  struct mssql_conn *conn = (struct mssql_conn*) theconn;
190  int binds_len = (binds ? gwlist_len(binds) : 0);
191 
192  *res = NULL;
193 
194  gw_assert(conn != NULL);
195 
196  ct_command(conn->command, CS_LANG_CMD,
197  octstr_get_cstr(sql), CS_NULLTERM, CS_UNUSED);
198 
199  if ((ret = ct_send(conn->command)) != CS_SUCCEED) {
200  error(0, "Error sending query");
201  return -1;
202  }
203 
204  *res = gwlist_create();
205  while((ret = ct_results(conn->command, &res_type)) == CS_SUCCEED) {
206  switch (res_type) {
207  case CS_ROW_RESULT:
208  if (ct_res_info(conn->command, CS_NUMDATA,
209  (CS_INT *)&columns, CS_UNUSED, NULL) != CS_SUCCEED) {
210  error(0, "Error fetching attributes");
211  return -1;
212  }
213  data = gw_malloc(sizeof(struct data_s)*columns);
214  memset(data, 0, sizeof(struct data_s)*columns);
215 
216  for (i = 0; i < columns; i++) {
217  data[i].format = gw_malloc(sizeof(CS_DATAFMT));
218  memset(data[i].format, 0, sizeof(CS_DATAFMT));
219  if (ct_describe(conn->command, i+1, data[i].format) != CS_SUCCEED) {
220  error(0, "Error fetching column description");
221  mssql_undef_colfmt(i);
222  gw_free(data);
223  return -1;
224  }
225  data[i].format->maxlength++;
226  data[i].data = gw_malloc(data[i].format->maxlength);
227  data[i].format->datatype = CS_CHAR_TYPE;
228  data[i].format->format = CS_FMT_NULLTERM;
229  if (ct_bind(conn->command, i+1, data[i].format, data[i].data,
230  &data[i].size, &data[i].ind) != CS_SUCCEED) {
231  error(0, "Error binding column");
232  mssql_undef_coldata(i);
233  return -1;
234  }
235  }
236  while(((ret = ct_fetch(conn->command, CS_UNUSED, CS_UNUSED,
237  CS_UNUSED, &count)) == CS_SUCCEED) || (ret == CS_ROW_FAIL)) {
238  if( ret == CS_ROW_FAIL ) {
239  error(0, "Error on row %d in this fetch batch.", count+1);
240  mssql_undef_coldata(columns);
241  gw_free(data);
242  return -1;
243  }
244  row = gwlist_create();
245  for (i = 0; i < columns; i++) {
246  if (data[i].data == NULL || data[i].ind == -1) {
247  gwlist_insert(row, i, octstr_create(""));
248  } else {
249  gwlist_insert(row, i, octstr_create_from_data((char *)data[i].data, data[i].size));
250  }
251  }
252  gwlist_append(*res, row);
253  }
254  if( ret != CS_END_DATA ) {
255  error(0, "ct_fetch failed");
256  mssql_undef_coldata(columns);
257  while ((row = gwlist_extract_first(*res)) != NULL)
259  gwlist_destroy(*res, NULL);
260  *res = NULL;
261  return -1;
262  }
263  mssql_undef_coldata(columns);
264  break;
265  case CS_CMD_SUCCEED:
266  case CS_CMD_DONE:
267  case CS_STATUS_RESULT:
268  break;
269  case CS_CMD_FAIL:
270  error(0, "select failed!");
271  return -1;
272  break;
273  default:
274  error(0, "ct_result returned unexpected result type: %d", res_type);
275  return -1;
276  break;
277  }
278  }
279  return 0;
280 }
281 
282 /* Run commands from which we expect no results returned */
283 static int mssql_update(void *theconn, const Octstr *sql, List *binds)
284 {
285  CS_RETCODE status, results_ret;
286  CS_INT result_type;
287 
288  struct mssql_conn *conn = (struct mssql_conn*) theconn;
289 
290  gw_assert(conn != NULL);
291  if (conn->command == NULL)
292  return -1;
293 
294  status = ct_command(conn->command, CS_LANG_CMD, octstr_get_cstr(sql), CS_NULLTERM, CS_UNUSED);
295  if (status != CS_SUCCEED) {
296  error(0, "ct_command() failed\n");
297  return -1;
298  }
299  status = ct_send(conn->command);
300  if (status != CS_SUCCEED) {
301  error(0, "ct_send() failed\n");
302  return -1;
303  }
304  while ((results_ret = ct_results(conn->command, &result_type)) == CS_SUCCEED) {
305  switch ((int) result_type) {
306  case CS_CMD_SUCCEED:
307  case CS_CMD_DONE:
308  case CS_STATUS_RESULT:
309  break;
310  default:
311  mssql_checkerr(result_type);
312  return -1;
313  }
314  }
315  mssql_checkerr(results_ret);
316  switch ((int) results_ret) {
317  case CS_END_RESULTS:
318  break;
319  default:
320  mssql_checkerr(result_type);
321  return -1;
322  }
323 
324  return 0;
325 }
326 
327 static struct db_ops mssql_ops = {
328  .open = mssql_open_conn,
329  .close = mssql_close_conn,
330  .check = mssql_check_conn,
331  .conf_destroy = mssql_conf_destroy,
332  .select = mssql_select,
333  .update = mssql_update
334 };
335 
336 #endif
void error(int err, const char *fmt,...)
Definition: log.c:612
MSSQLConf * mssql
Definition: dbpool.h:165
int size
Definition: wsasm.c:84
Definition: parse.c:65
void gwlist_append(List *list, void *item)
Definition: list.c:179
Octstr * server
Definition: dbpool.h:113
long gwlist_len(List *list)
Definition: list.c:166
Octstr * database
Definition: dbpool.h:114
static Octstr * connection
Definition: test_ppg.c:103
static void format(char *buf, const char *fmt)
Definition: accesslog.c:174
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
Octstr * password
Definition: dbpool.h:112
void * gwlist_extract_first(List *list)
Definition: list.c:305
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:334
Octstr * username
Definition: dbpool.h:111
gw_assert(wtls_machine->packet_to_send!=NULL)
void gwlist_insert(List *list, long pos, void *item)
Definition: list.c:214
Definition: dbpool.h:164
static Cfg * cfg
Definition: smsbox.c:115
Definition: octstr.c:118
char * result_type
Definition: wap-appl.c:197
#define gwlist_create()
Definition: list.h:136
#define octstr_create_from_data(data, len)
Definition: octstr.h:134
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.