bdb_base.c

00001 /* $Id$
00002  *
00003  * Copyright (C) 2006-2007 Sippy Software, Inc. <sales@sippysoft.com>
00004  *
00005  * This file is part of ser, a free SIP server.
00006  *
00007  * ser is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version
00011  *
00012  * For a license to use the ser software under conditions
00013  * other than those described here, or to purchase support for this
00014  * software, please contact iptel.org by e-mail at the following addresses:
00015  *    info@iptel.org
00016  *
00017  * ser is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025  *
00026  */
00027 
00028 
00029 #include "bdb.h"
00030 
00031 #define BDB_ID          "bdb://"
00032 #define BDB_ID_LEN      (sizeof(BDB_ID)-1)
00033 #define BDB_PATH_LEN    MAXPATHLEN
00034 
00035 /*
00036  * Initialize database connection
00037  */
00038 db_con_t* bdb_init(const char* _sqlurl)
00039 {
00040         db_con_t* _res;
00041         char *p;
00042         char bdb_path[BDB_PATH_LEN];
00043         int ret;
00044 
00045         if (!_sqlurl)
00046         {
00047 #ifdef BDB_EXTRA_DEBUG
00048                 LOG(L_ERR, "BDB:bdb_init: Invalid parameter value\n");
00049 #endif
00050                 return NULL;
00051         }
00052         p = (char *)_sqlurl;
00053         if(strncmp(p, BDB_ID, sizeof(BDB_ID) - 1))
00054         {
00055                 LOG(L_ERR, "BDB:bdb_init: invalid database URL - should be:"
00056                         " <%s[/]path/to/directory>\n", BDB_ID);
00057                 return NULL;
00058         }
00059         p += BDB_ID_LEN;
00060         if(p[0] != '/')
00061         {
00062                 if(sizeof(CFG_DIR) + strlen(p) + 2 > BDB_PATH_LEN)
00063                 {
00064                         LOG(L_ERR, "BDB:bdb_init: path to database is too long\n");
00065                         return NULL;
00066                 }
00067                 strcpy(bdb_path, CFG_DIR);
00068                 bdb_path[sizeof(CFG_DIR) - 1] = '/';
00069                 strcpy(&bdb_path[sizeof(CFG_DIR)], p);
00070                 p = bdb_path;
00071         }
00072 #ifdef BDB_EXTRA_DEBUG
00073         LOG(L_NOTICE, "BDB:bdb_init: bdb_path = %s\n", p);
00074 #endif
00075 
00076         _res = pkg_malloc(sizeof(db_con_t) + sizeof(bdb_con_t));
00077         if (!_res)
00078         {
00079                 LOG(L_ERR, "BDB:bdb_init: No memory left\n");
00080                 return NULL;
00081         }
00082         memset(_res, 0, sizeof(db_con_t) + sizeof(bdb_con_t));
00083         _res->tail = (unsigned long)((char*)_res + sizeof(bdb_con_t));
00084 
00085         ret = db_env_create(&BDB_CON_DBENV(_res), 0);
00086         if (ret != 0) {
00087                 LOG(L_ERR, "BDB:bdb_init: unable to db_env_create(): %s\n", db_strerror(ret));
00088 
00089                 pkg_free(_res);
00090                 return NULL;
00091         }
00092 
00093         ret = BDB_CON_DBENV(_res)->open(BDB_CON_DBENV(_res), p, DB_CREATE | DB_INIT_MPOOL | DB_INIT_CDB, 0);
00094         if (ret != 0) {
00095                 LOG(L_ERR, "BDB:bdb_init: unable to open environment: %s\n", db_strerror(ret));
00096 
00097                 pkg_free(_res);
00098                 return NULL;
00099         }
00100 
00101         return _res;
00102 }
00103 
00104 /*
00105  * Close a database connection
00106  */
00107 void bdb_close(db_con_t* _h)
00108 {
00109         if (!_h)
00110         {
00111 #ifdef DBT_EXTRA_DEBUG
00112                 LOG(L_ERR, "BDB:bdb_close: Invalid parameter value\n");
00113 #endif
00114                 return;
00115         }
00116 
00117         if (BDB_CON_DB(_h) != NULL) {
00118                 bdb_close_table(_h);
00119         }
00120 
00121         if (BDB_CON_DBENV(_h) != NULL) {
00122                 BDB_CON_DBENV(_h)->close(BDB_CON_DBENV(_h), 0);
00123         }
00124 
00125         pkg_free(_h);
00126 
00127         return;
00128 }
00129 
00130 
00131 /*
00132  * Raw SQL query -- is not the case to have this method
00133  */
00134 int bdb_raw_query(db_con_t* _h, char* _s, db_res_t** _r)
00135 {
00136     *_r = NULL;
00137     LOG(L_ERR, "BDB:bdb_raw_query: method is not supported.\n");
00138     return -1;
00139 }
00140 
00141 
00142 /*
00143  * Query table for specified rows
00144  * _h: structure representing database connection
00145  * _k: key names
00146  * _op: operators
00147  * _v: values of the keys that must match
00148  * _c: column names to return
00149  * _n: number of key=values pairs to compare
00150  * _nc: number of columns to return
00151  * _o: order by the specified column
00152  */
00153 
00154 int bdb_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v,
00155                 db_key_t* _c, int _n, int _nc, db_key_t _o, db_res_t** _r)
00156 {
00157         bdb_srow_p      s_r;            /* search keys row */
00158         bdb_rrow_p      r_r;            /* return keys row */
00159         int             ret;
00160 
00161         *_r = NULL;
00162         s_r = NULL;
00163         r_r = NULL;
00164 
00165         if (_o) {
00166                 LOG(L_ERR, "BDB:bdb_query: ORDER BY is not supported.\n");
00167                 return -1;
00168         }
00169 
00170         if ((ret = bdb_srow_db2bdb(_h, _k, _op, _v, _n, &s_r)) < 0) {
00171                 return -1;
00172         };
00173 
00174         if ((ret = bdb_rrow_db2bdb(_h, _c, _nc, &r_r)) < 0) {
00175                 bdb_free_srow(s_r);
00176                 return -1;
00177         };
00178 
00179         if ((ret = bdb_query_table(_h, s_r, r_r, _nc, _r)) < 0) {
00180                 bdb_free_rrow(r_r);
00181                 bdb_free_srow(s_r);
00182                 return -1;
00183         };
00184 
00185         bdb_free_rrow(r_r);
00186         bdb_free_srow(s_r);
00187 
00188         return 0;
00189 }
00190 
00191 
00192 /*
00193  * Insert a row into table
00194  */
00195 int bdb_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n)
00196 {
00197         bdb_row_p       r;
00198         DBC             *cursorp;
00199         int             ret;
00200 
00201         if ((ret = bdb_row_db2bdb(_h, _k, _v, _n, &r)) < 0) {
00202                 return -1;
00203         };
00204 
00205         if (r->key.size == 0) {
00206                 LOG(L_ERR, "BDB:bdb_insert: no primary key specified\n");
00207                 bdb_free_row(r);
00208                 return -1;
00209         }
00210 
00211         BDB_CON_DB(_h)->cursor(BDB_CON_DB(_h), NULL, &cursorp, DB_WRITECURSOR);
00212         ret = cursorp->c_put(cursorp, &(r->key), &(r->data), DB_KEYLAST);
00213 
00214         if (ret < 0) {
00215                 LOG(L_ERR, "BDB:bdb_insert: unable to insert record: %s\n", db_strerror(ret));
00216         }
00217 
00218         if (cursorp != NULL) {
00219                 cursorp->c_close(cursorp);
00220         }
00221 
00222         bdb_free_row(r);
00223 
00224         return ret;
00225 }
00226 
00227 
00228 /*
00229  * Delete a row from table
00230  */
00231 int bdb_delete(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, int _n)
00232 {
00233         bdb_srow_p      s_r;            /* search keys row */
00234         int             ret;
00235 
00236         s_r = NULL;
00237 
00238         if ((ret = bdb_srow_db2bdb(_h, _k, _o, _v, _n, &s_r)) < 0) {
00239                 return -1;
00240         };
00241 
00242         if ((ret = bdb_delete_table(_h, s_r)) < 0) {
00243                 bdb_free_srow(s_r);
00244                 return -1;
00245         };
00246 
00247         bdb_free_srow(s_r);
00248 
00249         return 0;
00250 }
00251 
00252 /*
00253  * Update a row in table
00254  */
00255 int bdb_update(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v,
00256               db_key_t* _uk, db_val_t* _uv, int _n, int _un)
00257 {
00258         bdb_srow_p      s_r;            /* search keys row */
00259         bdb_urow_p      u_r;            /* update row */
00260         int             ret;
00261 
00262         s_r = NULL;
00263         u_r = NULL;
00264 
00265         if ((ret = bdb_srow_db2bdb(_h, _k, _o, _v, _n, &s_r)) < 0) {
00266                 return -1;
00267         };
00268 
00269         if ((ret = bdb_urow_db2bdb(_h, _uk, _uv, _un, &u_r)) < 0) {
00270                 bdb_free_srow(s_r);
00271                 return -1;
00272         };
00273 
00274         if ((ret = bdb_update_table(_h, s_r, u_r)) < 0) {
00275                 bdb_free_urow(u_r);
00276                 bdb_free_srow(s_r);
00277                 return -1;
00278         };
00279 
00280         bdb_free_urow(u_r);
00281         bdb_free_srow(s_r);
00282 
00283         return 0;
00284 }
00285 
00286 /*
00287  * Free all memory allocated by get_result
00288  */
00289 int bdb_free_result(db_con_t* _h, db_res_t* _r)
00290 {
00291         db_row_t* r;
00292         db_val_t* v;
00293         int i, j;
00294 
00295         if (!_r) {
00296 #ifdef BDB_EXTRA_DEBUG
00297         LOG(L_NOTICE, "BDB:bdb_free_result: NULL pointer\n");
00298 #endif
00299                 return 0;
00300         }
00301 
00302         for (i = 0; i < RES_ROW_N(_r); i++) {
00303                 r = &(RES_ROWS(_r)[i]);
00304                 for (j = 0; j < RES_COL_N(_r); j++) {
00305                         v = &(ROW_VALUES(r)[j]);
00306                         if (VAL_TYPE(v) == DB_STRING || VAL_TYPE(v) == DB_STR || VAL_TYPE(v) == DB_BLOB) {
00307                                 free(VAL_STR(v).s);
00308                         }
00309                 }
00310                 free(ROW_VALUES(r));
00311         }
00312         free(RES_ROWS(_r));
00313 
00314         for (i = 0; i < RES_COL_N(_r); i++) {
00315                 pkg_free((void *)RES_NAMES(_r)[i]);
00316         }
00317         pkg_free(RES_NAMES(_r));
00318         pkg_free(RES_TYPES(_r));
00319 
00320         pkg_free(_r);
00321 
00322         return 0;
00323 }