km_bdb_res.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * db_berkeley module, portions of this code were templated using
00005  * the dbtext and postgres modules.
00006 
00007  * Copyright (C) 2007 Cisco Systems
00008  *
00009  * This file is part of SIP-router, a free SIP server.
00010  *
00011  * SIP-router is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * SIP-router is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License 
00022  * along with this program; if not, write to the Free Software 
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  * 
00025  * History:
00026  * --------
00027  * 2007-09-19  genesis (wiquan)
00028  */
00029 
00037 #include <stdio.h>
00038 #include <string.h>
00039 #include <sys/types.h>
00040 #include "../../mem/mem.h"
00041 #include "km_bdb_res.h"
00042 
00043 
00044 int bdb_get_columns(table_p _tp, db1_res_t* _res, int* _lres, int _nc)
00045 {
00046         int col;
00047 
00048         if (!_res) {
00049                 LM_ERR("invalid parameter\n");
00050                 return -1;
00051         }
00052 
00053         if (_nc < 0 ) {
00054                 LM_ERR("_nc parameter cannot be negative \n");
00055                 return -1;
00056         }
00057     /* the number of rows (tuples) in the query result. */
00058         RES_NUM_ROWS(_res) = 1;
00059 
00060         if (!_lres)
00061                 _nc = _tp->ncols;
00062 
00063         /* Save number of columns in the result structure */
00064         RES_COL_N(_res) = _nc;
00065 
00066         if (db_allocate_columns(_res, RES_COL_N(_res)) != 0) {
00067                 LM_ERR("could not allocate columns");
00068                 return -2;
00069         }
00070 
00071         /*
00072          * For each column both the name and the data type are saved.
00073          */
00074         for(col = 0; col < RES_COL_N(_res); col++) {
00075                 column_p cp = NULL;
00076                 cp = (_lres) ? _tp->colp[_lres[col]] : _tp->colp[col];
00077 
00078                 RES_NAMES(_res)[col] = (str*)pkg_malloc(sizeof(str));
00079                 if (! RES_NAMES(_res)[col]) {
00080                         LM_ERR("no private memory left\n");
00081                         db_free_columns(_res);
00082                         return -3;
00083                 }
00084                 LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n",
00085                         (unsigned long)sizeof(str), col, RES_NAMES(_res)[col]);
00086 
00087                 /* The pointer that is here returned is part of the result structure. */
00088                 RES_NAMES(_res)[col]->s = cp->name.s;
00089                 RES_NAMES(_res)[col]->len = cp->name.len;
00090 
00091                 LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_res)[col]
00092                         , col, RES_NAMES(_res)[col]->len, RES_NAMES(_res)[col]->s);
00093 
00094                 RES_TYPES(_res)[col] = cp->type;
00095         }
00096         return 0;
00097 }
00098 
00099 
00100 
00104 int bdb_convert_row(db1_res_t* _res, char *bdb_result, int* _lres)
00105 {
00106         int col, len, i, j;
00107         char **row_buf, *s;
00108         db_row_t* row = NULL;
00109         col = len = i = j = 0;
00110         
00111         if (!_res) {
00112                 LM_ERR("invalid parameter\n");
00113                 return -1;
00114         }
00115 
00116         /* Allocate a single row structure */
00117         len = sizeof(db_row_t);
00118         row = (db_row_t*)pkg_malloc(len);
00119         if (!row) {
00120                 LM_ERR("no private memory left\n");
00121                 return -1;
00122         }
00123         LM_DBG("allocate %d bytes for row %p\n", len, row);
00124         memset(row, 0, len);
00125         RES_ROWS(_res) = row;
00126         
00127         /* Save the number of rows in the current fetch */
00128         RES_ROW_N(_res) = 1;
00129 
00130         if (db_allocate_row(_res, row) != 0) {
00131                 LM_ERR("could not allocate row");
00132                 return -2;
00133         }
00134         /*
00135          * Allocate an array of pointers one per column.
00136          * It that will be used to hold the address of the string representation of each column.
00137          */
00138         len = sizeof(char *) * RES_COL_N(_res);
00139         row_buf = (char **)pkg_malloc(len);
00140         if (!row_buf) {
00141                 LM_ERR("no private memory left\n");
00142                 return -1;
00143         }
00144         LM_DBG("allocate for %d columns %d bytes in row buffer at %p\n", RES_COL_N(_res), len, row_buf);
00145         memset(row_buf, 0, len);
00146 
00147         /*populate the row_buf with bdb_result*/
00148         /*bdb_result is memory from our callers stack so we copy here*/
00149         s = strtok(bdb_result, DELIM);
00150         while( s!=NULL)
00151         {
00152                 if(_lres) {
00153                         /*only requested cols (_c was specified)*/
00154                         for(i=0; i<ROW_N(row); i++)
00155                         {       if (col == _lres[i]) {
00156                                         len = strlen(s);
00157                                         row_buf[i] = pkg_malloc(len+1);
00158                                         if (!row_buf[i]) {
00159                                                 LM_ERR("no private memory left\n");
00160                                                 return -1;
00161                                         }
00162                                         LM_DBG("allocated %d bytes for row_buf[%d] at %p\n", len, i, row_buf[i]);
00163                                         memset(row_buf[i], 0, len+1);
00164                                         strncpy(row_buf[i], s, len);
00165                                 }
00166                                 
00167                         }
00168                 }
00169                 else {
00170                         len = strlen(s);
00171                         row_buf[col] = pkg_malloc(len+1);
00172                         if (!row_buf[col]) {
00173                                 LM_ERR("no private memory left\n");
00174                                 return -1;
00175                         }
00176                                 LM_DBG("allocated %d bytes for row_buf[%d] at %p\n", len, col, row_buf[col]);
00177                         memset(row_buf[col], 0, len+1);
00178                         strncpy(row_buf[col], s, len);
00179                 }
00180                 s = strtok(NULL, DELIM);
00181                 col++;
00182         }
00183 
00184         /*do the type conversion per col*/
00185         for(col = 0; col < ROW_N(row); col++) {
00186                 /*skip the unrequested cols (as already specified)*/
00187                 if(!row_buf[col])  continue;
00188 
00189                 /* Convert the string representation into the value representation */
00190                 if (bdb_str2val(RES_TYPES(_res)[col], &(ROW_VALUES(row)[col])
00191                                 , row_buf[col], strlen(row_buf[col])) < 0) {
00192                         LM_ERR("while converting value\n");
00193                         LM_DBG("freeing row at %p\n", row);
00194                         db_free_row(row);
00195                         return -3;
00196                 }
00197         }
00198 
00199         /* pkg_free() must be done for the above allocations now that the row has been converted.
00200          * During bdb_convert_row (and subsequent bdb_str2val) processing, data types that don't need to be
00201          * converted (namely STRINGS) have their addresses saved.  These data types should not have
00202          * their pkg_malloc() allocations freed here because they are still needed.  However, some data types
00203          * (ex: INT, DOUBLE) should have their pkg_malloc() allocations freed because during the conversion
00204          * process, their converted values are saved in the union portion of the db_val_t structure.
00205          *
00206          * Warning: when the converted row is no longer needed, the data types whose addresses
00207          * were saved in the db_val_t structure must be freed or a memory leak will happen.
00208          * This processing should happen in the db_free_row() subroutine.  The caller of
00209          * this routine should ensure that db_free_rows(), db_free_row() or db_free_result()
00210          * is eventually called.
00211          */
00212         for (col = 0; col < RES_COL_N(_res); col++) {
00213                 switch (RES_TYPES(_res)[col]) 
00214                 {
00215                         case DB1_STRING:
00216                         case DB1_STR:
00217                                 break;
00218                         default:
00219                         LM_DBG("col[%d] Col[%.*s] Type[%d] Freeing row_buf[%p]\n", col
00220                                 , RES_NAMES(_res)[col]->len, RES_NAMES(_res)[col]->s,
00221                                   RES_TYPES(_res)[col], row_buf[col]);
00222                         LM_DBG("freeing row_buf[%d] at %p\n", col, row_buf[col]);
00223                         pkg_free(row_buf[col]);
00224                 }
00225                 /* The following housekeeping may not be technically required, but it is a good practice
00226                  * to NULL pointer fields that are no longer valid.  Note that DB1_STRING fields have not
00227                  * been pkg_free(). NULLing DB1_STRING fields would normally not be good to do because a memory
00228                  * leak would occur.  However, the pg_convert_row() routine has saved the DB1_STRING pointer
00229                  * in the db_val_t structure.  The db_val_t structure will eventually be used to pkg_free()
00230                  * the DB1_STRING storage.
00231                  */
00232                 row_buf[col] = (char *)NULL;
00233         }
00234         LM_DBG("freeing row buffer at %p\n", row_buf);
00235         pkg_free(row_buf);
00236         row_buf = NULL;
00237 
00238         return 0;
00239 
00240 }
00241 
00242 /*rx is row index*/
00243 int bdb_append_row(db1_res_t* _res, char *bdb_result, int* _lres, int _rx)
00244 {
00245         int col, len, i, j;
00246         char **row_buf, *s;
00247         db_row_t* row = NULL;
00248         col = len = i = j = 0;
00249         
00250         if (!_res) {
00251                 LM_ERR("invalid parameter");
00252                 return -1;
00253         }
00254         
00255         row = &(RES_ROWS(_res)[_rx]);
00256         
00257         if (db_allocate_row(_res, row) != 0) {
00258                 LM_ERR("could not allocate row");
00259                 return -2;
00260         }
00261         
00262         /*
00263          * Allocate an array of pointers one per column.
00264          * It that will be used to hold the address of the string representation of each column.
00265          */
00266         len = sizeof(char *) * RES_COL_N(_res);
00267         row_buf = (char **)pkg_malloc(len);
00268         if (!row_buf) {
00269                 LM_ERR("no private memory left\n");
00270                 return -1;
00271         }
00272         LM_DBG("allocate for %d columns %d bytes in row buffer at %p\n", RES_COL_N(_res), len, row_buf);
00273         memset(row_buf, 0, len);
00274         
00275         /*populate the row_buf with bdb_result*/
00276         /*bdb_result is memory from our callers stack so we copy here*/
00277         s = strtok(bdb_result, DELIM);
00278         while( s!=NULL)
00279         {       
00280                 if(_lres) {
00281                         /*only requested cols (_c was specified)*/
00282                         for(i=0; i<ROW_N(row); i++) {
00283                                 if (col == _lres[i]) {
00284                                         len = strlen(s);
00285                                         row_buf[i] = pkg_malloc(len+1);
00286                                         if (!row_buf[i]) {
00287                                                 LM_ERR("no private memory left\n");
00288                                                 return -1;
00289                                         }
00290                                         memset(row_buf[i], 0, len+1);
00291                                         strncpy(row_buf[i], s, len);
00292                                 }
00293                         }
00294                 }
00295                 else {
00296                         len = strlen(s);
00297 
00298 #ifdef BDB_EXTRA_DEBUG
00299                 LM_DBG("col[%i] = [%.*s]\n", col , len, s );
00300 #endif
00301 
00302                         row_buf[col] = (char*)pkg_malloc(len+1);
00303                         if (!row_buf[col]) {
00304                                 LM_ERR("no private memory left\n");
00305                                 return -1;
00306                         }
00307                         memset(row_buf[col], 0, len+1);
00308                         strncpy(row_buf[col], s, len);
00309                 }
00310                 s = strtok(NULL, DELIM);
00311                 col++;
00312         }
00313         
00314         /*do the type conversion per col*/
00315         for(col = 0; col < ROW_N(row); col++) {
00316 #ifdef BDB_EXTRA_DEBUG
00317                 LM_DBG("tc 1: col[%i] == ", col );
00318 #endif
00319 
00320                 /*skip the unrequested cols (as already specified)*/
00321                 if(!row_buf[col])  continue;
00322 
00323 #ifdef BDB_EXTRA_DEBUG
00324                 LM_DBG("tc 2: col[%i] \n", col );
00325 #endif
00326 
00327                 /* Convert the string representation into the value representation */
00328                 if (bdb_str2val(RES_TYPES(_res)[col], &(ROW_VALUES(row)[col])
00329                                 , row_buf[col], strlen(row_buf[col])) < 0) {
00330                         LM_ERR("while converting value\n");
00331                         LM_DBG("freeing row at %p\n", row);
00332                         db_free_row(row);
00333                         return -3;
00334                 }
00335         }
00336 
00337         /* pkg_free() must be done for the above allocations now that the row has been converted.
00338          * During bdb_convert_row (and subsequent bdb_str2val) processing, data types that don't need to be
00339          * converted (namely STRINGS) have their addresses saved.  These data types should not have
00340          * their pkg_malloc() allocations freed here because they are still needed.  However, some data types
00341          * (ex: INT, DOUBLE) should have their pkg_malloc() allocations freed because during the conversion
00342          * process, their converted values are saved in the union portion of the db_val_t structure.
00343          *
00344          * Warning: when the converted row is no longer needed, the data types whose addresses
00345          * were saved in the db_val_t structure must be freed or a memory leak will happen.
00346          * This processing should happen in the db_free_row() subroutine.  The caller of
00347          * this routine should ensure that db_free_rows(), db_free_row() or db_free_result()
00348          * is eventually called.
00349          */
00350         for (col = 0; col < RES_COL_N(_res); col++) {
00351                 if (RES_TYPES(_res)[col] != DB1_STRING) {
00352                         LM_DBG("col[%d] Col[%.*s] Type[%d] Freeing row_buf[%p]\n", col
00353                                 , RES_NAMES(_res)[col]->len, RES_NAMES(_res)[col]->s,
00354                                   RES_TYPES(_res)[col], row_buf[col]);
00355                         LM_DBG("freeing row_buf[%d] at %p\n", col, row_buf[col]);
00356                         pkg_free(row_buf[col]);
00357                 }
00358                 /* The following housekeeping may not be technically required, but it is a good practice
00359                  * to NULL pointer fields that are no longer valid.  Note that DB1_STRING fields have not
00360                  * been pkg_free(). NULLing DB1_STRING fields would normally not be good to do because a memory
00361                  * leak would occur.  However, the pg_convert_row() routine has saved the DB1_STRING pointer
00362                  * in the db_val_t structure.  The db_val_t structure will eventually be used to pkg_free()
00363                  * the DB1_STRING storage.
00364                  */
00365                 row_buf[col] = (char *)NULL;
00366         }
00367         LM_DBG("freeing row buffer at %p\n", row_buf);
00368         pkg_free(row_buf);
00369         row_buf = NULL;
00370         return 0;
00371 }
00372 
00373 
00374 
00375 int* bdb_get_colmap(table_p _dtp, db_key_t* _k, int _n)
00376 {
00377         int i, j, *_lref=NULL;
00378         
00379         if(!_dtp || !_k || _n < 0)
00380                 return NULL;
00381         
00382         _lref = (int*)pkg_malloc(_n*sizeof(int));
00383         if(!_lref)
00384                 return NULL;
00385         
00386         for(i=0; i < _n; i++)
00387         {
00388                 for(j=0; j<_dtp->ncols; j++) {
00389                         if(_k[i]->len==_dtp->colp[j]->name.len
00390                         && !strncasecmp(_k[i]->s, _dtp->colp[j]->name.s,
00391                                                 _dtp->colp[j]->name.len)) {
00392                                 _lref[i] = j;
00393                                 break;
00394                         }
00395                 }
00396                 if(i>=_dtp->ncols) {
00397                         LM_DBG("ERROR column <%.*s> not found\n", _k[i]->len, _k[i]->s);
00398                         pkg_free(_lref);
00399                         return NULL;
00400                 }
00401         }
00402         return _lref;
00403 }
00404 
00405 
00406 int bdb_is_neq_type(db_type_t _t0, db_type_t _t1)
00407 {
00408         if(_t0 == _t1)  return 0;
00409         
00410         switch(_t1)
00411         {
00412                 case DB1_INT:
00413                         if(_t0==DB1_DATETIME || _t0==DB1_BITMAP)
00414                                 return 0;
00415                 case DB1_BIGINT:
00416                                 LM_ERR("BIGINT not supported");
00417                                 return 0;
00418                 case DB1_DATETIME:
00419                         if(_t0==DB1_INT)
00420                                 return 0;
00421                         if(_t0==DB1_BITMAP)
00422                                 return 0;
00423                 case DB1_DOUBLE:
00424                         break;
00425                 case DB1_STRING:
00426                         if(_t0==DB1_STR)
00427                                 return 0;
00428                 case DB1_STR:
00429                         if(_t0==DB1_STRING || _t0==DB1_BLOB)
00430                                 return 0;
00431                 case DB1_BLOB:
00432                         if(_t0==DB1_STR)
00433                                 return 0;
00434                 case DB1_BITMAP:
00435                         if (_t0==DB1_INT)
00436                                 return 0;
00437         }
00438         return 1;
00439 }
00440 
00441 
00442 /*
00443 */
00444 int bdb_row_match(db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n, db1_res_t* _r, int* _lkey )
00445 {
00446         int i, res;
00447         db_row_t* row = NULL;
00448         
00449         if(!_r || !_lkey)
00450                 return 1;
00451         
00452         row = RES_ROWS(_r);
00453         
00454         for(i=0; i<_n; i++) {
00455                 res = bdb_cmp_val(&(ROW_VALUES(row)[_lkey[i]]), &_v[i]);
00456 
00457                 if(!_op || !strcmp(_op[i], OP_EQ)) {
00458                         if(res!=0)
00459                                 return 0;
00460                 } else {
00461                 if(!strcmp(_op[i], OP_LT)) {
00462                         if(res!=-1)
00463                                 return 0;
00464                 } else {
00465                 if(!strcmp(_op[i], OP_GT)) {
00466                         if(res!=1)
00467                                 return 0;
00468                 } else {
00469                 if(!strcmp(_op[i], OP_LEQ)) {
00470                         if(res==1)
00471                                 return 0;
00472                 } else {
00473                 if(!strcmp(_op[i], OP_GEQ)) {
00474                         if(res==-1)
00475                                 return 0;
00476                 } else {
00477                         return res;
00478                 }}}}}
00479         }
00480         
00481         return 1;
00482 }
00483 
00484 /*
00485 */
00486 int bdb_cmp_val(db_val_t* _vp, db_val_t* _v)
00487 {
00488         int _l, _n;
00489         
00490         if(!_vp && !_v)
00491                 return 0;
00492         if(!_v)
00493                 return 1;
00494         if(!_vp)
00495                 return -1;
00496         if(_vp->nul && _v->nul)
00497                 return 0;
00498         if(_v->nul)
00499                 return 1;
00500         if(_vp->nul)
00501                 return -1;
00502         
00503         switch(VAL_TYPE(_v))
00504         {
00505                 case DB1_INT:
00506                         return (_vp->val.int_val<_v->val.int_val)?-1:
00507                                         (_vp->val.int_val>_v->val.int_val)?1:0;
00508                 case DB1_BIGINT:
00509                         LM_ERR("BIGINT not supported");
00510                         return -1;
00511                 case DB1_DOUBLE:
00512                         return (_vp->val.double_val<_v->val.double_val)?-1:
00513                                         (_vp->val.double_val>_v->val.double_val)?1:0;
00514                 case DB1_DATETIME:
00515                         return (_vp->val.int_val<_v->val.time_val)?-1:
00516                                         (_vp->val.int_val>_v->val.time_val)?1:0;
00517                 case DB1_STRING:
00518                         _l = strlen(_v->val.string_val);
00519                         _l = (_l>_vp->val.str_val.len)?_vp->val.str_val.len:_l;
00520                         _n = strncasecmp(_vp->val.str_val.s, _v->val.string_val, _l);
00521                         if(_n)
00522                                 return _n;
00523                         if(_vp->val.str_val.len == strlen(_v->val.string_val))
00524                                 return 0;
00525                         if(_l==_vp->val.str_val.len)
00526                                 return -1;
00527                         return 1;
00528                 case DB1_STR:
00529                         _l = _v->val.str_val.len;
00530                         _l = (_l>_vp->val.str_val.len)?_vp->val.str_val.len:_l;
00531                         _n = strncasecmp(_vp->val.str_val.s, _v->val.str_val.s, _l);
00532                         if(_n)
00533                                 return _n;
00534                         if(_vp->val.str_val.len == _v->val.str_val.len)
00535                                 return 0;
00536                         if(_l==_vp->val.str_val.len)
00537                                 return -1;
00538                         return 1;
00539                 case DB1_BLOB:
00540                         _l = _v->val.blob_val.len;
00541                         _l = (_l>_vp->val.str_val.len)?_vp->val.str_val.len:_l;
00542                         _n = strncasecmp(_vp->val.str_val.s, _v->val.blob_val.s, _l);
00543                         if(_n)
00544                                 return _n;
00545                         if(_vp->val.str_val.len == _v->val.blob_val.len)
00546                                 return 0;
00547                         if(_l==_vp->val.str_val.len)
00548                                 return -1;
00549                         return 1;
00550                 case DB1_BITMAP:
00551                         return (_vp->val.int_val<_v->val.bitmap_val)?-1:
00552                                 (_vp->val.int_val>_v->val.bitmap_val)?1:0;
00553         }
00554         return -2;
00555 }