Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

dbpool_pgsql.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * dbpool_pgsql.c - implement PostgreSQL operations for generic database connection pool
00059  *
00060  * modeled after dbpool_mysql.c 
00061  * Martiin Atukunda <matlads@myrealbox.com>
00062  */
00063 
00064 #ifdef HAVE_PGSQL
00065 #include <libpq-fe.h>
00066 
00067 
00068 #define add1(str, value) \
00069     if (value != NULL && octstr_len(value) > 0) { \
00070         tmp = octstr_format(str, value); \
00071         octstr_append(cs, tmp); \
00072         octstr_destroy(tmp); \
00073     }
00074 
00075 
00076 static void *pgsql_open_conn(const DBConf *db_conf)
00077 {
00078     PGconn *conn = NULL;
00079     PgSQLConf *conf = db_conf->pgsql; /* make compiler happy */
00080     Octstr *tmp, *cs;
00081 
00082     /* sanity check */
00083     if (conf == NULL)
00084         return NULL;
00085 
00086     cs = octstr_create("");
00087     add1(" host=%S", conf->host);
00088     /* TODO: add hostaddr support via 'host' directive too.
00089      * This needs an octstr_is_addr(Octstr *os) checking if a given string
00090      * contains a valid IPv4 address. Obviously parsing on our own via gwlib
00091      * functions or using regex. If found, insert hostaddr instead of host
00092      * for the connection string. */
00093     /* add1(" hostaddr=%S", conf->host); */
00094     if (conf->port > 0) {   /* add only if user set a value */
00095         octstr_append_cstr(cs, " port=");    
00096         octstr_append_decimal(cs, conf->port);
00097     }
00098     add1(" user=%S", conf->username);
00099     add1(" password=%S", conf->password);
00100     add1(" dbname=%S", conf->database);
00101 
00102 #if 0
00103     /* TODO: This is very bad to show password in the log file */
00104     info(0, "PGSQL: Using connection string: %s.", octstr_get_cstr(cs));
00105 #endif
00106 
00107     conn = PQconnectdb(octstr_get_cstr(cs));
00108 
00109     octstr_destroy(cs);
00110     if (conn == NULL)
00111         goto failed;
00112 
00113     gw_assert(conn != NULL);
00114 
00115     if (PQstatus(conn) == CONNECTION_BAD) {
00116         error(0, "PGSQL: connection to database '%s' failed!", octstr_get_cstr(conf->database)); 
00117         panic(0, "PGSQL: %s", PQerrorMessage(conn));
00118         goto failed;
00119     }
00120 
00121     info(0, "PGSQL: Connected to server at '%s'.", octstr_get_cstr(conf->host));
00122 
00123     return conn;
00124 
00125 failed:
00126     PQfinish(conn);
00127     return NULL;
00128 }
00129 
00130 
00131 static void pgsql_close_conn(void *conn)
00132 {
00133     if (conn == NULL)
00134         return;
00135 
00136     PQfinish(conn);
00137     return;
00138 }
00139 
00140 
00141 static int pgsql_check_conn(void *conn)
00142 {
00143     if (conn == NULL)
00144         return -1;
00145     
00146     if (PQstatus(conn) == CONNECTION_BAD) {    
00147         error(0, "PGSQL: Database check failed!");
00148         error(0, "PGSQL: %s", PQerrorMessage(conn));
00149         return -1;
00150     }   
00151 
00152     return 0;
00153 }
00154 
00155 
00156 static void pgsql_conf_destroy(DBConf *db_conf)
00157 {
00158     PgSQLConf *conf = db_conf->pgsql;
00159 
00160     octstr_destroy(conf->host);
00161     octstr_destroy(conf->username);
00162     octstr_destroy(conf->password);
00163     octstr_destroy(conf->database);
00164 
00165     gw_free(conf);
00166     gw_free(db_conf);
00167 }
00168 
00169 
00170 static int pgsql_update(void *theconn, const Octstr *sql, List *binds)
00171 {
00172     int rows;
00173     PGresult *res = NULL;
00174     PGconn *conn = (PGconn*) theconn;
00175 
00176     res = PQexec(conn, octstr_get_cstr(sql));
00177     if (res == NULL)
00178         return -1;
00179 
00180     switch (PQresultStatus(res)) {
00181         case PGRES_BAD_RESPONSE:
00182         case PGRES_NONFATAL_ERROR:
00183         case PGRES_FATAL_ERROR:
00184             error(0, "PGSQL: %s", octstr_get_cstr(sql));
00185             error(0, "PGSQL: %s", PQresultErrorMessage(res));
00186             PQclear(res);
00187             return -1;
00188         default: /* for compiler please */
00189             break;
00190     }
00191     rows = atoi(PQcmdTuples(res));
00192     PQclear(res);
00193 
00194     return rows;
00195 }
00196 
00197 
00198 static int pgsql_select(void *theconn, const Octstr *sql, List *binds, List **list)
00199 {
00200     int nTuples, nFields, row_loop, field_loop;
00201     PGresult *res = NULL;
00202     List *fields;
00203     PGconn *conn = (PGconn*) theconn;
00204 
00205     gw_assert(list != NULL);
00206     *list = NULL;
00207 
00208     res = PQexec(conn, octstr_get_cstr(sql));
00209     if (res == NULL)
00210         return -1;
00211 
00212     switch (PQresultStatus(res)) {
00213         case PGRES_EMPTY_QUERY:
00214         case PGRES_BAD_RESPONSE:
00215         case PGRES_NONFATAL_ERROR:
00216         case PGRES_FATAL_ERROR:
00217             error(0, "PGSQL: %s", octstr_get_cstr(sql));
00218             error(0, "PGSQL: %s", PQresultErrorMessage(res));
00219             PQclear(res);
00220             return -1;
00221         default: /* for compiler please */
00222             break;
00223     }
00224 
00225     nTuples = PQntuples(res);
00226     nFields = PQnfields(res);
00227     *list = gwlist_create();
00228     for (row_loop = 0; row_loop < nTuples; row_loop++) {
00229         fields = gwlist_create();
00230         for (field_loop = 0; field_loop < nFields; field_loop++) {
00231             if (PQgetisnull(res, row_loop, field_loop))
00232                 gwlist_produce(fields, octstr_create(""));
00233             else 
00234                 gwlist_produce(fields, octstr_create(PQgetvalue(res, row_loop, field_loop)));
00235         }
00236         gwlist_produce(*list, fields);
00237     }
00238     PQclear(res);
00239 
00240     return 0;
00241 }
00242 
00243 
00244 static struct db_ops pgsql_ops = {
00245     .open = pgsql_open_conn,
00246     .close = pgsql_close_conn,
00247     .check = pgsql_check_conn,
00248     .conf_destroy = pgsql_conf_destroy,
00249     .update = pgsql_update,
00250     .select = pgsql_select
00251 };
00252 
00253 #endif /* HAVE_PGSQL */
00254 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.