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