1 /*
2 * Copyright (C) 2001-2003 FhG Fokus
3 * Copyright (C) 2007-2008 1&1 Internet AG
4 *
5 * This file is part of Kamailio, a free SIP server.
6 *
7 * Kamailio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version
11 *
12 * Kamailio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * \file lib/srdb1/db_ut.c
24 * \brief Utility functions for database drivers.
25 *
26 * This utility methods are used from the database SQL driver to convert
27 * values and print SQL queries from the internal API representation.
28 * \ingroup db1
29 */
30
31
32 #if defined (__OS_darwin) || defined (__OS_freebsd)
33 #include "../../core/pvar.h"
34 #endif
35
36 /**
37 * make strptime available
38 * use 600 for 'Single UNIX Specification, Version 3'
39 * _XOPEN_SOURCE creates conflict in swab definition in Solaris
40 */
41 #ifndef __OS_solaris
42 #define _XOPEN_SOURCE 600 /* glibc2 on linux, bsd */
43 #define _BSD_SOURCE 1 /* needed on linux to "fix" the effect
44 * of the above define on
45 * features.h/unistd.h syscall() */
46 #define _DEFAULT_SOURCE 1 /* _BSD_SOURCE is deprecated */
47 #else
48 #define _XOPEN_SOURCE_EXTENDED 1 /* solaris */
49 #endif
50
51 #include <time.h>
52
53 #ifndef __OS_solaris
54 #undef _XOPEN_SOURCE
55 #undef _XOPEN_SOURCE_EXTENDED
56 #else /* solaris */
57 #undef _XOPEN_SOURCE_EXTENDED
58 #endif
59
60 #include <limits.h>
61 #include <errno.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65
66 #include "../../core/mem/mem.h"
67 #include "../../core/dprint.h"
68
69 #include "db_ut.h"
70
71
72 /**
73 *
74 */
db_str2int(const char * _s,int * _v)75 int db_str2int(const char* _s, int* _v)
76 {
77 long tmp;
78 char* p = NULL;
79
80 if (!_s || !_v) {
81 LM_ERR("Invalid parameter value\n");
82 return -1;
83 }
84
85 tmp = strtoul(_s, &p, 10);
86 if ((tmp == ULONG_MAX && errno == ERANGE) ||
87 (tmp < INT_MIN) || (tmp > UINT_MAX)) {
88 LM_ERR("Value out of range\n");
89 return -1;
90 }
91 if (p && *p != '\0') {
92 LM_ERR("Unexpected characters: [%s]\n", p);
93 return -2;
94 }
95
96 *_v = (int)tmp;
97 return 0;
98 }
99
100
101 /**
102 *
103 */
db_str2uint(const char * _s,unsigned int * _v)104 int db_str2uint(const char* _s, unsigned int* _v)
105 {
106 unsigned long tmp;
107 char* p = NULL;
108
109 if (!_s || !_v) {
110 LM_ERR("Invalid parameter value\n");
111 return -1;
112 }
113
114 tmp = strtoul(_s, &p, 10);
115 if ((tmp == ULONG_MAX && errno == ERANGE) ||
116 ((long)tmp < INT_MIN) || (tmp > UINT_MAX)) {
117 LM_ERR("Value out of range\n");
118 return -1;
119 }
120 if (p && *p != '\0') {
121 LM_ERR("Unexpected characters: [%s]\n", p);
122 return -2;
123 }
124
125 *_v = (unsigned int)tmp;
126 return 0;
127 }
128
129
130 /**
131 *
132 */
db_str2longlong(const char * _s,long long * _v)133 int db_str2longlong(const char* _s, long long * _v)
134 {
135 long long tmp;
136 char* p = NULL;
137
138 if (!_s || !_v) {
139 LM_ERR("Invalid parameter value\n");
140 return -1;
141 }
142
143 tmp = strtoll(_s, &p, 10);
144 if (errno == ERANGE) {
145 LM_ERR("Value out of range\n");
146 return -1;
147 }
148 if (p && *p != '\0') {
149 LM_ERR("Unexpected characters: [%s]\n", p);
150 return -2;
151 }
152
153 *_v = tmp;
154 return 0;
155 }
156
157
158 /**
159 *
160 */
db_str2ulonglong(const char * _s,unsigned long long * _v)161 int db_str2ulonglong(const char* _s, unsigned long long * _v)
162 {
163 unsigned long long tmp;
164 char* p = NULL;
165
166 if (!_s || !_v) {
167 LM_ERR("Invalid parameter value\n");
168 return -1;
169 }
170
171 tmp = strtoull(_s, &p, 10);
172 if (errno == ERANGE) {
173 LM_ERR("Value out of range\n");
174 return -1;
175 }
176 if (p && *p != '\0') {
177 LM_ERR("Unexpected characters: [%s]\n", p);
178 return -2;
179 }
180
181 *_v = tmp;
182 return 0;
183 }
184
185
186 /*
187 * Convert a string to double
188 */
db_str2double(const char * _s,double * _v)189 int db_str2double(const char* _s, double* _v)
190 {
191 if ((!_s) || (!_v)) {
192 LM_ERR("Invalid parameter value\n");
193 return -1;
194 }
195
196 *_v = atof(_s);
197 return 0;
198 }
199
200
201 /*
202 * Convert an integer to string
203 */
db_int2str(int _v,char * _s,int * _l)204 int db_int2str(int _v, char* _s, int* _l)
205 {
206 int ret;
207
208 if ((!_s) || (!_l) || (!*_l)) {
209 LM_ERR("Invalid parameter value\n");
210 return -1;
211 }
212
213 ret = snprintf(_s, *_l, "%-d", _v);
214 if (ret < 0 || ret >= *_l) {
215 LM_ERR("Error in snprintf\n");
216 return -1;
217 }
218 *_l = ret;
219
220 return 0;
221 }
222
223
224 /*
225 * Convert an unsigned integer to string
226 */
db_uint2str(unsigned int _v,char * _s,int * _l)227 int db_uint2str(unsigned int _v, char* _s, int* _l)
228 {
229 int ret;
230
231 if ((!_s) || (!_l) || (!*_l)) {
232 LM_ERR("Invalid parameter value\n");
233 return -1;
234 }
235
236 ret = snprintf(_s, *_l, "%u", _v);
237 if (ret < 0 || ret >= *_l) {
238 LM_ERR("Error in snprintf\n");
239 return -1;
240 }
241 *_l = ret;
242
243 return 0;
244 }
245
246
247 /*
248 * Convert a long long to string
249 */
db_longlong2str(long long _v,char * _s,int * _l)250 int db_longlong2str(long long _v, char* _s, int* _l)
251 {
252 int ret;
253
254 if ((!_s) || (!_l) || (!*_l)) {
255 LM_ERR("Invalid parameter value\n");
256 return -1;
257 }
258
259 ret = snprintf(_s, *_l, "%-lld", _v);
260 if (ret < 0 || ret >= *_l) {
261 LM_ERR("Error in snprintf\n");
262 return -1;
263 }
264 *_l = ret;
265
266 return 0;
267 }
268
269
270 /*
271 * Convert an unsigned long long to string
272 */
db_ulonglong2str(unsigned long long _v,char * _s,int * _l)273 int db_ulonglong2str(unsigned long long _v, char* _s, int* _l)
274 {
275 int ret;
276
277 if ((!_s) || (!_l) || (!*_l)) {
278 LM_ERR("Invalid parameter value\n");
279 return -1;
280 }
281
282 ret = snprintf(_s, *_l, "%llu", _v);
283 if (ret < 0 || ret >= *_l) {
284 LM_ERR("Error in snprintf\n");
285 return -1;
286 }
287 *_l = ret;
288
289 return 0;
290 }
291
292
293 /*
294 * Convert a double to string
295 */
db_double2str(double _v,char * _s,int * _l)296 int db_double2str(double _v, char* _s, int* _l)
297 {
298 int ret;
299
300 if ((!_s) || (!_l) || (!*_l)) {
301 LM_ERR("Invalid parameter value\n");
302 return -1;
303 }
304
305 ret = snprintf(_s, *_l, "%-10.6f", _v);
306 if (ret < 0 || ret >= *_l) {
307 LM_ERR("Error in snprintf\n");
308 return -1;
309 }
310 *_l = ret;
311
312 return 0;
313 }
314
315
316 /*
317 * Convert a string to time_t
318 */
db_str2time(const char * _s,time_t * _v)319 int db_str2time(const char* _s, time_t* _v)
320 {
321 struct tm time;
322
323 if ((!_s) || (!_v)) {
324 LM_ERR("Invalid parameter value\n");
325 return -1;
326 }
327
328 /* Convert database time representation to time_t structure
329 * It is necessary to zero tm structure first */
330 memset(&time, '\0', sizeof(struct tm));
331 if (strptime(_s, "%Y-%m-%d %H:%M:%S", &time) == NULL) {
332 LM_ERR("Error during time conversion\n");
333 return -1;
334 }
335
336 /* Daylight saving information got lost in the database
337 * so let mktime to guess it. This eliminates the bug when
338 * contacts reloaded from the database have different time
339 * of expiration by one hour when daylight saving is used
340 */
341 time.tm_isdst = -1;
342 *_v = mktime(&time);
343
344 return 0;
345 }
346
347
348 /**
349 *
350 */
db_time2str_ex(time_t _v,char * _s,int * _l,int _qmode)351 int db_time2str_ex(time_t _v, char* _s, int* _l, int _qmode)
352 {
353 struct tm t;
354 int l;
355
356 if ((!_s) || (!_l) || (*_l < 2)) {
357 LM_ERR("Invalid parameter value\n");
358 return -1;
359 }
360
361 if(_qmode) *_s++ = '\'';
362
363 /* Convert time_t structure to format accepted by the database */
364 localtime_r(&_v, &t);
365 l = strftime(_s, *_l -1, "%Y-%m-%d %H:%M:%S", &t);
366
367 if (l == 0) {
368 LM_ERR("Error during time conversion\n");
369 /* the value of _s is now unspecified */
370 _s = NULL;
371 _l = 0;
372 return -1;
373 }
374 *_l = l;
375
376 if(_qmode) {
377 *(_s + l) = '\'';
378 *_l = l + 2;
379 }
380 return 0;
381 }
382
383 /**
384 *
385 */
db_time2str(time_t _v,char * _s,int * _l)386 int db_time2str(time_t _v, char* _s, int* _l)
387 {
388 return db_time2str_ex(_v, _s, _l, 1);
389 }
390
391 /*
392 * Print list of columns separated by comma
393 */
db_print_columns(char * _b,const int _l,const db_key_t * _c,const int _n,const char * _tq)394 int db_print_columns(char* _b, const int _l, const db_key_t* _c, const int _n, const char *_tq)
395 {
396 int i, ret, len = 0;
397
398 if ((!_c) || (!_n) || (!_b) || (!_l)) {
399 LM_ERR("Invalid parameter value\n");
400 return -1;
401 }
402
403 for(i = 0; i < _n; i++) {
404 if (i == (_n - 1)) {
405 ret = snprintf(_b + len, _l - len, "%s%.*s%s ", _tq, _c[i]->len, _c[i]->s, _tq);
406 if (ret < 0 || ret >= (_l - len)) goto error;
407 len += ret;
408 } else {
409 ret = snprintf(_b + len, _l - len, "%s%.*s%s,", _tq, _c[i]->len, _c[i]->s, _tq);
410 if (ret < 0 || ret >= (_l - len)) goto error;
411 len += ret;
412 }
413 }
414 return len;
415
416 error:
417 LM_ERR("Error in snprintf\n");
418 return -1;
419 }
420
421
422 /*
423 * Print values of SQL statement
424 */
db_print_values(const db1_con_t * _c,char * _b,const int _l,const db_val_t * _v,const int _n,int (* val2str)(const db1_con_t *,const db_val_t *,char *,int *))425 int db_print_values(const db1_con_t* _c, char* _b, const int _l, const db_val_t* _v,
426 const int _n, int (*val2str)(const db1_con_t*, const db_val_t*, char*, int*))
427 {
428 int i, l, len = 0;
429
430 if (!_c || !_b || !_l || !_v || !_n) {
431 LM_ERR("Invalid parameter value\n");
432 return -1;
433 }
434
435 for(i = 0; i < _n; i++) {
436 l = _l - len;
437 if ( (*val2str)(_c, _v + i, _b + len, &l) < 0) {
438 LM_ERR("Error while converting value to string\n");
439 return -1;
440 }
441 len += l;
442 if (i != (_n - 1)) {
443 *(_b + len) = ',';
444 len++;
445 }
446 }
447 return len;
448 }
449
450
451 /*
452 * Print where clause of SQL statement
453 */
db_print_where(const db1_con_t * _c,char * _b,const int _l,const db_key_t * _k,const db_op_t * _o,const db_val_t * _v,const int _n,int (* val2str)(const db1_con_t *,const db_val_t *,char *,int *))454 int db_print_where(const db1_con_t* _c, char* _b, const int _l, const db_key_t* _k,
455 const db_op_t* _o, const db_val_t* _v, const int _n, int (*val2str)
456 (const db1_con_t*, const db_val_t*, char*, int*))
457 {
458 int i, l, ret, len = 0;
459
460 if (!_c || !_b || !_l || !_k || !_v || !_n) {
461 LM_ERR("Invalid parameter value\n");
462 return -1;
463 }
464
465 for(i = 0; i < _n; i++) {
466 if (_o && strncmp(_o[i], OP_BITWISE_AND, 1) == 0) {
467 char tmp_buf[16];
468 int tmp_len = 15;
469 memset(tmp_buf, 0, 16);
470 if ((*val2str)(_c, &(_v[i]), tmp_buf, &tmp_len) < 0) {
471 LM_ERR("Error while converting value to string\n");
472 return -1;
473 }
474 ret = snprintf(_b + len, _l - len, "%s%.*s%s&%.*s=%.*s", CON_TQUOTESZ(_c),
475 _k[i]->len, _k[i]->s, CON_TQUOTESZ(_c), tmp_len, tmp_buf, tmp_len, tmp_buf);
476 if (ret < 0 || ret >= (_l - len)) goto error;
477 len += ret;
478 } else {
479 if (_o) {
480 ret = snprintf(_b + len, _l - len, "%s%.*s%s%s", CON_TQUOTESZ(_c),
481 _k[i]->len, _k[i]->s, CON_TQUOTESZ(_c), _o[i]);
482 if (ret < 0 || ret >= (_l - len)) goto error;
483 len += ret;
484 } else {
485 ret = snprintf(_b + len, _l - len, "%s%.*s%s=", CON_TQUOTESZ(_c),
486 _k[i]->len, _k[i]->s, CON_TQUOTESZ(_c));
487 if (ret < 0 || ret >= (_l - len)) goto error;
488 len += ret;
489 }
490 l = _l - len;
491 if ( (*val2str)(_c, &(_v[i]), _b + len, &l) < 0) {
492 LM_ERR("Error while converting value to string\n");
493 return -1;
494 }
495 len += l;
496 }
497
498 if (i != (_n - 1)) {
499 ret = snprintf(_b + len, _l - len, " AND ");
500 if (ret < 0 || ret >= (_l - len)) goto error;
501 len += ret;
502 }
503 }
504 return len;
505
506 error:
507 LM_ERR("Error in snprintf\n");
508 return -1;
509 }
510
511
512 /*
513 * Print set clause of update SQL statement
514 */
db_print_set(const db1_con_t * _c,char * _b,const int _l,const db_key_t * _k,const db_val_t * _v,const int _n,int (* val2str)(const db1_con_t *,const db_val_t *,char *,int *))515 int db_print_set(const db1_con_t* _c, char* _b, const int _l, const db_key_t* _k,
516 const db_val_t* _v, const int _n, int (*val2str)(const db1_con_t*,
517 const db_val_t*,char*, int*))
518 {
519 int i, l, ret, len = 0;
520
521 if (!_c || !_b || !_l || !_k || !_v || !_n) {
522 LM_ERR("Invalid parameter value\n");
523 return -1;
524 }
525
526 for(i = 0; i < _n; i++) {
527 ret = snprintf(_b + len, _l - len, "%s%.*s%s=",
528 CON_TQUOTESZ(_c), _k[i]->len, _k[i]->s, CON_TQUOTESZ(_c));
529 if (ret < 0 || ret >= (_l - len)) goto error;
530 len += ret;
531
532 l = _l - len;
533 if ( (*val2str)(_c, &(_v[i]), _b + len, &l) < 0) {
534 LM_ERR("Error while converting value to string\n");
535 return -1;
536 }
537 len += l;
538 if (i != (_n - 1)) {
539 if ((_l - len) >= 1) {
540 *(_b + len++) = ',';
541 }
542 }
543 }
544 return len;
545
546 error:
547 LM_ERR("Error in snprintf\n");
548 return -1;
549 }
550
551 /*
552 * Convert db_val to pv_spec
553 */
db_val2pv_spec(struct sip_msg * msg,db_val_t * dbval,pv_spec_t * pvs)554 int db_val2pv_spec(struct sip_msg* msg, db_val_t *dbval, pv_spec_t *pvs)
555 {
556 pv_value_t pv;
557 #define LL_LEN 21 /* sign, 19 digits and \0 */
558 static char ll_buf[LL_LEN];
559
560 if(dbval->nul)
561 {
562 pv.flags = PV_VAL_NULL;
563 } else
564 {
565 switch(dbval->type)
566 {
567 case DB1_STRING:
568 pv.flags = PV_VAL_STR;
569 pv.rs.s = (char*)dbval->val.string_val;
570 pv.rs.len = strlen(pv.rs.s);
571 break;
572 case DB1_STR:
573 pv.flags = PV_VAL_STR;
574 pv.rs.s = (char*)dbval->val.str_val.s;
575 pv.rs.len = dbval->val.str_val.len;
576 break;
577 case DB1_BLOB:
578 pv.flags = PV_VAL_STR;
579 pv.rs.s = (char*)dbval->val.blob_val.s;
580 pv.rs.len = dbval->val.blob_val.len;
581 break;
582 case DB1_INT:
583 pv.flags = PV_VAL_INT | PV_TYPE_INT;
584 pv.ri = (int)dbval->val.int_val;
585 break;
586 case DB1_DATETIME:
587 pv.flags = PV_VAL_INT | PV_TYPE_INT;
588 pv.ri = (int)dbval->val.time_val;
589 break;
590 case DB1_BITMAP:
591 pv.flags = PV_VAL_INT | PV_TYPE_INT;
592 pv.ri = (int)dbval->val.bitmap_val;
593 break;
594 case DB1_BIGINT:
595 /* BIGINT is stored as string */
596 pv.flags = PV_VAL_STR;
597 pv.rs.len = LL_LEN;
598 db_longlong2str(dbval->val.ll_val, ll_buf, &pv.rs.len);
599 pv.rs.s = ll_buf;
600 /* if it fits, also store as 32 bit integer*/
601 if (! ((unsigned long long)dbval->val.ll_val & 0xffffffff00000000ULL)) {
602 pv.flags |= PV_VAL_INT | PV_TYPE_INT;
603 pv.ri = (int)dbval->val.ll_val;
604 }
605 break;
606 default:
607 LM_NOTICE("unknown field type: %d, setting value to null\n",
608 dbval->type);
609 pv.flags = PV_VAL_NULL;
610 }
611 }
612
613 /* null values are ignored for avp type PV */
614 if (pv.flags == PV_VAL_NULL && pvs->type == PVT_AVP)
615 return 0;
616
617 /* add value to result pv */
618 if (pv_set_spec_value(msg, pvs, 0, &pv) != 0)
619 {
620 LM_ERR("Failed to add value to spec\n");
621 return -1;
622 }
623
624 return 0;
625 }
626