db_ut.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 
00034 #if defined (__OS_darwin) || defined (__OS_freebsd)
00035 #include "../../pvar.h"
00036 #endif
00037 
00043 #ifndef __OS_solaris
00044         #define _XOPEN_SOURCE 600          /* glibc2 on linux, bsd */
00045         #define _BSD_SOURCE 1              /* needed on linux to "fix" the effect
00046                                                                                  of the above define on 
00047                                                                                  features.h/unistd.h syscall() */
00048 #else
00049         #define _XOPEN_SOURCE_EXTENDED 1   /* solaris */
00050 #endif
00051 
00052 #include <time.h>
00053 
00054 #ifndef __OS_solaris
00055         #undef _XOPEN_SOURCE
00056         #undef _XOPEN_SOURCE_EXTENDED
00057 #else
00058         #undef _XOPEN_SOURCE_EXTENDED 1   /* solaris */
00059 #endif
00060 
00061 #include <limits.h>
00062 #include <errno.h>
00063 #include <stdio.h>
00064 #include <stdlib.h>
00065 #include <string.h>
00066 
00067 #include "../../mem/mem.h"
00068 #include "../../dprint.h"
00069 
00070 #include "db_ut.h"
00071 
00072 
00073 inline int db_str2int(const char* _s, int* _v)
00074 {
00075         long tmp;
00076 
00077         if (!_s || !_v) {
00078                LM_ERR("Invalid parameter value\n");
00079                return -1;
00080         }
00081 
00082         tmp = strtoul(_s, 0, 10);
00083         if ((tmp == ULONG_MAX && errno == ERANGE) || 
00084             (tmp < INT_MIN) || (tmp > UINT_MAX)) {
00085                 LM_ERR("Value out of range\n");
00086                 return -1;
00087         }
00088 
00089         *_v = (int)tmp;
00090         return 0;
00091 }
00092 
00093 
00094 inline int db_str2longlong(const char* _s, long long * _v)
00095 {
00096         long long tmp;
00097 
00098         if (!_s || !_v) {
00099                LM_ERR("Invalid parameter value\n");
00100                return -1;
00101         }
00102 
00103         tmp = strtoll(_s, 0, 10);
00104         if (errno == ERANGE) {
00105                 LM_ERR("Value out of range\n");
00106                 return -1;
00107         }
00108 
00109         *_v = tmp;
00110         return 0;
00111 }
00112 
00113 
00114 /*
00115  * Convert a string to double
00116  */
00117 inline int db_str2double(const char* _s, double* _v)
00118 {
00119         if ((!_s) || (!_v)) {
00120                 LM_ERR("Invalid parameter value\n");
00121                 return -1;
00122         }
00123 
00124         *_v = atof(_s);
00125         return 0;
00126 }
00127 
00128 
00129 
00130 /*
00131  * Convert an integer to string
00132  */
00133 inline int db_int2str(int _v, char* _s, int* _l)
00134 {
00135         int ret;
00136 
00137         if ((!_s) || (!_l) || (!*_l)) {
00138                 LM_ERR("Invalid parameter value\n");
00139                 return -1;
00140         }
00141 
00142         ret = snprintf(_s, *_l, "%-d", _v);
00143         if (ret < 0 || ret >= *_l) {
00144                 LM_ERR("Error in snprintf\n");
00145                 return -1;
00146         }
00147         *_l = ret;
00148 
00149         return 0;
00150 }
00151 
00152 
00153 /*
00154  * Convert an long long to string
00155  */
00156 inline int db_longlong2str(long long _v, char* _s, int* _l)
00157 {
00158         int ret;
00159 
00160         if ((!_s) || (!_l) || (!*_l)) {
00161                 LM_ERR("Invalid parameter value\n");
00162                 return -1;
00163         }
00164 
00165         ret = snprintf(_s, *_l, "%-lld", _v);
00166         if (ret < 0 || ret >= *_l) {
00167                 LM_ERR("Error in snprintf\n");
00168                 return -1;
00169         }
00170         *_l = ret;
00171 
00172         return 0;
00173 }
00174 
00175 
00176 /*
00177  * Convert a double to string
00178  */
00179 inline int db_double2str(double _v, char* _s, int* _l)
00180 {
00181         int ret;
00182 
00183         if ((!_s) || (!_l) || (!*_l)) {
00184                 LM_ERR("Invalid parameter value\n");
00185                 return -1;
00186         }
00187 
00188         ret = snprintf(_s, *_l, "%-10.2f", _v);
00189         if (ret < 0 || ret >= *_l) {
00190                 LM_ERR("Error in snprintf\n");
00191                 return -1;
00192         }
00193         *_l = ret;
00194 
00195         return 0;
00196 }
00197 
00198 
00199 /* 
00200  * Convert a string to time_t
00201  */
00202 inline int db_str2time(const char* _s, time_t* _v)
00203 {
00204         struct tm time;
00205 
00206         if ((!_s) || (!_v)) {
00207                 LM_ERR("Invalid parameter value\n");
00208                 return -1;
00209         }
00210 
00211         /* Convert database time representation to time_t structure
00212            It is necessary to zero tm structure first */
00213         memset(&time, '\0', sizeof(struct tm));
00214         if (strptime(_s, "%Y-%m-%d %H:%M:%S", &time) == NULL) {
00215                 LM_ERR("Error during time conversion\n");
00216                 return -1;
00217         }
00218 
00219         /* Daylight saving information got lost in the database
00220         * so let mktime to guess it. This eliminates the bug when
00221         * contacts reloaded from the database have different time
00222         * of expiration by one hour when daylight saving is used
00223         */ 
00224         time.tm_isdst = -1;
00225         *_v = mktime(&time);
00226 
00227         return 0;
00228 }
00229 
00230 
00231 inline int db_time2str(time_t _v, char* _s, int* _l)
00232 {
00233         struct tm* t;
00234         int l;
00235 
00236         if ((!_s) || (!_l) || (*_l < 2)) {
00237                 LM_ERR("Invalid parameter value\n");
00238                 return -1;
00239         }
00240 
00241         *_s++ = '\'';
00242 
00243         /* Convert time_t structure to format accepted by the database */
00244         t = localtime(&_v);
00245         l = strftime(_s, *_l -1, "%Y-%m-%d %H:%M:%S", t);
00246 
00247         if (l == 0) {
00248                 LM_ERR("Error during time conversion\n");
00249                 /* the value of _s is now unspecified */
00250                 _s = NULL;
00251                 _l = 0;
00252                 return -1;
00253         }
00254         *_l = l;
00255 
00256         *(_s + l) = '\'';
00257         *_l = l + 2;
00258         return 0;
00259 }
00260 
00261 
00262 /*
00263  * Print list of columns separated by comma
00264  */
00265 inline int db_print_columns(char* _b, const int _l, const db_key_t* _c, const int _n)
00266 {
00267         int i, ret, len = 0;
00268 
00269         if ((!_c) || (!_n) || (!_b) || (!_l)) {
00270                 LM_ERR("Invalid parameter value\n");
00271                 return -1;
00272         }
00273 
00274         for(i = 0; i < _n; i++) {
00275                 if (i == (_n - 1)) {
00276                         ret = snprintf(_b + len, _l - len, "%.*s ", _c[i]->len, _c[i]->s);
00277                         if (ret < 0 || ret >= (_l - len)) goto error;
00278                         len += ret;
00279                 } else {
00280                         ret = snprintf(_b + len, _l - len, "%.*s,", _c[i]->len, _c[i]->s);
00281                         if (ret < 0 || ret >= (_l - len)) goto error;
00282                         len += ret;
00283                 }
00284         }
00285         return len;
00286 
00287         error:
00288         LM_ERR("Error in snprintf\n");
00289         return -1;
00290 }
00291 
00292 
00293 /*
00294  * Print values of SQL statement
00295  */
00296 int db_print_values(const db1_con_t* _c, char* _b, const int _l, const db_val_t* _v,
00297         const int _n, int (*val2str)(const db1_con_t*, const db_val_t*, char*, int*))
00298 {
00299         int i, l, len = 0;
00300 
00301         if (!_c || !_b || !_l || !_v || !_n) {
00302                 LM_ERR("Invalid parameter value\n");
00303                 return -1;
00304         }
00305 
00306         for(i = 0; i < _n; i++) {
00307                 l = _l - len;
00308                 if ( (*val2str)(_c, _v + i, _b + len, &l) < 0) {
00309                         LM_ERR("Error while converting value to string\n");
00310                         return -1;
00311                 }
00312                 len += l;
00313                 if (i != (_n - 1)) {
00314                         *(_b + len) = ',';
00315                         len++;
00316                 }
00317         }
00318         return len;
00319 }
00320 
00321 
00322 /*
00323  * Print where clause of SQL statement
00324  */
00325 int db_print_where(const db1_con_t* _c, char* _b, const int _l, const db_key_t* _k,
00326         const db_op_t* _o, const db_val_t* _v, const int _n, int (*val2str)
00327         (const  db1_con_t*, const db_val_t*, char*, int*))
00328 {
00329         int i, l, ret, len = 0;
00330 
00331         if (!_c || !_b || !_l || !_k || !_v || !_n) {
00332                 LM_ERR("Invalid parameter value\n");
00333                 return -1;
00334         }
00335 
00336         for(i = 0; i < _n; i++) {
00337                 if (_o && strncmp(_o[i], OP_BITWISE_AND, 1) == 0) {
00338                         char tmp_buf[16];
00339                         int tmp_len = 15;
00340                         memset(tmp_buf, '0', 16);
00341                         if ((*val2str)(_c, &(_v[i]), tmp_buf, &tmp_len) < 0) {
00342                                 LM_ERR("Error while converting value to string\n");
00343                                 return -1;
00344                         }
00345                         ret = snprintf(_b + len, _l - len, "%.*s&%.*s=%.*s", _k[i]->len, _k[i]->s, tmp_len, tmp_buf, tmp_len, tmp_buf);
00346                         if (ret < 0 || ret >= (_l - len)) goto error;
00347                         len += ret;
00348                 } else {
00349                         if (_o) {
00350                                 ret = snprintf(_b + len, _l - len, "%.*s%s", _k[i]->len, _k[i]->s, _o[i]);
00351                                 if (ret < 0 || ret >= (_l - len)) goto error;
00352                                 len += ret;
00353                         } else {
00354                                 ret = snprintf(_b + len, _l - len, "%.*s=", _k[i]->len, _k[i]->s);
00355                                 if (ret < 0 || ret >= (_l - len)) goto error;
00356                                 len += ret;
00357                         }
00358                         l = _l - len;
00359                         if ( (*val2str)(_c, &(_v[i]), _b + len, &l) < 0) {
00360                                 LM_ERR("Error while converting value to string\n");
00361                                 return -1;
00362                         }
00363                         len += l;
00364                 }
00365 
00366                 if (i != (_n - 1)) {
00367                         ret = snprintf(_b + len, _l - len, " AND ");
00368                         if (ret < 0 || ret >= (_l - len)) goto error;
00369                         len += ret;
00370                 }
00371         }
00372         return len;
00373 
00374  error:
00375         LM_ERR("Error in snprintf\n");
00376         return -1;
00377 }
00378 
00379 
00380 /*
00381  * Print set clause of update SQL statement
00382  */
00383 int db_print_set(const db1_con_t* _c, char* _b, const int _l, const db_key_t* _k,
00384         const db_val_t* _v, const int _n, int (*val2str)(const db1_con_t*,
00385         const db_val_t*,char*, int*))
00386 {
00387         int i, l, ret, len = 0;
00388 
00389         if (!_c || !_b || !_l || !_k || !_v || !_n) {
00390                 LM_ERR("Invalid parameter value\n");
00391                 return -1;
00392         }
00393 
00394         for(i = 0; i < _n; i++) {
00395                 ret = snprintf(_b + len, _l - len, "%.*s=", _k[i]->len, _k[i]->s);
00396                 if (ret < 0 || ret >= (_l - len)) goto error;
00397                 len += ret;
00398 
00399                 l = _l - len;
00400                 if ( (*val2str)(_c, &(_v[i]), _b + len, &l) < 0) {
00401                         LM_ERR("Error while converting value to string\n");
00402                         return -1;
00403                 }
00404                 len += l;
00405                 if (i != (_n - 1)) {
00406                         if ((_l - len) >= 1) {
00407                                 *(_b + len++) = ',';
00408                         }
00409                 }
00410         }
00411         return len;
00412 
00413  error:
00414         LM_ERR("Error in snprintf\n");
00415         return -1;
00416 }
00417 
00418 /*
00419  * Convert db_val to pv_spec
00420  */
00421 int db_val2pv_spec(struct sip_msg* msg, db_val_t *dbval, pv_spec_t *pvs)
00422 {
00423         pv_value_t pv;
00424 #define LL_LEN 21   /* sign, 19 digits and \0 */
00425         static char ll_buf[LL_LEN];
00426 
00427         if(dbval->nul)
00428         {
00429                 pv.flags = PV_VAL_NULL;
00430         } else
00431         {
00432                 switch(dbval->type)
00433                 {
00434                         case DB1_STRING:
00435                                 pv.flags = PV_VAL_STR;
00436                                 pv.rs.s = (char*)dbval->val.string_val;
00437                                 pv.rs.len = strlen(pv.rs.s);
00438                         break;
00439                         case DB1_STR:
00440                                 pv.flags = PV_VAL_STR;
00441                                 pv.rs.s = (char*)dbval->val.str_val.s;
00442                                 pv.rs.len = dbval->val.str_val.len;
00443                         break;
00444                         case DB1_BLOB:
00445                                 pv.flags = PV_VAL_STR;
00446                                 pv.rs.s = (char*)dbval->val.blob_val.s;
00447                                 pv.rs.len = dbval->val.blob_val.len;
00448                         break;
00449                         case DB1_INT:
00450                                 pv.flags = PV_VAL_INT | PV_TYPE_INT;
00451                                 pv.ri = (int)dbval->val.int_val;
00452                         break;
00453                         case DB1_DATETIME:
00454                                 pv.flags = PV_VAL_INT | PV_TYPE_INT;
00455                                 pv.ri = (int)dbval->val.time_val;
00456                         break;
00457                         case DB1_BITMAP:
00458                                 pv.flags = PV_VAL_INT | PV_TYPE_INT;
00459                                 pv.ri = (int)dbval->val.bitmap_val;
00460                         break;
00461                         case DB1_BIGINT:
00462                                 /* BIGINT is stored as string */
00463                                 pv.flags = PV_VAL_STR;
00464                                 pv.rs.len = LL_LEN;
00465                                 db_longlong2str(dbval->val.ll_val, ll_buf, &pv.rs.len);
00466                                 pv.rs.s = ll_buf;
00467                         break;
00468                         default:
00469                                 LM_NOTICE("unknown field type: %d, setting value to null\n",
00470                                           dbval->type);
00471                                 pv.flags = PV_VAL_NULL;
00472                 }
00473         }
00474 
00475         /* null values are ignored for avp type PV */
00476         if (pv.flags == PV_VAL_NULL && pvs->type == PVT_AVP)
00477                 return 0;
00478 
00479         /* add value to result pv */
00480         if (pv_set_spec_value(msg, pvs, 0, &pv) != 0)
00481         {
00482                 LM_ERR("Failed to add value to spec\n");
00483                 return -1;
00484         }
00485 
00486         return 0;
00487 }