db/db.c

Go to the documentation of this file.
00001 /*
00002  * $Id: db.c 5711 2009-03-16 13:15:28Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  * Copyright (C) 2007-2008 1&1 Internet AG
00006  * 
00007  * This file is part of Kamailio, a free SIP server.
00008  *
00009  * Kamailio is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * Kamailio is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License 
00020  * along with this program; if not, write to the Free Software 
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  */
00023  /*
00024   * History:
00025   * --------
00026   *  2004-06-06  bind_dbmod takes dbf as parameter (andrei)
00027   *  2006-10-10  Added support for retrieving the last inserted ID (Carsten Bock, BASIS AudioNet GmbH)
00028   */
00029 
00030 /**
00031  * \file db/db.c
00032  * \ingroup db
00033  * \brief Generic Database Interface
00034  *
00035  */
00036 /*! \defgroup db DB: The Kamailio generic database interface
00037  * This is a generic database interface for modules that need to utilize a
00038  * database. The interface should be used by all modules that access database.
00039  * The interface will be independent of the underlying database server.
00040  * Notes:
00041  * If possible, use the predefined macros if you need to access any structure
00042  * attributes.
00043  * For additional description, see the comments in the sources of mysql module.
00044  *
00045  * If you want to see more complicated examples of how the API could be used,
00046  * take a look at the sources of the usrloc or auth modules.
00047  * - \ref usrloc
00048  * - \ref auth
00049  *
00050  * Implemented modules
00051  * - \ref ../modules/db_berkeley
00052  * - \ref ../modules/db_flatstore
00053  * - \ref ../modules/db_text
00054  * - \ref ../modules/db_mysql
00055  * - \ref ../modules/db_oracle
00056  * - \ref ../modules/db_postgres
00057  * - \ref ../modules/db_unixodbc
00058  */
00059 
00060 #include "../dprint.h"
00061 #include "../sr_module.h"
00062 #include "../mem/mem.h"
00063 #include "../ut.h"
00064 #include "db_cap.h"
00065 #include "db_id.h"
00066 #include "db_pool.h"
00067 #include "db.h"
00068 
00069 static unsigned int MAX_URL_LENGTH = 255; /*!< maximum length of a SQL URL */
00070 
00071 
00072 int db_check_api(db_func_t* dbf, char *mname)
00073 {
00074    if(dbf==NULL)
00075       return -1;
00076 
00077    /* All modules must export db_use_table */
00078    if (dbf->use_table == 0) {
00079       LM_ERR("module %s does not export db_use_table function\n", mname);
00080       goto error;
00081    }
00082 
00083    /* All modules must export db_init */
00084    if (dbf->init == 0) {
00085       LM_ERR("module %s does not export db_init function\n", mname);
00086       goto error;
00087    }
00088 
00089    /* All modules must export db_close */
00090    if (dbf->close == 0) {
00091       LM_ERR("module %s does not export db_close function\n", mname);
00092       goto error;
00093    }
00094 
00095    if (dbf->query) {
00096       dbf->cap |= DB_CAP_QUERY;
00097    }
00098 
00099    if (dbf->fetch_result) {
00100       dbf->cap |= DB_CAP_FETCH;
00101    }
00102 
00103    if (dbf->raw_query) {
00104       dbf->cap |= DB_CAP_RAW_QUERY;
00105    }
00106 
00107    /* Free result must be exported if DB_CAP_QUERY or
00108     * DB_CAP_RAW_QUERY is set */
00109    if ((dbf->cap & (DB_CAP_QUERY|DB_CAP_RAW_QUERY)) && (dbf->free_result==0)) {
00110       LM_ERR("module %s supports queries but does not export free_result\n",
00111             mname);
00112       goto error;
00113    }
00114 
00115    if (dbf->insert) {
00116       dbf->cap |= DB_CAP_INSERT;
00117    }
00118 
00119    if (dbf->delete) {
00120       dbf->cap |= DB_CAP_DELETE;
00121    }
00122 
00123    if (dbf->update) {
00124       dbf->cap |= DB_CAP_UPDATE;
00125    }
00126 
00127    if (dbf->replace) {
00128       dbf->cap |= DB_CAP_REPLACE;
00129    }
00130 
00131    if (dbf->last_inserted_id) {
00132       dbf->cap |= DB_CAP_LAST_INSERTED_ID;
00133    }
00134 
00135    if (dbf->insert_update) {
00136       dbf->cap |= DB_CAP_INSERT_UPDATE;
00137    }
00138    return 0;
00139 error:
00140    return -1;
00141 }
00142 
00143 /*! \brief fills mydbf with the corresponding db module callbacks
00144  * \param mod
00145  * \param mydbf
00146  * \return returns 0 on success, -1 on error
00147  * \note on error mydbf will contain only 0s */
00148 int db_bind_mod(const str* mod, db_func_t* mydbf)
00149 {
00150    char *name, *tmp, *p;
00151    int len;
00152    db_func_t dbf;
00153    db_bind_api_f dbind;
00154 
00155    if (!mod || !mod->s) {
00156       LM_CRIT("null database module name\n");
00157       return -1;
00158    }
00159    if (mydbf==0) {
00160       LM_CRIT("null dbf parameter\n");
00161       return -1;
00162    }
00163    if (mod->len > MAX_URL_LENGTH)
00164    {
00165       LM_ERR("SQL URL too long\n");
00166       return 0;
00167    }
00168    // add the prefix
00169    name = pkg_malloc(mod->len + 4);
00170    if (!name) {
00171       LM_ERR("no private memory left\n");
00172       return -1;
00173    }
00174    memcpy(name, "db_", 3);
00175    memcpy(name+3, mod->s, mod->len);
00176    name[mod->len+3] = 0;
00177 
00178    /* for safety we initialize mydbf with 0 (this will cause
00179     *  a segfault immediately if someone tries to call a function
00180     *  from it without checking the return code from bind_dbmod */
00181    memset((void*)mydbf, 0, sizeof(db_func_t));
00182 
00183    p = strchr(name, ':');
00184    if (p) {
00185       len = p - name;
00186       tmp = (char*)pkg_malloc(len + 4);
00187       if (!tmp) {
00188          LM_ERR("no private memory left\n");
00189          pkg_free(name);
00190          return -1;
00191       }
00192       memcpy(tmp, name, len);
00193       tmp[len] = '\0';
00194       pkg_free(name);
00195    } else {
00196       tmp = name;
00197    }
00198 
00199    dbind = (db_bind_api_f)find_mod_export(tmp, "db_bind_api", 0, 0);
00200    if(dbind != NULL)
00201    {
00202       LM_DBG("using db bind api for %s\n", tmp);
00203       if(dbind(&dbf)<0)
00204       {
00205          LM_ERR("db_bind_api returned error for module %s\n", tmp);
00206          goto error;
00207       }
00208    } else {
00209       memset(&dbf, 0, sizeof(db_func_t));
00210       LM_DBG("using export interface to bind %s\n", tmp);
00211       dbf.use_table = (db_use_table_f)find_mod_export(tmp,
00212          "db_use_table", 2, 0);
00213       dbf.init = (db_init_f)find_mod_export(tmp, "db_init", 1, 0);
00214       dbf.close = (db_close_f)find_mod_export(tmp, "db_close", 2, 0);
00215       dbf.query = (db_query_f)find_mod_export(tmp, "db_query", 2, 0);
00216       dbf.fetch_result = (db_fetch_result_f)find_mod_export(tmp,
00217          "db_fetch_result", 2, 0);
00218       dbf.raw_query = (db_raw_query_f)find_mod_export(tmp,
00219          "db_raw_query", 2, 0);
00220       dbf.free_result = (db_free_result_f)find_mod_export(tmp,
00221          "db_free_result", 2, 0);
00222       dbf.insert = (db_insert_f)find_mod_export(tmp, "db_insert", 2, 0);
00223       dbf.delete = (db_delete_f)find_mod_export(tmp, "db_delete", 2, 0);
00224       dbf.update = (db_update_f)find_mod_export(tmp, "db_update", 2, 0);
00225       dbf.replace = (db_replace_f)find_mod_export(tmp, "db_replace", 2, 0);
00226       dbf.last_inserted_id= (db_last_inserted_id_f)find_mod_export(tmp,
00227          "db_last_inserted_id", 1, 0);
00228       dbf.insert_update = (db_insert_update_f)find_mod_export(tmp,
00229          "db_insert_update", 2, 0);
00230    }
00231    if(db_check_api(&dbf, tmp)!=0)
00232       goto error;
00233 
00234    *mydbf=dbf; /* copy */
00235    pkg_free(tmp);
00236    return 0;
00237 
00238 error:
00239    pkg_free(tmp);
00240    return -1;
00241 }
00242 
00243 
00244 /*! \brief
00245  * Initialize database module
00246  * \note No function should be called before this
00247  */
00248 db_con_t* db_do_init(const str* url, void* (*new_connection)())
00249 {
00250    struct db_id* id;
00251    void* con;
00252    db_con_t* res;
00253 
00254    int con_size = sizeof(db_con_t) + sizeof(void *);
00255    id = 0;
00256    res = 0;
00257 
00258    if (!url || !url->s || !new_connection) {
00259       LM_ERR("invalid parameter value\n");
00260       return 0;
00261    }
00262    if (url->len > MAX_URL_LENGTH)
00263    {
00264       LM_ERR("The configured db_url is too long\n");
00265       return 0;
00266    }
00267    
00268    /* this is the root memory for this database connection. */
00269    res = (db_con_t*)pkg_malloc(con_size);
00270    if (!res) {
00271       LM_ERR("no private memory left\n");
00272       return 0;
00273    }
00274    memset(res, 0, con_size);
00275 
00276    id = new_db_id(url);
00277    if (!id) {
00278       LM_ERR("cannot parse URL '%.*s'\n", url->len, url->s);
00279       goto err;
00280    }
00281 
00282    /* Find the connection in the pool */
00283    con = pool_get(id);
00284    if (!con) {
00285       LM_DBG("connection %p not found in pool\n", id);
00286       /* Not in the pool yet */
00287       con = new_connection(id);
00288       if (!con) {
00289          LM_ERR("could not add connection to the pool\n");
00290          goto err;
00291       }
00292       pool_insert((struct pool_con*)con);
00293    } else {
00294       LM_DBG("connection %p found in pool\n", id);
00295    }
00296 
00297    res->tail = (unsigned long)con;
00298    return res;
00299 
00300  err:
00301    if (id) free_db_id(id);
00302    if (res) pkg_free(res);
00303    return 0;
00304 }
00305 
00306 
00307 /*! \brief
00308  * Shut down database module
00309  * \note No function should be called after this
00310  */
00311 void db_do_close(db_con_t* _h, void (*free_connection)())
00312 {
00313    struct pool_con* con;
00314 
00315    if (!_h || !_h->tail) {
00316       LM_ERR("invalid parameter value\n");
00317       return;
00318    }
00319 
00320    con = (struct pool_con*)_h->tail;
00321    if (pool_remove(con) == 1) {
00322       free_connection(con);
00323    }
00324 
00325    pkg_free(_h);
00326 }
00327 
00328 
00329 
00330 /*! \brief
00331  * Get version of a table
00332  * \param dbf
00333  * \param connection
00334  * \param table
00335  * \return If there is no row for the given table, return version 0
00336  */
00337 int db_table_version(const db_func_t* dbf, db_con_t* connection, const str* table)
00338 {
00339    db_key_t key[1], col[1];
00340    db_val_t val[1];
00341    db_res_t* res = NULL;
00342    db_val_t* ver = 0;
00343 
00344    if (!dbf||!connection || !table || !table->s) {
00345       LM_CRIT("invalid parameter value\n");
00346       return -1;
00347    }
00348 
00349    str version = str_init(VERSION_TABLE);
00350    int ret;
00351 
00352    if (dbf->use_table(connection, &version) < 0) {
00353       LM_ERR("error while changing table\n");
00354       return -1;
00355    }
00356    str tmp1 = str_init(TABLENAME_COLUMN);
00357    key[0] = &tmp1;
00358 
00359    VAL_TYPE(val) = DB_STR;
00360    VAL_NULL(val) = 0;
00361    VAL_STR(val) = *table;
00362    
00363    str tmp2 = str_init(VERSION_COLUMN);
00364    col[0] = &tmp2;
00365    
00366    if (dbf->query(connection, key, 0, val, col, 1, 1, 0, &res) < 0) {
00367       LM_ERR("error in db_query\n");
00368       return -1;
00369    }
00370 
00371    if (RES_ROW_N(res) == 0) {
00372       LM_DBG("no row for table %.*s found\n",
00373          table->len, ZSW(table->s));
00374       return 0;
00375    }
00376 
00377    if (RES_ROW_N(res) != 1) {
00378       LM_ERR("invalid number of rows received:"
00379          " %d, %.*s\n", RES_ROW_N(res), table->len, ZSW(table->s));
00380       dbf->free_result(connection, res);
00381       return -1;
00382    }
00383 
00384    ver = ROW_VALUES(RES_ROWS(res));
00385    if ( VAL_TYPE(ver)!=DB_INT || VAL_NULL(ver) ) {
00386       LM_ERR("invalid type (%d) or nul (%d) version "
00387          "columns for %.*s\n", VAL_TYPE(ver), VAL_NULL(ver),
00388          table->len, ZSW(table->s));
00389       dbf->free_result(connection, res);
00390       return -1;
00391    }
00392 
00393    ret = VAL_INT(ver);
00394    dbf->free_result(connection, res);
00395    return ret;
00396 }
00397 
00398 /*! \brief
00399  * Check the table version
00400  * 0 means ok, -1 means an error occured
00401  */
00402 int db_check_table_version(db_func_t* dbf, db_con_t* dbh, const str* table, const unsigned int version)
00403 {
00404    int ver = db_table_version(dbf, dbh, table);
00405    if (ver < 0) {
00406       LM_ERR("querying version for table %.*s\n", table->len, table->s);
00407       return -1;
00408    } else if (ver != version) {
00409       LM_ERR("invalid version %d for table %.*s found, expected %d (check table structure and table \"version\")\n", ver, table->len, table->s, version);
00410       return -1;
00411    }
00412    return 0;
00413 }
00414 
00415 /*! \brief
00416  * Store name of table that will be used by
00417  * subsequent database functions
00418  */
00419 int db_use_table(db_con_t* _h, const str* _t)
00420 {
00421    if (!_h || !_t || !_t->s) {
00422       LM_ERR("invalid parameter value\n");
00423       return -1;
00424    }
00425 
00426    CON_TABLE(_h) = _t;
00427    return 0;
00428 }

Generated on Mon May 21 18:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6