Kannel: Open Source WAP and SMS gateway  svn-r5335
dbpool_pgsql.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_pgsql.c - implement PostgreSQL operations for generic database connection pool
59  *
60  * modeled after dbpool_mysql.c
61  * Martiin Atukunda <matlads@myrealbox.com>
62  */
63 
64 #ifdef HAVE_PGSQL
65 #include <libpq-fe.h>
66 
67 
68 #define add1(str, value) \
69  if (value != NULL && octstr_len(value) > 0) { \
70  tmp = octstr_format(str, value); \
71  octstr_append(cs, tmp); \
72  octstr_destroy(tmp); \
73  }
74 
75 
76 static void *pgsql_open_conn(const DBConf *db_conf)
77 {
78  PGconn *conn = NULL;
79  PgSQLConf *conf = db_conf->pgsql; /* make compiler happy */
80  Octstr *tmp, *cs;
81 
82  /* sanity check */
83  if (conf == NULL)
84  return NULL;
85 
86  cs = octstr_create("");
87  add1(" host=%S", conf->host);
88  /* TODO: add hostaddr support via 'host' directive too.
89  * This needs an octstr_is_addr(Octstr *os) checking if a given string
90  * contains a valid IPv4 address. Obviously parsing on our own via gwlib
91  * functions or using regex. If found, insert hostaddr instead of host
92  * for the connection string. */
93  /* add1(" hostaddr=%S", conf->host); */
94  if (conf->port > 0) { /* add only if user set a value */
95  octstr_append_cstr(cs, " port=");
96  octstr_append_decimal(cs, conf->port);
97  }
98  add1(" user=%S", conf->username);
99  add1(" password=%S", conf->password);
100  add1(" dbname=%S", conf->database);
101 
102 #if 0
103  /* TODO: This is very bad to show password in the log file */
104  info(0, "PGSQL: Using connection string: %s.", octstr_get_cstr(cs));
105 #endif
106 
107  conn = PQconnectdb(octstr_get_cstr(cs));
108 
109  octstr_destroy(cs);
110  if (conn == NULL)
111  goto failed;
112 
113  gw_assert(conn != NULL);
114 
115  if (PQstatus(conn) == CONNECTION_BAD) {
116  error(0, "PGSQL: connection to database '%s' failed!", octstr_get_cstr(conf->database));
117  panic(0, "PGSQL: %s", PQerrorMessage(conn));
118  goto failed;
119  }
120 
121  info(0, "PGSQL: Connected to server at '%s'.", octstr_get_cstr(conf->host));
122 
123  return conn;
124 
125 failed:
126  PQfinish(conn);
127  return NULL;
128 }
129 
130 
131 static void pgsql_close_conn(void *conn)
132 {
133  if (conn == NULL)
134  return;
135 
136  PQfinish(conn);
137  return;
138 }
139 
140 
141 static int pgsql_check_conn(void *conn)
142 {
143  if (conn == NULL)
144  return -1;
145 
146  if (PQstatus(conn) == CONNECTION_BAD) {
147  error(0, "PGSQL: Database check failed!");
148  error(0, "PGSQL: %s", PQerrorMessage(conn));
149  return -1;
150  }
151 
152  return 0;
153 }
154 
155 
156 static void pgsql_conf_destroy(DBConf *db_conf)
157 {
158  PgSQLConf *conf = db_conf->pgsql;
159 
160  octstr_destroy(conf->host);
161  octstr_destroy(conf->username);
162  octstr_destroy(conf->password);
163  octstr_destroy(conf->database);
164 
165  gw_free(conf);
166  gw_free(db_conf);
167 }
168 
169 
170 static int pgsql_update(void *theconn, const Octstr *sql, List *binds)
171 {
172  int rows;
173  PGresult *res = NULL;
174  PGconn *conn = (PGconn*) theconn;
175 
176  res = PQexec(conn, octstr_get_cstr(sql));
177  if (res == NULL)
178  return -1;
179 
180  switch (PQresultStatus(res)) {
181  case PGRES_BAD_RESPONSE:
182  case PGRES_NONFATAL_ERROR:
183  case PGRES_FATAL_ERROR:
184  error(0, "PGSQL: %s", octstr_get_cstr(sql));
185  error(0, "PGSQL: %s", PQresultErrorMessage(res));
186  PQclear(res);
187  return -1;
188  default: /* for compiler please */
189  break;
190  }
191  rows = atoi(PQcmdTuples(res));
192  PQclear(res);
193 
194  return rows;
195 }
196 
197 
198 static int pgsql_select(void *theconn, const Octstr *sql, List *binds, List **list)
199 {
200  int nTuples, nFields, row_loop, field_loop;
201  PGresult *res = NULL;
202  List *fields;
203  PGconn *conn = (PGconn*) theconn;
204 
205  gw_assert(list != NULL);
206  *list = NULL;
207 
208  res = PQexec(conn, octstr_get_cstr(sql));
209  if (res == NULL)
210  return -1;
211 
212  switch (PQresultStatus(res)) {
213  case PGRES_EMPTY_QUERY:
214  case PGRES_BAD_RESPONSE:
215  case PGRES_NONFATAL_ERROR:
216  case PGRES_FATAL_ERROR:
217  error(0, "PGSQL: %s", octstr_get_cstr(sql));
218  error(0, "PGSQL: %s", PQresultErrorMessage(res));
219  PQclear(res);
220  return -1;
221  default: /* for compiler please */
222  break;
223  }
224 
225  nTuples = PQntuples(res);
226  nFields = PQnfields(res);
227  *list = gwlist_create();
228  for (row_loop = 0; row_loop < nTuples; row_loop++) {
229  fields = gwlist_create();
230  for (field_loop = 0; field_loop < nFields; field_loop++) {
231  if (PQgetisnull(res, row_loop, field_loop))
232  gwlist_produce(fields, octstr_create(""));
233  else
234  gwlist_produce(fields, octstr_create(PQgetvalue(res, row_loop, field_loop)));
235  }
236  gwlist_produce(*list, fields);
237  }
238  PQclear(res);
239 
240  return 0;
241 }
242 
243 
244 static struct db_ops pgsql_ops = {
245  .open = pgsql_open_conn,
246  .close = pgsql_close_conn,
247  .check = pgsql_check_conn,
248  .conf_destroy = pgsql_conf_destroy,
249  .update = pgsql_update,
250  .select = pgsql_select
251 };
252 
253 #endif /* HAVE_PGSQL */
254 
void error(int err, const char *fmt,...)
Definition: log.c:648
void info(int err, const char *fmt,...)
Definition: log.c:672
gw_assert(wtls_machine->packet_to_send !=NULL)
void gwlist_produce(List *list, void *item)
Definition: list.c:411
Octstr * username
Definition: dbpool.h:140
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1511
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
PgSQLConf * pgsql
Definition: dbpool.h:171
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define octstr_create(cstr)
Definition: octstr.h:125
Octstr * password
Definition: dbpool.h:141
Definition: dbpool.h:164
void octstr_append_decimal(Octstr *ostr, long value)
Definition: octstr.c:1976
Octstr * database
Definition: dbpool.h:142
Definition: octstr.c:118
#define panic
Definition: log.h:87
long port
Definition: dbpool.h:139
#define gwlist_create()
Definition: list.h:136
Octstr * host
Definition: dbpool.h:138
Definition: list.c:102
void *(* open)(const DBConf *conf)
Definition: dbpool_p.h:73
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.