bdb_cmd.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * BDB Database Driver for SIP-router
00005  *
00006  * Copyright (C) 2008 iptelorg GmbH
00007  *
00008  * This file is part of SIP-router, a free SIP server.
00009  *
00010  * SIP-router is free software; you can redistribute it and/or modify it under the
00011  * terms of the GNU General Public License as published by the Free Software
00012  * Foundation; either version 2 of the License, or (at your option) any later
00013  * version.
00014  *
00015  * SIP-router is distributed in the hope that it will be useful, but WITHOUT ANY
00016  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
00018  * details.
00019  *
00020  * You should have received a copy of the GNU General Public License along
00021  * with this program; if not, write to the Free Software Foundation, Inc.,
00022  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023  */
00024 
00035 #include <string.h>
00036 
00037 #include "../../mem/mem.h"
00038 #include "../../dprint.h"
00039 #include "../../ut.h"
00040 
00041 #include "bdb_cmd.h"
00042 #include "bdb_fld.h"
00043 #include "bdb_con.h"
00044 #include "bdb_uri.h"
00045 #include "bdb_res.h"
00046 #include "bdb_lib.h"
00047 #include "bdb_crs_compat.h"
00048 
00049 #define BDB_BUF_SIZE 1024
00050 
00056 static void bdb_cmd_free(db_cmd_t* cmd, bdb_cmd_t* payload)
00057 {
00058         db_drv_free(&payload->gen);
00059         if (payload->dbcp)
00060                 payload->dbcp->CLOSE_CURSOR(payload->dbcp);
00061         if(payload->skey.s)
00062                 pkg_free(payload->skey.s);
00063         pkg_free(payload);
00064 }
00065 
00066 int bdb_prepare_query(db_cmd_t* cmd, bdb_cmd_t *bcmd)
00067 {
00068         bdb_tcache_t *tbc = NULL;
00069         bdb_table_t *tp = NULL;
00070         bdb_fld_t *f;
00071         db_fld_t *fld;
00072         int mode;
00073         int i;
00074 
00075         if(bcmd->bcon==NULL || bcmd->bcon->dbp==NULL)
00076                 return -1;
00077         
00078         tbc = bdblib_get_table(bcmd->bcon->dbp, &cmd->table);
00079         if(tbc==NULL)
00080         {
00081                 ERR("bdb: table does not exist!\n");
00082                 return -1;
00083         }
00084 
00085         tp = tbc->dtp;
00086         if(tp==NULL || tp->db==NULL)
00087         {
00088                 ERR("bdb: table not loaded!\n");
00089                 return -1;
00090         }
00091 
00092         mode = 0;
00093         if (!DB_FLD_EMPTY(cmd->result)) 
00094         { /* columns to be returned provided */
00095                 if (cmd->result_count > tp->ncols)
00096                 {
00097                         ERR("bdb: too many columns in query\n");
00098                         goto error;
00099                 }
00100         } else {
00101                 mode = 1;
00102                 cmd->result = db_fld(tp->ncols + 1);
00103                 cmd->result_count = tp->ncols;
00104                 for(i = 0; i < cmd->result_count; i++) {
00105                         if (bdb_fld(cmd->result + i, cmd->table.s) < 0)
00106                                 goto error;
00107                 }               
00108         }
00109         
00110         for (i = 0; i < cmd->result_count; i++) {
00111                 fld = cmd->result + i;
00112                 f = DB_GET_PAYLOAD(fld);
00113                 if(mode==1)
00114                 {
00115                         DBG("bdb: column name [%.*s]\n", tp->colp[i]->name.len,
00116                                         tp->colp[i]->name.s);
00117                 
00118                         f->name = pkg_malloc(tp->colp[i]->name.len+1);
00119                         if (f->name == NULL) {
00120                                 ERR("bdb: Out of private memory\n");
00121                                 goto error;
00122                         }
00123                         strncpy(f->name, tp->colp[i]->name.s, tp->colp[i]->name.len);
00124                         f->name[tp->colp[i]->name.len] = '\0';
00125                         fld->name = f->name;
00126                         fld->type = tp->colp[i]->type;
00127                         f->col_pos = i;
00128                 } else {
00129                         f->col_pos = bdb_get_colpos(tp, fld->name);
00130                         if(f->col_pos == -1)
00131                         {
00132                                 ERR("bdb: Column not found\n");
00133                                 goto error;
00134                         }
00135                 }
00136                 switch(fld->type) {
00137                         case DB_INT:
00138                         case DB_BITMAP:
00139                         case DB_FLOAT:
00140                         case DB_DOUBLE:
00141                         case DB_DATETIME:
00142                         case DB_STR:
00143                                 if (!f->buf.s) f->buf.s = pkg_malloc(BDB_BUF_SIZE);
00144                                 if (f->buf.s == NULL) {
00145                                         ERR("bdb: No memory left\n");
00146                                         goto error;
00147                                 }
00148                                 fld[i].v.lstr.s = f->buf.s;
00149                         break;
00150 
00151                         case DB_CSTR:
00152                                 if (!f->buf.s) f->buf.s = pkg_malloc(BDB_BUF_SIZE);
00153                                 if (f->buf.s == NULL) {
00154                                         ERR("bdb: No memory left\n");
00155                                         goto error;
00156                                 }
00157                                 fld[i].v.cstr = f->buf.s;
00158                         break;
00159 
00160                 case DB_BLOB:
00161                                 if (!f->buf.s) f->buf.s = pkg_malloc(BDB_BUF_SIZE);
00162                                 if (f->buf.s == NULL) {
00163                                         ERR("mysql: No memory left\n");
00164                                         goto error;
00165                                 }
00166                                 fld[i].v.blob.s = f->buf.s;
00167                         break;
00168 
00169                 case DB_NONE:
00170                         /* Eliminates gcc warning */
00171                         break;
00172                 }
00173         }
00174         
00175         if (!DB_FLD_EMPTY(cmd->match))
00176         {
00177                 if (cmd->match_count > tp->ncols)
00178                 {
00179                         ERR("bdb: too many columns in match struct of query\n");
00180                         goto error;
00181                 }
00182                 for (i = 0; i < cmd->match_count; i++) {
00183                         fld = cmd->result + i;
00184                         f = DB_GET_PAYLOAD(fld);
00185                         f->col_pos = bdb_get_colpos(tp, fld->name);
00186                         if(f->col_pos == -1)
00187                         {
00188                                 ERR("bdb: Match column not found\n");
00189                                 goto error;
00190                         }
00191                 }
00192         }
00193 
00194         return 0;
00195 
00196 error:
00197         return -1;
00198 }
00199 
00200 int bdb_query(db_cmd_t* cmd, bdb_cmd_t *bcmd)
00201 {
00202         DBT key;
00203         DB *db;
00204         static char kbuf[MAX_ROW_SIZE];
00205         int klen;
00206 
00207         bdb_tcache_t *tbc = NULL;
00208         bdb_table_t *tp = NULL;
00209 
00210         if(bcmd->bcon==NULL || bcmd->bcon->dbp==NULL)
00211                 return -1;
00212         
00213         tbc = bdblib_get_table(bcmd->bcon->dbp, &cmd->table);
00214         if(tbc==NULL)
00215         {
00216                 ERR("bdb: table does not exist!\n");
00217                 return -1;
00218         }
00219 
00220         tp = tbc->dtp;
00221         if(tp==NULL)
00222         {
00223                 ERR("bdb: table not loaded!\n");
00224                 return -1;
00225         }
00226         db = tp->db;
00227         if(db==NULL)
00228         {
00229                 ERR("bdb: db structure not intialized!\n");
00230                 return -1;
00231         }
00232 
00233         if (DB_FLD_EMPTY(cmd->match))
00234         { /* no match constraint */
00235                 if (db->cursor(db, NULL, &bcmd->dbcp, 0) != 0) 
00236                 {
00237                         ERR("bdb: error creating cursor\n");
00238                         goto error;
00239                 }
00240                 bcmd->skey.len = 0;
00241                 return 0;
00242         }
00243 
00244         memset(&key, 0, sizeof(DBT));
00245         memset(kbuf, 0, MAX_ROW_SIZE);
00246         
00247         klen=MAX_ROW_SIZE;
00248         if(bdblib_valtochar(tp, cmd->match, cmd->match_count,
00249                         kbuf, &klen, BDB_KEY)!=0)
00250         {
00251                 ERR("bdb: error creating key\n");
00252                 goto error;
00253         }
00254         
00255         if(klen > bcmd->skey_size || bcmd->skey.s==NULL)
00256         {
00257                 if(bcmd->skey.s!=NULL)
00258                         pkg_free(bcmd->skey.s);
00259                 bcmd->skey.s = (char*)pkg_malloc(klen*sizeof(char));
00260                 if(bcmd->skey.s == NULL)
00261                 {
00262                         ERR("bdb: no pkg memory\n");
00263                         goto error;
00264                 }
00265                 bcmd->skey_size = klen;
00266         }
00267         memcpy(bcmd->skey.s, kbuf, klen);
00268         bcmd->skey.len = klen;
00269 
00270         return 0;
00271 error:
00272         return -1;
00273 }
00274 
00275 int bdb_cmd(db_cmd_t* cmd)
00276 {
00277         bdb_cmd_t *bcmd;
00278         db_con_t  *con;
00279         bdb_con_t *bcon;
00280 
00281         bcmd = (bdb_cmd_t*)pkg_malloc(sizeof(bdb_cmd_t));
00282         if (bcmd == NULL) {
00283                 ERR("bdb: No memory left\n");
00284                 goto error;
00285         }
00286         memset(bcmd, '\0', sizeof(bdb_cmd_t));
00287         if (db_drv_init(&bcmd->gen, bdb_cmd_free) < 0) goto error;
00288 
00289         con = cmd->ctx->con[db_payload_idx];
00290         bcon = DB_GET_PAYLOAD(con);
00291         bcmd->bcon = bcon;
00292 
00293         switch(cmd->type) {
00294         case DB_PUT:
00295         case DB_DEL:
00296         case DB_UPD:
00297                 ERR("bdb: The driver does not support DB modifications yet.\n");
00298                 goto error;
00299                 break;
00300 
00301         case DB_GET:
00302                 if(bdb_prepare_query(cmd, bcmd)!=0)
00303                 {
00304                         ERR("bdb: error preparing query.\n");
00305                         goto error;
00306                 }
00307                 break;
00308 
00309         case DB_SQL:
00310                 ERR("bdb: The driver does not support raw queries yet.\n");
00311                 goto error;
00312         }
00313 
00314         DB_SET_PAYLOAD(cmd, bcmd);
00315         return 0;
00316 
00317 error:
00318         if (bcmd) {
00319                 DB_SET_PAYLOAD(cmd, NULL);
00320                 db_drv_free(&bcmd->gen);
00321                 pkg_free(bcmd);
00322         }
00323         return -1;
00324 }
00325 
00326 
00327 int bdb_cmd_exec(db_res_t* res, db_cmd_t* cmd)
00328 {
00329         db_con_t* con;
00330         bdb_cmd_t *bcmd;
00331         bdb_con_t *bcon;
00332 
00333         /* First things first: retrieve connection info from the currently active
00334          * connection and also mysql payload from the database command
00335          */
00336         con = cmd->ctx->con[db_payload_idx];
00337         bcmd = DB_GET_PAYLOAD(cmd);
00338         bcon = DB_GET_PAYLOAD(con);
00339 
00340         if ((bcon->flags & BDB_CONNECTED)==0) {
00341                 ERR("bdb: not connected\n");
00342                 return -1;
00343         }
00344         bcmd->next_flag = -1;
00345         switch(cmd->type) {
00346                 case DB_DEL:
00347                 case DB_PUT:
00348                 case DB_UPD:
00349                                 /* no result expected - cleanup */
00350                                 DBG("bdb: query with no result.\n");
00351                         break;
00352                 case DB_GET:
00353                                 return bdb_query(cmd, bcmd);
00354                         break;
00355                 default:
00356                                 /* result expected - no cleanup */
00357                                 DBG("bdb: query with result.\n");
00358         }
00359 
00360         return 0;
00361 }
00362 
00363 int bdb_update_result(db_cmd_t *cmd, DBT *data)
00364 {
00365         bdb_fld_t *f;
00366         db_fld_t *fld;
00367         int i;
00368         int col;
00369         char *s;
00370         static str col_map[MAX_NUM_COLS];
00371 
00372         memset(col_map, 0, MAX_NUM_COLS*sizeof(str));
00373 
00374         col = 0;
00375         s = (char*)data->data;
00376         col_map[col].s = s;
00377         while(*s!='\0')
00378         {
00379                 if(*s == *DELIM)
00380                 {
00381                         col_map[col].len = s - col_map[col].s;
00382                         col++;
00383                         col_map[col].s = s+1;
00384                 }
00385                 s++;
00386         }
00387         col_map[col].len = s - col_map[col].s;
00388 
00389         for (i = 0; i < cmd->result_count; i++) {
00390                 fld = cmd->result + i;
00391                 f = DB_GET_PAYLOAD(fld);
00392                 if(col_map[f->col_pos].len == 0)
00393                 {
00394                         fld->flags |= DB_NULL;
00395                         continue;
00396                 }
00397                 fld->flags &= ~DB_NULL;
00398 
00399                 switch(fld->type) {
00400                         case DB_STR:
00401                                 fld->v.lstr.s = f->buf.s;
00402                                 if(col_map[f->col_pos].len < BDB_BUF_SIZE)
00403                                 {
00404                                         fld->v.lstr.len = col_map[f->col_pos].len;
00405                                 } else {
00406                                         /* truncate ?!? */
00407                                         fld->v.lstr.len = BDB_BUF_SIZE - 1;
00408                                 }
00409                                 memcpy(fld->v.lstr.s, col_map[f->col_pos].s, fld->v.lstr.len);
00410                         break;
00411 
00412                         case DB_BLOB:
00413                                 fld->v.blob.s = f->buf.s;
00414                                 if(col_map[f->col_pos].len < BDB_BUF_SIZE)
00415                                 {
00416                                         fld->v.blob.len = col_map[f->col_pos].len;
00417                                 } else {
00418                                         /* truncate ?!? */
00419                                         fld->v.blob.len = BDB_BUF_SIZE - 1;
00420                                 }
00421                                 memcpy(fld->v.blob.s, col_map[f->col_pos].s, fld->v.blob.len);
00422 
00423                         break;
00424 
00425                         case DB_CSTR:
00426                                 fld->v.cstr = f->buf.s;
00427                                 if(col_map[f->col_pos].len < BDB_BUF_SIZE)
00428                                 {
00429                                         memcpy(fld->v.cstr, col_map[f->col_pos].s,
00430                                                         col_map[f->col_pos].len);
00431                                         fld->v.cstr[col_map[f->col_pos].len] = '\0';
00432                                 } else {
00433                                         /* truncate ?!? */
00434                                         memcpy(fld->v.cstr, col_map[f->col_pos].s,
00435                                                         BDB_BUF_SIZE - 1);
00436                                         fld->v.cstr[BDB_BUF_SIZE - 1] = '\0';;
00437                                 }
00438 
00439                         break;
00440                         
00441                         case DB_DATETIME:
00442                                 /* str to time */
00443                                 col_map[f->col_pos].s[col_map[f->col_pos].len]='\0';
00444                                 if (bdb_str2time(col_map[f->col_pos].s, &fld->v.time) < 0)
00445                                 {
00446                                         ERR("Error while converting INT value from string\n");
00447                                         return -1;
00448                                 }
00449                         break;
00450 
00451                         case DB_INT:
00452                                 /* str to int */
00453                                 col_map[f->col_pos].s[col_map[f->col_pos].len]='\0';
00454                                 if (bdb_str2int(col_map[f->col_pos].s, &fld->v.int4) < 0)
00455                                 {
00456                                         ERR("Error while converting INT value from string\n");
00457                                         return -1;
00458                                 }
00459                         break;
00460 
00461                         case DB_FLOAT:
00462                         case DB_DOUBLE:
00463                                 /* str to dowuble */
00464                                 col_map[f->col_pos].s[col_map[f->col_pos].len]='\0';
00465                                 if (bdb_str2double(col_map[f->col_pos].s, &fld->v.dbl) < 0)
00466                                 {
00467                                         ERR("Error while converting DOUBLE value from string\n");
00468                                         return -1;
00469                                 }
00470                         break;
00471 
00472                         case DB_BITMAP:
00473                                 /* str to int */
00474                                 col_map[f->col_pos].s[col_map[f->col_pos].len]='\0';
00475                                 if (bdb_str2int(col_map[f->col_pos].s, &fld->v.int4) < 0)
00476                                 {
00477                                         ERR("Error while converting BITMAP value from string\n");
00478                                         return -1;
00479                                 }
00480                         break;
00481 
00482                         case DB_NONE:
00483                         break;
00484                 }
00485         }
00486         return 0;
00487 
00488 }
00489 
00490 int bdb_cmd_first(db_res_t* res)
00491 {
00492         bdb_cmd_t *bcmd;
00493 
00494         bcmd = DB_GET_PAYLOAD(res->cmd);
00495         switch (bcmd->next_flag) {
00496                 case -2: /* table is empty */
00497                         return 1;
00498                 case 0:  /* cursor position is 0 */
00499                         return 0;
00500                 case 1:  /* next row */
00501                 case 2:  /* EOF */
00502                         ERR("bdb: no next row.\n");
00503                         return -1;
00504                 default:
00505                         return bdb_cmd_next(res);
00506         }
00507 }
00508 
00509 
00510 int bdb_cmd_next(db_res_t* res)
00511 {
00512         db_con_t *con;
00513         bdb_res_t *bres;
00514         bdb_con_t *bcon;
00515         bdb_cmd_t *bcmd;
00516         DBT key, data;
00517         int ret;
00518         static char dbuf[MAX_ROW_SIZE];
00519 
00520         con = res->cmd->ctx->con[db_payload_idx];
00521         bres = DB_GET_PAYLOAD(res);
00522         bcon = DB_GET_PAYLOAD(con);
00523         bcmd = DB_GET_PAYLOAD(res->cmd);
00524 
00525         if (bcmd->next_flag == 2 || bcmd->next_flag == -2) return 1;
00526 
00527         memset(&key, 0, sizeof(DBT));
00528         memset(&data, 0, sizeof(DBT));
00529         memset(dbuf, 0, MAX_ROW_SIZE);
00530         
00531         data.data = dbuf;
00532         data.ulen = MAX_ROW_SIZE;
00533         data.flags = DB_DBT_USERMEM;
00534 
00535         ret = 0;
00536         if(bcmd->skey.len==0)
00537         {
00538                 while((ret = bcmd->dbcp->c_get(bcmd->dbcp, &key, &data, DB_NEXT))==0)
00539                 {
00540                         if(!strncasecmp((char*)key.data,"METADATA",8)) 
00541                                 continue;
00542                         break;
00543                 }
00544                 if(ret!=0)
00545                 {
00546                         bcmd->next_flag =  bcmd->next_flag<0?-2:2;
00547                         return 1;
00548                 }
00549         } else {
00550                 key.data = bcmd->skey.s;
00551                 key.ulen = bcmd->skey_size;
00552                 key.flags = DB_DBT_USERMEM;
00553                 key.size = bcmd->skey.len;
00554                 ret = bcmd->dbcp->c_get(bcmd->dbcp, &key, &data, DB_NEXT);
00555                 if(ret!=0)
00556                 {
00557                         bcmd->next_flag = bcmd->next_flag<0?-2:2;
00558                         return 1;
00559                 }
00560         }
00561 
00562         if (bcmd->next_flag <= 0) {
00563                 bcmd->next_flag++;
00564         }
00565 
00566         if (bdb_update_result(res->cmd, &data) < 0) {
00567                 return -1;
00568         }
00569 
00570         res->cur_rec->fld = res->cmd->result;
00571         return 0;
00572 }
00573 
00574