db_postgres/dbase.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dbase.c 5431 2009-01-07 14:46:10Z henningw $
00003  *
00004  * Copyright (C) 2003 August.Net Services, LLC
00005  * Copyright (C) 2006 Norman Brandinger
00006  * Copyright (C) 2008 1&1 Internet AG
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History
00025  * -------
00026  * 2003-04-06 initial code written (Greg Fausak/Andy Fullford)
00027  * 2006-07-28 within pg_get_result(): added check to immediatly return of no 
00028  *            result set was returned added check to only execute 
00029  *            convert_result() if PGRES_TUPLES_OK added safety check to avoid 
00030  *            double pg_free_result() (norm)
00031  * 2006-08-07 Rewrote pg_get_result().
00032  *            Additional debugging lines have been placed through out the code.
00033  *            Added Asynchronous Command Processing (PQsendQuery/PQgetResult) 
00034  *            instead of PQexec. this was done in preparation of adding FETCH 
00035  *            support.  Note that PQexec returns a result pointer while 
00036  *            PQsendQuery does not.  The result set pointer is obtained from 
00037  *            a call (or multiple calls) to PQgetResult.
00038  *            Removed transaction processing calls (BEGIN/COMMIT/ROLLBACK) as 
00039  *            they added uneeded overhead.  Klaus' testing showed in excess of 
00040  *            1ms gain by removing each command.  In addition, Kamailio only 
00041  *            issues single queries and is not, at this time transaction aware.
00042  *            The transaction processing routines have been left in place 
00043  *            should this support be needed in the future.
00044  *            Updated logic in pg_query / pg_raw_query to accept a (0) result 
00045  *            set (_r) parameter.  In this case, control is returned
00046  *            immediately after submitting the query and no call to 
00047  *            pg_get_results() is performed. This is a requirement for 
00048  *            FETCH support. (norm)
00049  * 2006-10-27 Added fetch support (norm)
00050  *            Removed dependency on aug_* memory routines (norm)
00051  *            Added connection pooling support (norm)
00052  *            Standardized API routines to pg_* names (norm)
00053  * 2006-11-01 Updated pg_insert(), pg_delete(), pg_update() and 
00054  *            pg_get_result() to handle failed queries.  Detailed warnings 
00055  *            along with the text of the failed query is now displayed in the 
00056  *            log. Callers of these routines can now assume that a non-zero 
00057  *            rc indicates the query failed and that remedial action may need 
00058  *            to be taken. (norm)
00059  */
00060 
00061 /*! \file
00062  *  \brief DB_POSTGRES :: Core
00063  *  \ingroup db_postgres
00064  *  Module: \ref db_postgres
00065  */
00066 
00067 /*! maximum number of columns */
00068 #define MAXCOLUMNS   512
00069 
00070 #include <string.h>
00071 #include <stdio.h>
00072 #include "../../dprint.h"
00073 #include "../../mem/mem.h"
00074 #include "../../db/db.h"
00075 #include "../../db/db_ut.h"
00076 #include "../../db/db_query.h"
00077 #include "dbase.h"
00078 #include "pg_con.h"
00079 #include "val.h"
00080 #include "res.h"
00081 
00082 static void db_postgres_free_query(const db_con_t* _con);
00083 
00084 
00085 /*!
00086  * \brief Initialize database for future queries
00087  * \param _url URL of the database that should be opened
00088  * \return database connection on success, NULL on error
00089  * \note this function must be called prior to any database functions
00090  */
00091 db_con_t *db_postgres_init(const str* _url)
00092 {
00093    return db_do_init(_url, (void*) db_postgres_new_connection);
00094 }
00095 
00096 
00097 /*!
00098  * \brief Close database when the database is no longer needed
00099  * \param _h closed connection, as returned from db_postgres_init
00100  * \note free all memory and resources
00101  */
00102 void db_postgres_close(db_con_t* _h)
00103 {
00104    db_do_close(_h, db_postgres_free_connection);
00105 }
00106 
00107 
00108 /*!
00109  * \brief Submit_query, run a query
00110  * \param _con database connection
00111  * \param _s query string
00112  * \return 0 on success, negative on failure
00113  */
00114 static int db_postgres_submit_query(const db_con_t* _con, const str* _s)
00115 {
00116    if(! _con || !_s || !_s->s)
00117    {
00118       LM_ERR("invalid parameter value\n");
00119       return(-1);
00120    }
00121 
00122    /* this bit of nonsense in case our connection get screwed up */
00123    switch(PQstatus(CON_CONNECTION(_con)))
00124    {
00125       case CONNECTION_OK: 
00126          break;
00127       case CONNECTION_BAD:
00128          LM_DBG("connection reset\n");
00129          PQreset(CON_CONNECTION(_con));
00130          break;
00131       case CONNECTION_STARTED:
00132       case CONNECTION_MADE:
00133       case CONNECTION_AWAITING_RESPONSE:
00134       case CONNECTION_AUTH_OK:
00135       case CONNECTION_SETENV:
00136       case CONNECTION_SSL_STARTUP:
00137       case CONNECTION_NEEDED:
00138       default:
00139          LM_ERR("%p PQstatus(%s) invalid: %.*s\n", _con,
00140             PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s);
00141          return -1;
00142    }
00143 
00144    /* free any previous query that is laying about */
00145    db_postgres_free_query(_con);
00146 
00147    /* exec the query */
00148    if (PQsendQuery(CON_CONNECTION(_con), _s->s)) {
00149       LM_DBG("%p PQsendQuery(%.*s)\n", _con, _s->len, _s->s);
00150    } else {
00151       LM_ERR("%p PQsendQuery Error: %s Query: %.*s\n", _con,
00152       PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s);
00153       return -1;
00154    }
00155 
00156    return 0;
00157 }
00158 
00159 
00160 /*!
00161  * \brief Gets a partial result set, fetch rows from a result
00162  *
00163  * Gets a partial result set, fetch a number of rows from a database result.
00164  * This function initialize the given result structure on the first run, and
00165  * fetches the nrows number of rows. On subsequenting runs, it uses the
00166  * existing result and fetches more rows, until it reaches the end of the
00167  * result set. Because of this the result needs to be null in the first
00168  * invocation of the function. If the number of wanted rows is zero, the
00169  * function returns anything with a result of zero.
00170  * \param _con database connection
00171  * \param _res result set
00172  * \param nrows number of fetches rows
00173  * \return 0 on success, negative on failure
00174  */
00175 int db_postgres_fetch_result(const db_con_t* _con, db_res_t** _res, const int nrows)
00176 {
00177    int rows;
00178    PGresult *res = NULL;
00179    ExecStatusType pqresult;
00180 
00181    if (!_con || !_res || nrows < 0) {
00182       LM_ERR("invalid parameter value\n");
00183       return -1;
00184    }
00185 
00186    /* exit if the fetch count is zero */
00187    if (nrows == 0) {
00188       if (*_res)
00189          db_free_result(*_res);
00190 
00191       *_res = 0;
00192       return 0;
00193    }
00194 
00195    if (*_res == NULL) {
00196       /* Allocate a new result structure */
00197       *_res = db_new_result();
00198 
00199       /* Get the result of the previous query */
00200       while (1) {
00201          if ((res = PQgetResult(CON_CONNECTION(_con)))) {
00202             CON_RESULT(_con) = res;
00203          } else {
00204             break;
00205          }
00206       }
00207       pqresult = PQresultStatus(CON_RESULT(_con));
00208       LM_DBG("%p PQresultStatus(%s) PQgetResult(%p)\n", _con,
00209          PQresStatus(pqresult), CON_RESULT(_con));
00210 
00211       switch(pqresult) {
00212          case PGRES_COMMAND_OK:
00213             /* Successful completion of a command returning no data (such as INSERT or UPDATE). */
00214             return 0;
00215 
00216          case PGRES_TUPLES_OK:
00217             /* Successful completion of a command returning data (such as a SELECT or SHOW). */
00218             if (db_postgres_get_columns(_con, *_res) < 0) {
00219                LM_ERR("failed to get column names\n");
00220                return -2;
00221             }
00222             break;
00223 
00224          case PGRES_FATAL_ERROR:
00225             LM_ERR("%p - invalid query, execution aborted\n", _con);
00226             LM_ERR("%p - PQresultStatus(%s)\n", _con, PQresStatus(pqresult));
00227             LM_ERR("%p: %s\n", _con, PQresultErrorMessage(CON_RESULT(_con)));
00228             if (*_res)
00229                db_free_result(*_res);
00230             *_res = 0;
00231             return -3;
00232 
00233          case PGRES_EMPTY_QUERY:
00234          /* notice or warning */
00235          case PGRES_NONFATAL_ERROR:
00236          /* status for COPY command, not used */
00237          case PGRES_COPY_OUT:
00238          case PGRES_COPY_IN:
00239          /* unexpected response */
00240          case PGRES_BAD_RESPONSE:
00241          default:
00242             LM_ERR("%p - probable invalid query\n", _con);
00243             LM_ERR("%p - PQresultStatus(%s)\n", _con, PQresStatus(pqresult));
00244             LM_ERR("%p: %s\n", _con, PQresultErrorMessage(CON_RESULT(_con)));
00245             if (*_res)
00246                db_free_result(*_res);
00247             *_res = 0;
00248             return -4;
00249       }
00250 
00251    } else {
00252       if(RES_ROWS(*_res) != NULL) {
00253          db_free_rows(*_res);
00254       }
00255       RES_ROWS(*_res) = 0;
00256       RES_ROW_N(*_res) = 0;
00257    }
00258 
00259    /* Get the number of rows (tuples) in the query result. */
00260    RES_NUM_ROWS(*_res) = PQntuples(CON_RESULT(_con));
00261 
00262    /* determine the number of rows remaining to be processed */
00263    rows = RES_NUM_ROWS(*_res) - RES_LAST_ROW(*_res);
00264 
00265    /* If there aren't any more rows left to process, exit */
00266    if (rows <= 0)
00267       return 0;
00268 
00269    /* if the fetch count is less than the remaining rows to process                 */
00270    /* set the number of rows to process (during this call) equal to the fetch count */
00271    if (nrows < rows)
00272       rows = nrows;
00273 
00274    RES_ROW_N(*_res) = rows;
00275 
00276    LM_DBG("converting row %d of %d count %d\n", RES_LAST_ROW(*_res),
00277          RES_NUM_ROWS(*_res), RES_ROW_N(*_res));
00278 
00279    if (db_postgres_convert_rows(_con, *_res) < 0) {
00280       LM_ERR("failed to convert rows\n");
00281       if (*_res)
00282          db_free_result(*_res);
00283 
00284       *_res = 0;
00285       return -3;
00286    }
00287 
00288    /* update the total number of rows processed */
00289    RES_LAST_ROW(*_res) += rows;
00290    return 0;
00291 }
00292 
00293 
00294 /*!
00295  * \brief Free database and any old query results
00296  * \param _con database connection
00297  */
00298 static void db_postgres_free_query(const db_con_t* _con)
00299 {
00300    if(CON_RESULT(_con))
00301    {
00302       LM_DBG("PQclear(%p) result set\n", CON_RESULT(_con));
00303       PQclear(CON_RESULT(_con));
00304       CON_RESULT(_con) = 0;
00305    }
00306 }
00307 
00308 
00309 /*!
00310  * \brief Free the query and the result memory in the core
00311  * \param _con database connection
00312  * \param _r result set
00313  * \return 0 on success, -1 on failure
00314  */
00315 int db_postgres_free_result(db_con_t* _con, db_res_t* _r)
00316 {
00317      if ((!_con) || (!_r)) {
00318         LM_ERR("invalid parameter value\n");
00319         return -1;
00320      }
00321      if (db_free_result(_r) < 0) {
00322         LM_ERR("unable to free result structure\n");
00323         return -1;
00324      }
00325    db_postgres_free_query(_con);
00326    return 0;
00327 }
00328 
00329 
00330 /*!
00331  * \brief Query table for specified rows
00332  * \param _h structure representing database connection
00333  * \param _k key names
00334  * \param _op operators
00335  * \param _v values of the keys that must match
00336  * \param _c column names to return
00337  * \param _n nmber of key=values pairs to compare
00338  * \param _nc number of columns to return
00339  * \param _o order by the specified column
00340  * \param _r result set
00341  * \return 0 on success, negative on failure
00342  */
00343 int db_postgres_query(const db_con_t* _h, const db_key_t* _k, const db_op_t* _op,
00344         const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
00345         const db_key_t _o, db_res_t** _r)
00346 {
00347    return db_do_query(_h, _k, _op, _v, _c, _n, _nc, _o, _r, db_postgres_val2str,
00348       db_postgres_submit_query, db_postgres_store_result);
00349 }
00350 
00351 
00352 /*!
00353  * Execute a raw SQL query
00354  * \param _h database connection
00355  * \param _s raw query string
00356  * \param _r result set
00357  * \return 0 on success, negative on failure
00358  */
00359 int db_postgres_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r)
00360 {
00361    return db_do_raw_query(_h, _s, _r, db_postgres_submit_query,
00362       db_postgres_store_result);
00363 }
00364 
00365 
00366 /*!
00367  * \brief Retrieve result set
00368  * \param _con structure representing the database connection
00369  * \param _r pointer to a structure represending the result set
00370  * \return 0 If the status of the last command produced a result set and,
00371  *   If the result set contains data or the convert_result() routine
00372  *   completed successfully. Negative if the status of the last command was
00373  * not handled or if the convert_result() returned an error.
00374  * \note A new result structure is allocated on every call to this routine.
00375  * If this routine returns 0, it is the callers responsbility to free the
00376  * result structure. If this routine returns < 0, then the result structure
00377  * is freed before returning to the caller.
00378  */
00379 int db_postgres_store_result(const db_con_t* _con, db_res_t** _r)
00380 {
00381    PGresult *res = NULL;
00382    ExecStatusType pqresult;
00383    int rc = 0;
00384 
00385    *_r = db_new_result();
00386    if (*_r==NULL) {
00387       LM_ERR("failed to init new result\n");
00388       rc = -1;
00389       goto done;
00390    }
00391 
00392    while (1) {
00393       if ((res = PQgetResult(CON_CONNECTION(_con)))) {
00394          CON_RESULT(_con) = res;
00395       } else {
00396          break;
00397       }
00398    }
00399 
00400    pqresult = PQresultStatus(CON_RESULT(_con));
00401    
00402    LM_DBG("%p PQresultStatus(%s) PQgetResult(%p)\n", _con,
00403       PQresStatus(pqresult), CON_RESULT(_con));
00404 
00405    switch(pqresult) {
00406       case PGRES_COMMAND_OK:
00407       /* Successful completion of a command returning no data
00408        * (such as INSERT or UPDATE). */
00409       rc = 0;
00410       break;
00411 
00412       case PGRES_TUPLES_OK:
00413          /* Successful completion of a command returning data
00414           * (such as a SELECT or SHOW). */
00415          if (db_postgres_convert_result(_con, *_r) < 0) {
00416             LM_ERR("error while converting result\n");
00417             LM_DBG("freeing result set at %p\n", _r);
00418             pkg_free(*_r);
00419             *_r = 0;
00420             rc = -4;
00421             break;
00422          }
00423          rc =  0;
00424          break;
00425       /* query failed */
00426       case PGRES_FATAL_ERROR:
00427          LM_ERR("invalid query, execution aborted\n");
00428          LM_ERR("driver error: %s, %s\n", PQresStatus(pqresult), PQresultErrorMessage(CON_RESULT(_con)));
00429          db_free_result(*_r);
00430          *_r = 0;
00431          rc = -3;
00432          break;
00433 
00434       case PGRES_EMPTY_QUERY:
00435       /* notice or warning */
00436       case PGRES_NONFATAL_ERROR:
00437       /* status for COPY command, not used */
00438       case PGRES_COPY_OUT:
00439       case PGRES_COPY_IN:
00440       /* unexpected response */
00441       case PGRES_BAD_RESPONSE:
00442       default:
00443          LM_ERR("probable invalid query, execution aborted\n");
00444          LM_ERR("driver message: %s, %s\n", PQresStatus(pqresult), PQresultErrorMessage(CON_RESULT(_con)));
00445          db_free_result(*_r);
00446          *_r = 0;
00447          rc = -4;
00448          break;
00449    }
00450 
00451 done:
00452    db_postgres_free_query(_con);
00453    return (rc);
00454 }
00455 
00456 
00457 /*!
00458  * \brief Insert a row into specified table
00459  * \param _h structure representing database connection
00460  * \param _k key names
00461  * \param _v values of the keys
00462  * \param _n number of key=value pairs
00463  * \return 0 on success, negative on failure
00464  */
00465 int db_postgres_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v,
00466       const int _n)
00467 {
00468    db_res_t* _r = NULL;
00469 
00470    int tmp = db_do_insert(_h, _k, _v, _n, db_postgres_val2str, db_postgres_submit_query);
00471    // finish the async query, otherwise the next query will not complete
00472    if (db_postgres_store_result(_h, &_r) != 0)
00473       LM_WARN("unexpected result returned");
00474    
00475    if (_r)
00476       db_free_result(_r);
00477 
00478    return tmp;
00479 }
00480 
00481 
00482 /*!
00483  * \brief Delete a row from the specified table
00484  * \param _h structure representing database connection
00485  * \param _k key names
00486  * \param _o operators
00487  * \param _v values of the keys that must match
00488  * \param _n number of key=value pairs
00489  * \return 0 on success, negative on failure
00490  */
00491 int db_postgres_delete(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
00492       const db_val_t* _v, const int _n)
00493 {
00494    db_res_t* _r = NULL;
00495    int tmp = db_do_delete(_h, _k, _o, _v, _n, db_postgres_val2str,
00496       db_postgres_submit_query);
00497 
00498    if (db_postgres_store_result(_h, &_r) != 0)
00499       LM_WARN("unexpected result returned");
00500    
00501    if (_r)
00502       db_free_result(_r);
00503 
00504    return tmp;
00505 }
00506 
00507 
00508 /*!
00509  * Update some rows in the specified table
00510  * \param _h structure representing database connection
00511  * \param _k key names
00512  * \param _o operators
00513  * \param _v values of the keys that must match
00514  * \param _uk updated columns
00515  * \param _uv updated values of the columns
00516  * \param _n number of key=value pairs
00517  * \param _un number of columns to update
00518  * \return 0 on success, negative on failure
00519  */
00520 int db_postgres_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
00521       const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv, const int _n,
00522       const int _un)
00523 {
00524    db_res_t* _r = NULL;
00525    int tmp = db_do_update(_h, _k, _o, _v, _uk, _uv, _n, _un, db_postgres_val2str,
00526       db_postgres_submit_query);
00527 
00528    if (db_postgres_store_result(_h, &_r) != 0)
00529       LM_WARN("unexpected result returned");
00530    
00531    if (_r)
00532       db_free_result(_r);
00533 
00534    return tmp;
00535 }
00536 
00537 
00538 /*!
00539  * Store name of table that will be used by subsequent database functions
00540  * \param _con database connection
00541  * \param _t table name
00542  * \return 0 on success, negative on error
00543  */
00544 int db_postgres_use_table(db_con_t* _con, const str* _t)
00545 {
00546    return db_use_table(_con, _t);
00547 }

Generated on Tue May 22 14:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6