lib/srdb1/db.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
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 
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_query.h"
00068 #include "db.h"
00069 
00070 static unsigned int MAX_URL_LENGTH = 255;       
00073 int db_check_api(db_func_t* dbf, char *mname)
00074 {
00075         if(dbf==NULL)
00076                 return -1;
00077 
00078         /* All modules must export db_use_table */
00079         if (dbf->use_table == 0) {
00080                 LM_ERR("module %s does not export db_use_table function\n", mname);
00081                 goto error;
00082         }
00083 
00084         /* All modules must export db_init */
00085         if (dbf->init == 0) {
00086                 LM_ERR("module %s does not export db_init function\n", mname);
00087                 goto error;
00088         }
00089 
00090         /* All modules must export db_close */
00091         if (dbf->close == 0) {
00092                 LM_ERR("module %s does not export db_close function\n", mname);
00093                 goto error;
00094         }
00095 
00096         if (dbf->query) {
00097                 dbf->cap |= DB_CAP_QUERY;
00098         }
00099 
00100         if (dbf->fetch_result) {
00101                 dbf->cap |= DB_CAP_FETCH;
00102         }
00103 
00104         if (dbf->raw_query) {
00105                 dbf->cap |= DB_CAP_RAW_QUERY;
00106         }
00107 
00108         /* Free result must be exported if DB_CAP_QUERY or
00109          * DB_CAP_RAW_QUERY is set */
00110         if ((dbf->cap & (DB_CAP_QUERY|DB_CAP_RAW_QUERY)) && (dbf->free_result==0)) {
00111                 LM_ERR("module %s supports queries but does not export free_result\n",
00112                                 mname);
00113                 goto error;
00114         }
00115 
00116         if (dbf->insert) {
00117                 dbf->cap |= DB_CAP_INSERT;
00118         }
00119 
00120         if (dbf->delete) {
00121                 dbf->cap |= DB_CAP_DELETE;
00122         }
00123 
00124         if (dbf->update) {
00125                 dbf->cap |= DB_CAP_UPDATE;
00126         }
00127 
00128         if (dbf->replace) {
00129                 dbf->cap |= DB_CAP_REPLACE;
00130         }
00131 
00132         if (dbf->last_inserted_id) {
00133                 dbf->cap |= DB_CAP_LAST_INSERTED_ID;
00134         }
00135 
00136         if (dbf->insert_update) {
00137                 dbf->cap |= DB_CAP_INSERT_UPDATE;
00138         }
00139 
00140         if (dbf->insert_delayed) {
00141                 dbf->cap |= DB_CAP_INSERT_DELAYED;
00142         }
00143 
00144         if (dbf->affected_rows) {
00145                 dbf->cap |= DB_CAP_AFFECTED_ROWS;
00146         }
00147 
00148         return 0;
00149 error:
00150         return -1;
00151 }
00152 
00158 int db_bind_mod(const str* mod, db_func_t* mydbf)
00159 {
00160         char *name, *tmp, *p;
00161         int len;
00162         db_func_t dbf;
00163         db_bind_api_f dbind;
00164 
00165         if (!mod || !mod->s) {
00166                 LM_CRIT("null database module name\n");
00167                 return -1;
00168         }
00169         if (mydbf==0) {
00170                 LM_CRIT("null dbf parameter\n");
00171                 return -1;
00172         }
00173         if (mod->len > MAX_URL_LENGTH)
00174         {
00175                 LM_ERR("SQL URL too long\n");
00176                 return -1;
00177         }
00178         // add the prefix
00179         name = pkg_malloc(mod->len + 4);
00180         if (!name) {
00181                 LM_ERR("no private memory left\n");
00182                 return -1;
00183         }
00184         memcpy(name, "db_", 3);
00185         memcpy(name+3, mod->s, mod->len);
00186         name[mod->len+3] = 0;
00187 
00188         /* for safety we initialize mydbf with 0 (this will cause
00189          *  a segfault immediately if someone tries to call a function
00190          *  from it without checking the return code from bind_dbmod */
00191         memset((void*)mydbf, 0, sizeof(db_func_t));
00192 
00193         p = strchr(name, ':');
00194         if (p) {
00195                 len = p - name;
00196                 tmp = (char*)pkg_malloc(len + 4);
00197                 if (!tmp) {
00198                         LM_ERR("no private memory left\n");
00199                         pkg_free(name);
00200                         return -1;
00201                 }
00202                 memcpy(tmp, name, len);
00203                 tmp[len] = '\0';
00204                 pkg_free(name);
00205         } else {
00206                 tmp = name;
00207         }
00208 
00209         dbind = (db_bind_api_f)find_mod_export(tmp, "db_bind_api", 0, 0);
00210         if(dbind != NULL)
00211         {
00212                 LM_DBG("using db bind api for %s\n", tmp);
00213                 if(dbind(&dbf)<0)
00214                 {
00215                         LM_ERR("db_bind_api returned error for module %s\n", tmp);
00216                         goto error;
00217                 }
00218         } else {
00219                 memset(&dbf, 0, sizeof(db_func_t));
00220                 LM_DBG("using export interface to bind %s\n", tmp);
00221                 dbf.use_table = (db_use_table_f)find_mod_export(tmp,
00222                         "db_use_table", 2, 0);
00223                 dbf.init = (db_init_f)find_mod_export(tmp, "db_init", 1, 0);
00224                 dbf.init2 = (db_init2_f)find_mod_export(tmp, "db_init2", 1, 0);
00225                 dbf.close = (db_close_f)find_mod_export(tmp, "db_close", 2, 0);
00226                 dbf.query = (db_query_f)find_mod_export(tmp, "db_query", 2, 0);
00227                 dbf.fetch_result = (db_fetch_result_f)find_mod_export(tmp,
00228                         "db_fetch_result", 2, 0);
00229                 dbf.raw_query = (db_raw_query_f)find_mod_export(tmp,
00230                         "db_raw_query", 2, 0);
00231                 dbf.free_result = (db_free_result_f)find_mod_export(tmp,
00232                         "db_free_result", 2, 0);
00233                 dbf.insert = (db_insert_f)find_mod_export(tmp, "db_insert", 2, 0);
00234                 dbf.delete = (db_delete_f)find_mod_export(tmp, "db_delete", 2, 0);
00235                 dbf.update = (db_update_f)find_mod_export(tmp, "db_update", 2, 0);
00236                 dbf.replace = (db_replace_f)find_mod_export(tmp, "db_replace", 2, 0);
00237                 dbf.last_inserted_id= (db_last_inserted_id_f)find_mod_export(tmp,
00238                         "db_last_inserted_id", 1, 0);
00239                 dbf.affected_rows = (db_affected_rows_f)find_mod_export(tmp,
00240                         "db_affected_rows", 1, 0);
00241                 dbf.insert_update = (db_insert_update_f)find_mod_export(tmp,
00242                         "db_insert_update", 2, 0);
00243                 dbf.insert_delayed = (db_insert_delayed_f)find_mod_export(tmp,
00244                         "db_insert_delayed", 2, 0);
00245                 dbf.start_transaction = (db_start_transaction_f)find_mod_export(tmp,
00246                         "db_start_transaction", 1, 0);
00247                 dbf.end_transaction = (db_end_transaction_f)find_mod_export(tmp,
00248                         "db_end_transaction", 1, 0);
00249                 dbf.abort_transaction = (db_abort_transaction_f)find_mod_export(tmp,
00250                         "db_abort_transaction", 1, 0);
00251         }
00252         if(db_check_api(&dbf, tmp)!=0)
00253                 goto error;
00254 
00255         *mydbf=dbf; /* copy */
00256         pkg_free(tmp);
00257         return 0;
00258 
00259 error:
00260         pkg_free(tmp);
00261         return -1;
00262 }
00263 
00264 
00269 db1_con_t* db_do_init(const str* url, void* (*new_connection)())
00270 {
00271         return db_do_init2(url, *new_connection, DB_POOLING_PERMITTED);
00272 }
00273 
00274 
00279 db1_con_t* db_do_init2(const str* url, void* (*new_connection)(), db_pooling_t pooling)
00280 {
00281         struct db_id* id;
00282         void* con;
00283         db1_con_t* res;
00284 
00285         int con_size = sizeof(db1_con_t) + sizeof(void *);
00286         id = 0;
00287         res = 0;
00288 
00289         if (!url || !url->s || !new_connection) {
00290                 LM_ERR("invalid parameter value\n");
00291                 return 0;
00292         }
00293         if (url->len > MAX_URL_LENGTH)
00294         {
00295                 LM_ERR("The configured db_url is too long\n");
00296                 return 0;
00297         }
00298         
00299         /* this is the root memory for this database connection. */
00300         res = (db1_con_t*)pkg_malloc(con_size);
00301         if (!res) {
00302                 LM_ERR("no private memory left\n");
00303                 return 0;
00304         }
00305         memset(res, 0, con_size);
00306 
00307         id = new_db_id(url, pooling);
00308         if (!id) {
00309                 LM_ERR("cannot parse URL '%.*s'\n", url->len, url->s);
00310                 goto err;
00311         }
00312 
00313         /* Find the connection in the pool */
00314         con = pool_get(id);
00315         if (!con) {
00316                 LM_DBG("connection %p not found in pool\n", id);
00317                 /* Not in the pool yet */
00318                 con = new_connection(id);
00319                 if (!con) {
00320                         LM_ERR("could not add connection to the pool");
00321                         goto err;
00322                 }
00323                 pool_insert((struct pool_con*)con);
00324         } else {
00325                 LM_DBG("connection %p found in pool\n", id);
00326         }
00327 
00328         res->tail = (unsigned long)con;
00329         return res;
00330 
00331  err:
00332         if (id) free_db_id(id);
00333         if (res) pkg_free(res);
00334         return 0;
00335 }
00336 
00337 
00342 void db_do_close(db1_con_t* _h, void (*free_connection)())
00343 {
00344         struct pool_con* con;
00345 
00346         if (!_h || !_h->tail) {
00347                 LM_ERR("invalid parameter value\n");
00348                 return;
00349         }
00350 
00351         con = (struct pool_con*)_h->tail;
00352         if (pool_remove(con) == 1) {
00353                 free_connection(con);
00354         }
00355 
00356         pkg_free(_h);
00357 }
00358 
00359 
00360 
00368 int db_table_version(const db_func_t* dbf, db1_con_t* connection, const str* table)
00369 {
00370         db_key_t key[1], col[1];
00371         db_val_t val[1];
00372         db1_res_t* res = NULL;
00373         db_val_t* ver = 0;
00374         str version = str_init(VERSION_TABLE);
00375         str tmp1 = str_init(TABLENAME_COLUMN);
00376         str tmp2 = str_init(VERSION_COLUMN);
00377         int ret;
00378 
00379         if (!dbf||!connection || !table || !table->s) {
00380                 LM_CRIT("invalid parameter value\n");
00381                 return -1;
00382         }
00383 
00384         if (dbf->use_table(connection, &version) < 0) {
00385                 LM_ERR("error while changing table\n");
00386                 return -1;
00387         }
00388         key[0] = &tmp1;
00389 
00390         VAL_TYPE(val) = DB1_STR;
00391         VAL_NULL(val) = 0;
00392         VAL_STR(val) = *table;
00393         
00394         col[0] = &tmp2;
00395         
00396         if (dbf->query(connection, key, 0, val, col, 1, 1, 0, &res) < 0) {
00397                 LM_ERR("error in db_query\n");
00398                 return -1;
00399         }
00400 
00401         if (RES_ROW_N(res) == 0) {
00402                 LM_DBG("no row for table %.*s found\n",
00403                         table->len, ZSW(table->s));
00404                 return 0;
00405         }
00406 
00407         if (RES_ROW_N(res) != 1) {
00408                 LM_ERR("invalid number of rows received:"
00409                         " %d, %.*s\n", RES_ROW_N(res), table->len, ZSW(table->s));
00410                 dbf->free_result(connection, res);
00411                 return -1;
00412         }
00413 
00414         ver = ROW_VALUES(RES_ROWS(res));
00415         if ( VAL_TYPE(ver)!=DB1_INT || VAL_NULL(ver) ) {
00416                 LM_ERR("invalid type (%d) or nul (%d) version "
00417                         "columns for %.*s\n", VAL_TYPE(ver), VAL_NULL(ver),
00418                         table->len, ZSW(table->s));
00419                 dbf->free_result(connection, res);
00420                 return -1;
00421         }
00422 
00423         ret = VAL_INT(ver);
00424         dbf->free_result(connection, res);
00425         return ret;
00426 }
00427 
00432 int db_check_table_version(db_func_t* dbf, db1_con_t* dbh, const str* table, const unsigned int version)
00433 {
00434         int ver = db_table_version(dbf, dbh, table);
00435         if (ver < 0) {
00436                 LM_ERR("querying version for table %.*s\n", table->len, table->s);
00437                 return -1;
00438         } else if (ver != version) {
00439                 LM_ERR("invalid version %d for table %.*s found, expected %d (check table structure and table \"version\")\n", ver, table->len, table->s, version);
00440                 return -1;
00441         }
00442         return 0;
00443 }
00444 
00449 int db_use_table(db1_con_t* _h, const str* _t)
00450 {
00451         if (!_h || !_t || !_t->s) {
00452                 LM_ERR("invalid parameter value\n");
00453                 return -1;
00454         }
00455 
00456         CON_TABLE(_h) = _t;
00457         return 0;
00458 }
00459 
00460 
00474 int db_load_bulk_data(db_func_t* binding, db1_con_t* handle, str* name, db_key_t* cols,
00475                       unsigned int count, unsigned int strict, db1_res_t* res)
00476 {
00477         if (binding == NULL) {
00478                 LM_ERR("invalid database module binding\n");
00479                 return -1;
00480         }
00481 
00482         if(handle == NULL) {
00483                 LM_ERR("invalid database handle\n");
00484                 return -1;
00485         }
00486 
00487         if (binding->use_table(handle, name) < 0) {
00488                 LM_ERR("error in use_table for database\n");
00489                 return -1;
00490         }
00491 
00492         /* select the whole table and all the columns */
00493         if(binding->query(handle, 0, 0, 0, cols, 0, count, 0, &res) < 0) {
00494                 LM_ERR("error while querying database\n");
00495                 return -1;
00496         }
00497 
00498         if(RES_ROW_N(res) == 0) {
00499                 binding->free_result(handle, res);
00500                 if (strict == 1) {
00501                         LM_ERR("no data in the database table %.*s\n", name->len, name->s);
00502                         return -1;
00503                 } else {
00504                         LM_WARN("no data in the database table %.*s, use an empty set\n", name->len, name->s);
00505                         return 0;
00506                 }
00507         }
00508 
00509         return 0;
00510 }
00511 
00519 int db_api_init(void)
00520 {
00521         if(db_query_init()<0)
00522                 return -1;
00523         return 0;
00524 }