Browse code

db_text: safety check for lres

Daniel-Constantin Mierla authored on 13/04/2021 07:15:10
Showing 1 changed files
... ...
@@ -915,7 +915,7 @@ dbt_row_p dbt_result_extract_results(dbt_table_p _dtp, dbt_row_p* pRows, int _nr
915 915
 	dbt_row_p pPrvRow=NULL;
916 916
 	int i, n, r;
917 917
 
918
-	if(!_dtp || !pRows || _ncols<=0)
918
+	if(!_dtp || !pRows || _ncols<=0 || !_lres)
919 919
 		return NULL;
920 920
 
921 921
 	for(r=0; r < _nrows; r++) {
Browse code

db_text: use reallocxf() to handle realloc failure

Daniel-Constantin Mierla authored on 10/08/2017 10:15:23
Showing 1 changed files
... ...
@@ -721,7 +721,7 @@ int dbt_mangle_columnselection(int **_lres, int *_nc, int *_o_nc, int *_o_l, int
721 721
 		return 0; /* all order-by columns also selected, we're fine */
722 722
 
723 723
 	/* make _lres bigger */
724
-	*_lres = pkg_realloc(*_lres, sizeof(int) * (*_nc + *_o_nc));
724
+	*_lres = pkg_reallocxf(*_lres, sizeof(int) * (*_nc + *_o_nc));
725 725
 	if (! *_lres)
726 726
 		return -1;
727 727
 
Browse code

db_text: implement fetch and memory constraints

when dealing with large db_text files, pkg_memory is not suitable for
operating the database.

implementing fetch allows modules like presence & registrar & usrloc
to query large tables without constraints on pkg_memory.

creates tmp tables in shared memory for query results

(cherry picked from commit 18c64d2c9ff1527655055f75aa22e7d68c307874)

Conflicts:
src/modules/db_text/db_text.c
src/modules/db_text/dbt_api.c
src/modules/db_text/dbt_base.c
src/modules/db_text/dbt_lib.c

lazedo authored on 18/01/2017 10:00:22 • Luis Azedo committed on 18/01/2017 10:30:32
Showing 1 changed files
... ...
@@ -92,7 +92,7 @@ clean:
92 92
 	return NULL;
93 93
 }
94 94
 
95
-int dbt_result_free(dbt_result_p _dres)
95
+int _dbt_result_free(dbt_result_p _dres)
96 96
 {
97 97
 	dbt_row_p _rp=NULL, _rp0=NULL;
98 98
 	int i;
... ...
@@ -134,6 +134,22 @@ int dbt_result_free(dbt_result_p _dres)
134 134
 	return 0;
135 135
 }
136 136
 
137
+int dbt_result_free(db1_con_t* _h, dbt_table_p _dres)
138
+{
139
+	if ((!_h))
140
+	{
141
+		LM_ERR("invalid parameter value\n");
142
+		return -1;
143
+	}
144
+
145
+	if (!_dres)
146
+		return 0;
147
+
148
+	dbt_db_del_table(DBT_CON_CONNECTION(_h), &_dres->name, 1);
149
+
150
+	return 0;
151
+}
152
+
137 153
 int dbt_result_add_row(dbt_result_p _dres, dbt_row_p _drp)
138 154
 {
139 155
 	if(!_dres || !_drp)
... ...
@@ -316,45 +332,48 @@ clean:
316 332
 	return -1;
317 333
 }
318 334
 
319
-int dbt_result_print(dbt_result_p _dres)
335
+int dbt_result_print(dbt_table_p _dres)
320 336
 {
321
-#if 0
322 337
 	int i;
323
-	FILE *fout = stdout;
338
+	FILE *fout = stderr;
324 339
 	dbt_row_p rowp = NULL;
325 340
 	char *p;
326 341
 
327
-	if(!_dres || _dres->nrcols<=0)
342
+	if(!_dres || _dres->nrcols<=0) {
343
+		LM_INFO("NO PRINT\n");
328 344
 		return -1;
345
+	}
329 346
 
330 347
 	fprintf(fout, "\nContent of result\n");
331 348
 
332 349
 	for(i=0; i<_dres->nrcols; i++)
333 350
 	{
334
-		switch(_dres->colv[i].type)
351
+		switch(_dres->colv[i]->type)
335 352
 		{
336 353
 			case DB1_INT:
337
-				fprintf(fout, "%.*s(int", _dres->colv[i].name.len,
338
-								_dres->colv[i].name.s);
339
-				if(_dres->colv[i].flag & DBT_FLAG_NULL)
354
+				fprintf(fout, "%.*s(int", _dres->colv[i]->name.len,
355
+								_dres->colv[i]->name.s);
356
+				if(_dres->colv[i]->flag & DBT_FLAG_NULL)
340 357
 					fprintf(fout, ",null");
341 358
 				fprintf(fout, ") ");
342 359
 			break;
343 360
 			case DB1_DOUBLE:
344
-				fprintf(fout, "%.*s(double", _dres->colv[i].name.len,
345
-							_dres->colv[i].name.s);
346
-				if(_dres->colv[i].flag & DBT_FLAG_NULL)
361
+				fprintf(fout, "%.*s(double", _dres->colv[i]->name.len,
362
+							_dres->colv[i]->name.s);
363
+				if(_dres->colv[i]->flag & DBT_FLAG_NULL)
347 364
 					fprintf(fout, ",null");
348 365
 				fprintf(fout, ") ");
349 366
 			break;
350 367
 			case DB1_STR:
351
-				fprintf(fout, "%.*s(str", _dres->colv[i].name.len,
352
-						_dres->colv[i].name.s);
353
-				if(_dres->colv[i].flag & DBT_FLAG_NULL)
368
+			case DB1_STRING:
369
+				fprintf(fout, "%.*s(str", _dres->colv[i]->name.len,
370
+						_dres->colv[i]->name.s);
371
+				if(_dres->colv[i]->flag & DBT_FLAG_NULL)
354 372
 					fprintf(fout, ",null");
355 373
 				fprintf(fout, ") ");
356 374
 			break;
357 375
 			default:
376
+				LM_INFO("TYPE NOT HANDLED %i\n", _dres->colv[i]->type);
358 377
 				return -1;
359 378
 		}
360 379
 	}
... ...
@@ -364,7 +383,7 @@ int dbt_result_print(dbt_result_p _dres)
364 383
 	{
365 384
 		for(i=0; i<_dres->nrcols; i++)
366 385
 		{
367
-			switch(_dres->colv[i].type)
386
+			switch(_dres->colv[i]->type)
368 387
 			{
369 388
 				case DB1_INT:
370 389
 					if(rowp->fields[i].nul)
... ...
@@ -381,6 +400,7 @@ int dbt_result_print(dbt_result_p _dres)
381 400
 								rowp->fields[i].val.double_val);
382 401
 				break;
383 402
 				case DB1_STR:
403
+				case DB1_STRING:
384 404
 					fprintf(fout, "\"");
385 405
 					if(!rowp->fields[i].nul)
386 406
 					{
... ...
@@ -423,7 +443,6 @@ int dbt_result_print(dbt_result_p _dres)
423 443
 		fprintf(fout, "\n");
424 444
 		rowp = rowp->next;
425 445
 	}
426
-#endif
427 446
 
428 447
 	return 0;
429 448
 }
... ...
@@ -526,6 +545,29 @@ dbt_row_p dbt_result_new_row(dbt_result_p _dres)
526 545
 	return _drp;
527 546
 }
528 547
 
548
+//dbt_row_p dbt_result_new_rows(dbt_row_p* _res, int rows, int cols)
549
+//{
550
+//	dbt_row_p _drp = NULL;
551
+//	if(!_dres || _dres->nrcols<=0)
552
+//		return NULL;
553
+//
554
+//	_drp = (dbt_row_p)shm_malloc(sizeof(dbt_row_t) * rows);
555
+//	if(!_drp)
556
+//		return NULL;
557
+//	memset(_drp, 0, sizeof(dbt_row_t));
558
+//	_drp->fields = (dbt_val_p)shm_malloc(_dres->nrcols*sizeof(dbt_val_t));
559
+//	if(!_drp->fields)
560
+//	{
561
+//		shm_free(_drp);
562
+//		return NULL;
563
+//	}
564
+//	memset(_drp->fields, 0, _dres->nrcols*sizeof(dbt_val_t));
565
+//
566
+//	_drp->next = _drp->prev = NULL;
567
+//
568
+//	return _drp;
569
+//}
570
+
529 571
 
530 572
 /* The _o clause to query is not really a db_key_t, it is SQL (str).
531 573
  * db_mysql and db_postgres simply paste it into SQL, we need to parse it. */
... ...
@@ -824,3 +866,129 @@ void dbt_project_result(dbt_result_p _dres, int _o_nc)
824 866
 	_dres->nrcols -= _o_nc;
825 867
 }
826 868
 
869
+/* comparison function for qsort */
870
+int dbt_qsort_compare_temp(const void *_a, const void *_b)
871
+{
872
+	int _i, _j, _r;
873
+
874
+	for (_i=0; _i<dbt_sort_o_n; _i++)
875
+	{
876
+		_j = dbt_sort_o_l[_i];
877
+		_r = dbt_cmp_val(&(*(dbt_row_p *)_a)->fields[_j], &(*(dbt_row_p *)_b)->fields[_j]);
878
+		if (_r == 0)
879
+			continue; /* no result yet, compare next column */
880
+		if (_r == +1 || _r == -1)
881
+			return (dbt_sort_o_op[_i] == '<') ? _r : -_r; /* ASC OR DESC */
882
+		/* error */
883
+		longjmp(dbt_sort_jmpenv, _r);
884
+	}
885
+
886
+	/* no result after comparing all columns, same */
887
+	return 0;
888
+}
889
+
890
+int dbt_sort_result_temp(dbt_row_p *_res, int count, int *_o_l, char *_o_op, int _o_n)
891
+{
892
+	int _i;
893
+
894
+	/* set globals */
895
+	dbt_sort_o_l = _o_l;
896
+	dbt_sort_o_op = _o_op;
897
+	dbt_sort_o_n = _o_n;
898
+	_i = setjmp(dbt_sort_jmpenv);  /* exception handling */
899
+	if (_i)
900
+	{
901
+		/* error occured during qsort */
902
+		LM_ERR("qsort aborted\n");
903
+		return _i;
904
+	}
905
+
906
+	qsort(_res, count, sizeof(dbt_row_p), &dbt_qsort_compare_temp);
907
+
908
+	return 0;
909
+}
910
+
911
+dbt_row_p dbt_result_extract_results(dbt_table_p _dtp, dbt_row_p* pRows, int _nrows, int* _lres, int _ncols)
912
+{
913
+	dbt_row_p pRow=NULL;
914
+	dbt_row_p pTopRow=NULL;
915
+	dbt_row_p pPrvRow=NULL;
916
+	int i, n, r;
917
+
918
+	if(!_dtp || !pRows || _ncols<=0)
919
+		return NULL;
920
+
921
+	for(r=0; r < _nrows; r++) {
922
+		pRow = dbt_row_new(_ncols);
923
+
924
+		for(i=0; i<_ncols; i++)
925
+		{
926
+			n = _lres[i];
927
+			pRow->fields[i].nul = pRows[r]->fields[n].nul;
928
+			if(pRow->fields[i].nul)
929
+			{
930
+				memset(&(pRow->fields[i].val), 0, sizeof(pRow->fields[i].val));
931
+				continue;
932
+			}
933
+
934
+			switch(_dtp->colv[n]->type)
935
+			{
936
+				case DB1_INT:
937
+				case DB1_DATETIME:
938
+				case DB1_BITMAP:
939
+					pRow->fields[i].type = _dtp->colv[n]->type;
940
+					pRow->fields[i].val.int_val = pRows[r]->fields[n].val.int_val;
941
+				break;
942
+				case DB1_DOUBLE:
943
+					pRow->fields[i].type = DB1_DOUBLE;
944
+					pRow->fields[i].val.double_val=pRows[r]->fields[n].val.double_val;
945
+				break;
946
+				case DB1_STRING:
947
+				case DB1_STR:
948
+				case DB1_BLOB:
949
+					pRow->fields[i].type = _dtp->colv[n]->type;
950
+					pRow->fields[i].val.str_val.len =
951
+							pRows[r]->fields[n].val.str_val.len;
952
+					pRow->fields[i].val.str_val.s =(char*)shm_malloc(sizeof(char)*
953
+							(pRows[r]->fields[n].val.str_val.len+1));
954
+					if(!pRow->fields[i].val.str_val.s)
955
+						goto clean;
956
+					memcpy(pRow->fields[i].val.str_val.s,
957
+							pRows[r]->fields[n].val.str_val.s,
958
+							pRows[r]->fields[n].val.str_val.len);
959
+					pRow->fields[i].val.str_val.s[pRows[r]->fields[n].val.str_val.len]=0;
960
+				break;
961
+				default:
962
+					goto clean;
963
+			}
964
+		}
965
+
966
+		if(pTopRow == NULL) {
967
+			pTopRow = pRow;
968
+		} else {
969
+			pRow->prev = pPrvRow;
970
+			pPrvRow->next = pRow;
971
+		}
972
+		pPrvRow = pRow;
973
+	}
974
+
975
+	return pTopRow;
976
+
977
+clean:
978
+	LM_DBG("make clean!\n");
979
+	while(i>=0)
980
+	{
981
+		if((pRow->fields[i].type == DB1_STRING
982
+					|| pRow->fields[i].type == DB1_STR
983
+					|| pRow->fields[i].type == DB1_BLOB)
984
+				&& !pRow->fields[i].nul
985
+				&& pRow->fields[i].val.str_val.s)
986
+			shm_free(pRow->fields[i].val.str_val.s);
987
+
988
+		i--;
989
+	}
990
+	shm_free(pRow->fields);
991
+	shm_free(pRow);
992
+
993
+	return pTopRow;
994
+}
Browse code

core, lib, modules: updated include paths for header files

Daniel-Constantin Mierla authored on 07/12/2016 11:07:22
Showing 1 changed files
... ...
@@ -27,7 +27,7 @@
27 27
 #include <stdlib.h>
28 28
 #include <setjmp.h>
29 29
 
30
-#include "../../mem/mem.h"
30
+#include "../../core/mem/mem.h"
31 31
 
32 32
 #include "dbt_res.h"
33 33
 
Browse code

core, lib, modules: restructured source code tree

- new folder src/ to hold the source code for main project applications
- main.c is in src/
- all core files are subfolder are in src/core/
- modules are in src/modules/
- libs are in src/lib/
- application Makefiles are in src/
- application binary is built in src/ (src/kamailio)

Daniel-Constantin Mierla authored on 07/12/2016 11:03:51
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,826 @@
1
+/*
2
+ * DBText module core functions
3
+ *
4
+ * Copyright (C) 2001-2003 FhG Fokus
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
+ *
22
+ */
23
+
24
+#include <stdio.h>
25
+#include <string.h>
26
+#include <sys/types.h>
27
+#include <stdlib.h>
28
+#include <setjmp.h>
29
+
30
+#include "../../mem/mem.h"
31
+
32
+#include "dbt_res.h"
33
+
34
+#define SIGN(_i) ((_i) > 0 ? 1 : ((_i) < 0 ? -1 : 0))
35
+
36
+dbt_result_p dbt_result_new(dbt_table_p _dtp, int *_lres, int _sz)
37
+{
38
+	dbt_result_p _dres = NULL;
39
+	int i, n;
40
+	char *p;
41
+
42
+	if(!_dtp || _sz < 0)
43
+		return NULL;
44
+
45
+	if(!_lres)
46
+		_sz = _dtp->nrcols;
47
+
48
+	_dres = (dbt_result_p)pkg_malloc(sizeof(dbt_result_t));
49
+	if(!_dres)
50
+		return NULL;
51
+	_dres->colv = (dbt_column_p)pkg_malloc(_sz*sizeof(dbt_column_t));
52
+	if(!_dres->colv)
53
+	{
54
+		LM_DBG("no pkg memory!\n");
55
+		pkg_free(_dres);
56
+		return NULL;
57
+	}
58
+	memset(_dres->colv, 0, _sz*sizeof(dbt_column_t));
59
+	LM_DBG("new res with %d cols\n", _sz);
60
+	for(i = 0; i < _sz; i++)
61
+	{
62
+		n = (_lres)?_dtp->colv[_lres[i]]->name.len:_dtp->colv[i]->name.len;
63
+		p = (_lres)?_dtp->colv[_lres[i]]->name.s:_dtp->colv[i]->name.s;
64
+		_dres->colv[i].name.s = (char*)pkg_malloc((n+1)*sizeof(char));
65
+		if(!_dres->colv[i].name.s)
66
+		{
67
+			LM_DBG("no pkg memory\n");
68
+			goto clean;
69
+		}
70
+		_dres->colv[i].name.len = n;
71
+		strncpy(_dres->colv[i].name.s, p, n);
72
+		_dres->colv[i].name.s[n] = 0;
73
+		_dres->colv[i].type =
74
+				(_lres)?_dtp->colv[_lres[i]]->type:_dtp->colv[i]->type;
75
+	}
76
+
77
+	_dres->nrcols = _sz;
78
+	_dres->nrrows = 0;
79
+	_dres->rows = NULL;
80
+
81
+	return _dres;
82
+clean:
83
+	while(i>=0)
84
+	{
85
+		if(_dres->colv[i].name.s)
86
+			pkg_free(_dres->colv[i].name.s);
87
+		i--;
88
+	}
89
+	pkg_free(_dres->colv);
90
+	pkg_free(_dres);
91
+
92
+	return NULL;
93
+}
94
+
95
+int dbt_result_free(dbt_result_p _dres)
96
+{
97
+	dbt_row_p _rp=NULL, _rp0=NULL;
98
+	int i;
99
+
100
+	if(!_dres)
101
+		return -1;
102
+	_rp = _dres->rows;
103
+	while(_rp)
104
+	{
105
+		_rp0=_rp;
106
+		_rp=_rp->next;
107
+		if(_rp0->fields)
108
+		{
109
+			for(i=0; i<_dres->nrcols; i++)
110
+			{
111
+				if((_dres->colv[i].type==DB1_STR
112
+							|| _dres->colv[i].type==DB1_STRING
113
+							|| _dres->colv[i].type==DB1_BLOB
114
+							)
115
+						&& _rp0->fields[i].val.str_val.s)
116
+					pkg_free(_rp0->fields[i].val.str_val.s);
117
+			}
118
+			pkg_free(_rp0->fields);
119
+		}
120
+		pkg_free(_rp0);
121
+	}
122
+	if(_dres->colv)
123
+	{
124
+		for(i=0; i<_dres->nrcols; i++)
125
+		{
126
+			if(_dres->colv[i].name.s)
127
+				pkg_free(_dres->colv[i].name.s);
128
+		}
129
+		pkg_free(_dres->colv);
130
+	}
131
+
132
+	pkg_free(_dres);
133
+
134
+	return 0;
135
+}
136
+
137
+int dbt_result_add_row(dbt_result_p _dres, dbt_row_p _drp)
138
+{
139
+	if(!_dres || !_drp)
140
+		return -1;
141
+	_dres->nrrows++;
142
+
143
+	if(_dres->rows)
144
+		(_dres->rows)->prev = _drp;
145
+	_drp->next = _dres->rows;
146
+	_dres->rows = _drp;
147
+
148
+	return 0;
149
+}
150
+
151
+int* dbt_get_refs(dbt_table_p _dtp, db_key_t* _k, int _n)
152
+{
153
+	int i, j, *_lref=NULL;
154
+
155
+	if(!_dtp || !_k || _n < 0)
156
+		return NULL;
157
+
158
+	_lref = (int*)pkg_malloc(_n*sizeof(int));
159
+	if(!_lref)
160
+		return NULL;
161
+
162
+	for(i=0; i < _n; i++)
163
+	{
164
+		for(j=0; j<_dtp->nrcols; j++)
165
+		{
166
+			if(_k[i]->len==_dtp->colv[j]->name.len
167
+				&& !strncasecmp(_k[i]->s, _dtp->colv[j]->name.s,
168
+						_dtp->colv[j]->name.len))
169
+			{
170
+				_lref[i] = j;
171
+				break;
172
+			}
173
+		}
174
+		if(j>=_dtp->nrcols)
175
+		{
176
+			LM_ERR("column <%.*s> not found\n", _k[i]->len, _k[i]->s);
177
+			pkg_free(_lref);
178
+			return NULL;
179
+		}
180
+	}
181
+	return _lref;
182
+}
183
+
184
+
185
+int dbt_row_match(dbt_table_p _dtp, dbt_row_p _drp, int* _lkey,
186
+			db_op_t* _op, db_val_t* _v, int _n)
187
+{
188
+	int i, res;
189
+	if(!_dtp || !_drp)
190
+		return 0;
191
+	if(!_lkey)
192
+		return 1;
193
+	for(i=0; i<_n; i++)
194
+	{
195
+		res = dbt_cmp_val(&_drp->fields[_lkey[i]], &_v[i]);
196
+		if(!_op || !strcmp(_op[i], OP_EQ))
197
+		{
198
+			if(res!=0)
199
+				return 0;
200
+		}else{
201
+		if(!strcmp(_op[i], OP_NEQ))
202
+		{
203
+			if(res==0)
204
+				return 0;
205
+		}else{
206
+		if(!strcmp(_op[i], OP_LT))
207
+		{
208
+			if(res!=-1)
209
+				return 0;
210
+		}else{
211
+		if(!strcmp(_op[i], OP_GT))
212
+		{
213
+			if(res!=1)
214
+				return 0;
215
+		}else{
216
+		if(!strcmp(_op[i], OP_LEQ))
217
+		{
218
+			if(res==1)
219
+				return 0;
220
+		}else{
221
+		if(!strcmp(_op[i], OP_GEQ))
222
+		{
223
+			if(res==-1)
224
+				return 0;
225
+		}else{
226
+			return 0;
227
+		}}}}}}
228
+	}
229
+	return 1;
230
+}
231
+
232
+int dbt_result_extract_fields(dbt_table_p _dtp, dbt_row_p _drp,
233
+				int* _lres, dbt_result_p _dres)
234
+{
235
+	dbt_row_p _rp=NULL;
236
+	int i, n;
237
+
238
+	if(!_dtp || !_drp || !_dres || _dres->nrcols<=0)
239
+		return -1;
240
+
241
+	_rp = dbt_result_new_row(_dres);
242
+	if(!_rp)
243
+		return -1;
244
+
245
+	for(i=0; i<_dres->nrcols; i++)
246
+	{
247
+		n = (_lres)?_lres[i]:i;
248
+		if(dbt_is_neq_type(_dres->colv[i].type, _dtp->colv[n]->type))
249
+		{
250
+			LM_DBG("wrong types!\n");
251
+			goto clean;
252
+		}
253
+		_rp->fields[i].nul = _drp->fields[n].nul;
254
+		if(_rp->fields[i].nul)
255
+		{
256
+			memset(&(_rp->fields[i].val), 0, sizeof(_rp->fields[i].val));
257
+			continue;
258
+		}
259
+
260
+		switch(_dres->colv[i].type)
261
+		{
262
+			case DB1_INT:
263
+			case DB1_DATETIME:
264
+			case DB1_BITMAP:
265
+				_rp->fields[i].type = _dres->colv[i].type;
266
+				_rp->fields[i].val.int_val = _drp->fields[n].val.int_val;
267
+			break;
268
+			case DB1_DOUBLE:
269
+				_rp->fields[i].type = DB1_DOUBLE;
270
+				_rp->fields[i].val.double_val=_drp->fields[n].val.double_val;
271
+			break;
272
+			case DB1_STRING:
273
+			case DB1_STR:
274
+			case DB1_BLOB:
275
+				_rp->fields[i].type = _dres->colv[i].type;
276
+				_rp->fields[i].val.str_val.len =
277
+						_drp->fields[n].val.str_val.len;
278
+				_rp->fields[i].val.str_val.s =(char*)pkg_malloc(sizeof(char)*
279
+						(_drp->fields[n].val.str_val.len+1));
280
+				if(!_rp->fields[i].val.str_val.s)
281
+					goto clean;
282
+				memcpy(_rp->fields[i].val.str_val.s,
283
+						_drp->fields[n].val.str_val.s,
284
+						_rp->fields[i].val.str_val.len);
285
+				_rp->fields[i].val.str_val.s[_rp->fields[i].val.str_val.len]=0;
286
+			break;
287
+			default:
288
+				goto clean;
289
+		}
290
+	}
291
+
292
+	if(_dres->rows)
293
+		(_dres->rows)->prev = _rp;
294
+	_rp->next = _dres->rows;
295
+	_dres->rows = _rp;
296
+	_dres->nrrows++;
297
+
298
+	return 0;
299
+
300
+clean:
301
+	LM_DBG("make clean!\n");
302
+	while(i>=0)
303
+	{
304
+		if((_rp->fields[i].type == DB1_STRING
305
+					|| _rp->fields[i].type == DB1_STR
306
+					|| _rp->fields[i].type == DB1_BLOB)
307
+				&& !_rp->fields[i].nul
308
+				&& _rp->fields[i].val.str_val.s)
309
+			pkg_free(_rp->fields[i].val.str_val.s);
310
+
311
+		i--;
312
+	}
313
+	pkg_free(_rp->fields);
314
+	pkg_free(_rp);
315
+
316
+	return -1;
317
+}
318
+
319
+int dbt_result_print(dbt_result_p _dres)
320
+{
321
+#if 0
322
+	int i;
323
+	FILE *fout = stdout;
324
+	dbt_row_p rowp = NULL;
325
+	char *p;
326
+
327
+	if(!_dres || _dres->nrcols<=0)
328
+		return -1;
329
+
330
+	fprintf(fout, "\nContent of result\n");
331
+
332
+	for(i=0; i<_dres->nrcols; i++)
333
+	{
334
+		switch(_dres->colv[i].type)
335
+		{
336
+			case DB1_INT:
337
+				fprintf(fout, "%.*s(int", _dres->colv[i].name.len,
338
+								_dres->colv[i].name.s);
339
+				if(_dres->colv[i].flag & DBT_FLAG_NULL)
340
+					fprintf(fout, ",null");
341
+				fprintf(fout, ") ");
342
+			break;
343
+			case DB1_DOUBLE:
344
+				fprintf(fout, "%.*s(double", _dres->colv[i].name.len,
345
+							_dres->colv[i].name.s);
346
+				if(_dres->colv[i].flag & DBT_FLAG_NULL)
347
+					fprintf(fout, ",null");
348
+				fprintf(fout, ") ");
349
+			break;
350
+			case DB1_STR:
351
+				fprintf(fout, "%.*s(str", _dres->colv[i].name.len,
352
+						_dres->colv[i].name.s);
353
+				if(_dres->colv[i].flag & DBT_FLAG_NULL)
354
+					fprintf(fout, ",null");
355
+				fprintf(fout, ") ");
356
+			break;
357
+			default:
358
+				return -1;
359
+		}
360
+	}
361
+	fprintf(fout, "\n");
362
+	rowp = _dres->rows;
363
+	while(rowp)
364
+	{
365
+		for(i=0; i<_dres->nrcols; i++)
366
+		{
367
+			switch(_dres->colv[i].type)
368
+			{
369
+				case DB1_INT:
370
+					if(rowp->fields[i].nul)
371
+						fprintf(fout, "N ");
372
+					else
373
+						fprintf(fout, "%d ",
374
+								rowp->fields[i].val.int_val);
375
+				break;
376
+				case DB1_DOUBLE:
377
+					if(rowp->fields[i].nul)
378
+						fprintf(fout, "N ");
379
+					else
380
+						fprintf(fout, "%.2f ",
381
+								rowp->fields[i].val.double_val);
382
+				break;
383
+				case DB1_STR:
384
+					fprintf(fout, "\"");
385
+					if(!rowp->fields[i].nul)
386
+					{
387
+						p = rowp->fields[i].val.str_val.s;
388
+						while(p < rowp->fields[i].val.str_val.s
389
+								+ rowp->fields[i].val.str_val.len)
390
+						{
391
+							switch(*p)
392
+							{
393
+								case '\n':
394
+									fprintf(fout, "\\n");
395
+								break;
396
+								case '\r':
397
+									fprintf(fout, "\\r");
398
+								break;
399
+								case '\t':
400
+									fprintf(fout, "\\t");
401
+								break;
402
+								case '\\':
403
+									fprintf(fout, "\\\\");
404
+								break;
405
+								case '"':
406
+									fprintf(fout, "\\\"");
407
+								break;
408
+								case '\0':
409
+									fprintf(fout, "\\0");
410
+								break;
411
+								default:
412
+									fprintf(fout, "%c", *p);
413
+							}
414
+							p++;
415
+						}
416
+					}
417
+					fprintf(fout, "\" ");
418
+				break;
419
+				default:
420
+					return -1;
421
+			}
422
+		}
423
+		fprintf(fout, "\n");
424
+		rowp = rowp->next;
425
+	}
426
+#endif
427
+
428
+	return 0;
429
+}
430
+
431
+int dbt_cmp_val(dbt_val_p _vp, db_val_t* _v)
432
+{
433
+	int _l, _n;
434
+	if(!_vp && !_v)
435
+		return 0;
436
+	if(!_v)
437
+		return 1;
438
+	if(!_vp)
439
+		return -1;
440
+	if(_vp->nul && _v->nul)
441
+		return 0;
442
+	if(_v->nul)
443
+		return 1;
444
+	if(_vp->nul)
445
+		return -1;
446
+
447
+	switch(VAL_TYPE(_v))
448
+	{
449
+		case DB1_INT:
450
+			return (_vp->val.int_val<_v->val.int_val)?-1:
451
+					(_vp->val.int_val>_v->val.int_val)?1:0;
452
+
453
+		case DB1_BIGINT:
454
+			LM_ERR("BIGINT not supported\n");
455
+			return -1;
456
+
457
+		case DB1_DOUBLE:
458
+			return (_vp->val.double_val<_v->val.double_val)?-1:
459
+					(_vp->val.double_val>_v->val.double_val)?1:0;
460
+		case DB1_DATETIME:
461
+			return (_vp->val.int_val<_v->val.time_val)?-1:
462
+					(_vp->val.int_val>_v->val.time_val)?1:0;
463
+		case DB1_STRING:
464
+			_l = strlen(_v->val.string_val);
465
+			_l = (_l>_vp->val.str_val.len)?_vp->val.str_val.len:_l;
466
+			_n = strncasecmp(_vp->val.str_val.s, _v->val.string_val, _l);
467
+			if(_n)
468
+				return SIGN(_n);
469
+			if(_vp->val.str_val.len == strlen(_v->val.string_val))
470
+				return 0;
471
+			if(_l==_vp->val.str_val.len)
472
+				return -1;
473
+			return 1;
474
+		case DB1_STR:
475
+			_l = _v->val.str_val.len;
476
+			_l = (_l>_vp->val.str_val.len)?_vp->val.str_val.len:_l;
477
+			_n = strncasecmp(_vp->val.str_val.s, _v->val.str_val.s, _l);
478
+			if(_n)
479
+				return SIGN(_n);
480
+			if(_vp->val.str_val.len == _v->val.str_val.len)
481
+				return 0;
482
+			if(_l==_vp->val.str_val.len)
483
+				return -1;
484
+			return 1;
485
+		case DB1_BLOB:
486
+			_l = _v->val.blob_val.len;
487
+			_l = (_l>_vp->val.str_val.len)?_vp->val.str_val.len:_l;
488
+			_n = strncasecmp(_vp->val.str_val.s, _v->val.blob_val.s, _l);
489
+			if(_n)
490
+				return SIGN(_n);
491
+			if(_vp->val.str_val.len == _v->val.blob_val.len)
492
+				return 0;
493
+			if(_l==_vp->val.str_val.len)
494
+				return -1;
495
+			return 1;
496
+		case DB1_BITMAP:
497
+			return (_vp->val.int_val<_v->val.bitmap_val)?-1:
498
+				(_vp->val.int_val>_v->val.bitmap_val)?1:0;
499
+		default:
500
+			LM_ERR("invalid datatype %d\n", VAL_TYPE(_v));
501
+			return -2;
502
+	}
503
+	return -2;
504
+}
505
+
506
+dbt_row_p dbt_result_new_row(dbt_result_p _dres)
507
+{
508
+	dbt_row_p _drp = NULL;
509
+	if(!_dres || _dres->nrcols<=0)
510
+		return NULL;
511
+
512
+	_drp = (dbt_row_p)pkg_malloc(sizeof(dbt_row_t));
513
+	if(!_drp)
514
+		return NULL;
515
+	memset(_drp, 0, sizeof(dbt_row_t));
516
+	_drp->fields = (dbt_val_p)pkg_malloc(_dres->nrcols*sizeof(dbt_val_t));
517
+	if(!_drp->fields)
518
+	{
519
+		pkg_free(_drp);
520
+		return NULL;
521
+	}
522
+	memset(_drp->fields, 0, _dres->nrcols*sizeof(dbt_val_t));
523
+
524
+	_drp->next = _drp->prev = NULL;
525
+
526
+	return _drp;
527
+}
528
+
529
+
530
+/* The _o clause to query is not really a db_key_t, it is SQL (str).
531
+ * db_mysql and db_postgres simply paste it into SQL, we need to parse it. */
532
+/* Format of _o:  column1 [ASC|DESC], column2 [ASC|DESC], ... */
533
+int dbt_parse_orderbyclause(db_key_t **_o_k, char **_o_op, int *_o_n, db_key_t _o)
534
+{
535
+	char *_po, *_ps, *_pe;
536
+	char _c = '\0';
537
+	char _d[8];
538
+	int _n;
539
+	int _i;
540
+	str *_s;
541
+
542
+	/* scan _o, count ',' -> upper bound for no of columns */
543
+	_n = 1;
544
+	for (_i=0; _i < _o->len; _i++)
545
+		if (_o->s[_i] == ',')
546
+			_n++;
547
+
548
+	/* *_o_k will include the db_key_ts, the strs, a copy of _o and \0 */
549
+	*_o_k = pkg_malloc((sizeof(db_key_t)+sizeof(str)) * _n + _o->len + 1);
550
+	if (!*_o_k)
551
+		return -1;
552
+	_s = (str *)((char *)(*_o_k) + sizeof(db_key_t) * _n);
553
+	for (_i=0; _i < _n; _i++)
554
+		(*_o_k)[_i] = &_s[_i];
555
+	_po = (char *)(*_o_k) + (sizeof(db_key_t) + sizeof(str)) * _n;
556
+	memcpy(_po, _o->s, _o->len);
557
+	*(_po+_o->len) = '\0';
558
+
559
+	*_o_op = pkg_malloc(sizeof(char) * _n);
560
+	if (!*_o_op)
561
+	{
562
+		pkg_free(*_o_k);
563
+		return -1;
564
+	}
565
+
566
+	*_o_n = 0;
567
+	_ps = _po;
568
+	while (*_o_n < _n)
569
+	{
570
+		while (*_ps == ' ') _ps++;
571
+		if (*_ps == '\0')
572
+			break;
573
+		strcpy(_d, " \f\n\r\t\v,"); /* isspace() and comma */
574
+		if (*_ps == '"' || *_ps == '\'') /* detect quote */
575
+		{
576
+			_d[0] = *_ps;
577
+			_d[1] = '\0';
578
+			_ps++;
579
+		}
580
+		_pe = strpbrk(_ps, _d); /* search quote, space, comma or eos */
581
+		if (!_pe && _d[0] == ' ') /* if token is last token in string */
582
+			_pe = _po + _o->len; /* point to end of string */
583
+		if (! _pe) /* we were looking for quote but found none */
584
+			goto parse_error;
585
+
586
+		/* _ps points to start of column-name,
587
+		 * _pe points after the column-name, on quote, space, comma, or '\0' */
588
+		_c = *_pe;
589
+		*_pe = '\0';
590
+		(*_o_k)[*_o_n]->s = _ps;
591
+		(*_o_k)[*_o_n]->len = _pe - _ps;
592
+		(*_o_op)[*_o_n] = '<'; /* default */
593
+		(*_o_n)++;
594
+
595
+		if (_c == '\0')
596
+			break;
597
+
598
+		/* go beyond current tok