Browse code

- mysql module updated to new db api

Jan Janak authored on 04/04/2007 11:48:20
Showing 18 changed files
1 1
deleted file mode 100644
... ...
@@ -1,669 +0,0 @@
1
-/* 
2
- * $Id$ 
3
- *
4
- * MySQL module core functions
5
- *
6
- * Copyright (C) 2001-2003 FhG Fokus
7
- *
8
- * This file is part of ser, a free SIP server.
9
- *
10
- * ser is free software; you can redistribute it and/or modify
11
- * it under the terms of the GNU General Public License as published by
12
- * the Free Software Foundation; either version 2 of the License, or
13
- * (at your option) any later version
14
- *
15
- * For a license to use the ser software under conditions
16
- * other than those described here, or to purchase support for this
17
- * software, please contact iptel.org by e-mail at the following addresses:
18
- *    info@iptel.org
19
- *
20
- * ser is distributed in the hope that it will be useful,
21
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
- * GNU General Public License for more details.
24
- *
25
- * You should have received a copy of the GNU General Public License 
26
- * along with this program; if not, write to the Free Software 
27
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
- */
29
-
30
-#include <stdio.h>
31
-#include <string.h>
32
-#include <stdlib.h>
33
-#include <time.h>
34
-#include <mysql/mysql.h>
35
-#include <mysql/errmsg.h>
36
-#include "../../mem/mem.h"
37
-#include "../../dprint.h"
38
-#include "../../db/db_pool.h"
39
-#include "../../globals.h"
40
-#include "../../pt.h"
41
-#include "utils.h"
42
-#include "val.h"
43
-#include "my_con.h"
44
-#include "res.h"
45
-#include "db_mod.h"
46
-#include "dbase.h"
47
-
48
-
49
-#define SQL_BUF_LEN 65536
50
-
51
-static char sql_buf[SQL_BUF_LEN];
52
-
53
-
54
-/*
55
- * Send an SQL query to the server
56
- */
57
-static int submit_query(db_con_t* _h, const char* _s)
58
-{	
59
-	time_t t;
60
-	int i, code;
61
-
62
-	if ((!_h) || (!_s)) {
63
-		LOG(L_ERR, "submit_query: Invalid parameter value\n");
64
-		return -1;
65
-	}
66
-
67
-	if (ping_interval) {
68
-		t = time(0);
69
-		if ((t - CON_TIMESTAMP(_h)) > ping_interval) {
70
-			if (mysql_ping(CON_CONNECTION(_h))) {
71
-				DBG("submit_query: mysql_ping failed\n");
72
-			}
73
-		}
74
-		CON_TIMESTAMP(_h) = t;
75
-	}
76
-
77
-	/* screws up the terminal when the query contains a BLOB :-( (by bogdan)
78
-	 * DBG("submit_query(): %s\n", _s);
79
-	 */
80
-
81
-	/* When a server connection is lost and a query is attempted, most of
82
-	 * the time the query will return a CR_SERVER_LOST, then at the second
83
-	 * attempt to execute it, the mysql lib will reconnect and succeed.
84
-	 * However is a few cases, the first attempt returns CR_SERVER_GONE_ERROR
85
-	 * the second CR_SERVER_LOST and only the third succeeds.
86
-	 * Thus the 3 in the loop count. Increasing the loop count over this
87
-	 * value shouldn't be needed, but it doesn't hurt either, since the loop
88
-	 * will most of the time stop at the second or sometimes at the third
89
-	 * iteration.
90
-	 */
91
-	for (i=0; i<(auto_reconnect ? 3 : 1); i++) {
92
-		if (mysql_query(CON_CONNECTION(_h), _s)==0) {
93
-			return 0;
94
-		}
95
-		code = mysql_errno(CON_CONNECTION(_h));
96
-		if (code != CR_SERVER_GONE_ERROR && code != CR_SERVER_LOST) {
97
-			break;
98
-		}
99
-	}
100
-	LOG(L_ERR, "submit_query: %s\n", mysql_error(CON_CONNECTION(_h)));
101
-	return -2;
102
-}
103
-
104
-
105
-/*
106
- * Print list of columns separated by comma
107
- */
108
-static int print_columns(char* _b, int _l, db_key_t* _c, int _n)
109
-{
110
-	int i, ret;
111
-	int len = 0;
112
-
113
-	if ((!_c) || (!_n) || (!_b) || (!_l)) {
114
-		LOG(L_ERR, "print_columns: Invalid parameter value\n");
115
-		return -1;
116
-	}
117
-
118
-	for(i = 0; i < _n; i++) {
119
-		if (i == (_n - 1)) {
120
-			ret = snprintf(_b + len, _l - len, "%s ", _c[i]);
121
-			if (ret < 0 || ret >= (_l - len)) goto error;
122
-			len += ret;
123
-		} else {
124
-			ret = snprintf(_b + len, _l - len, "%s,", _c[i]);
125
-			if (ret < 0 || ret >= (_l - len)) goto error;
126
-			len += ret;
127
-		}
128
-	}
129
-	return len;
130
-
131
- error:
132
-	LOG(L_ERR, "print_columns: Error in snprintf\n");
133
-	return -1;
134
-}
135
-
136
-
137
-/*
138
- * Print list of values separated by comma
139
- */
140
-static int print_values(MYSQL* _c, char* _b, int _l, db_val_t* _v, int _n)
141
-{
142
-	int i, res = 0, l;
143
-
144
-	if (!_c || !_b || !_l || !_v || !_n) {
145
-		LOG(L_ERR, "print_values: Invalid parameter value\n");
146
-		return -1;
147
-	}
148
-
149
-	for(i = 0; i < _n; i++) {
150
-		l = _l - res;
151
-		if (val2str(_c, _v + i, _b + res, &l) < 0) {
152
-			LOG(L_ERR, "print_values: Error while converting value to string\n");
153
-			return -1;
154
-		}
155
-		res += l;
156
-		if (i != (_n - 1)) {
157
-			*(_b + res) = ',';
158
-			res++;
159
-		}
160
-	}
161
-	return res;
162
-}
163
-
164
-
165
-/*
166
- * Print where clause of SQL statement
167
- */
168
-static int print_where(MYSQL* _c, char* _b, int _l, db_key_t* _k, db_op_t* _o, db_val_t* _v, int _n)
169
-{
170
-	int i;
171
-	int len = 0, ret;
172
-	int l;
173
-
174
-	if (!_c || !_b || !_l || !_k || !_v || !_n) {
175
-		LOG(L_ERR, "print_where: Invalid parameter value\n");
176
-		return -1;
177
-	}
178
-
179
-	for(i = 0; i < _n; i++) {
180
-		if (_v[i].nul) {
181
-			ret = snprintf(_b + len, _l - len, "%s is ", _k[i]);
182
-			if (ret < 0 || ret >= (_l - len)) goto error;
183
-			len += ret;
184
-		} else if (_o) {
185
-			ret = snprintf(_b + len, _l - len, "%s%s", _k[i], _o[i]);
186
-			if (ret < 0 || ret >= (_l - len)) goto error;
187
-			len += ret;
188
-		} else {
189
-			ret = snprintf(_b + len, _l - len, "%s=", _k[i]);
190
-			if (ret < 0 || ret >= (_l - len)) goto error;
191
-			len += ret;
192
-		}
193
-		l = _l - len;
194
-		val2str(_c, &(_v[i]), _b + len, &l);
195
-		len += l;
196
-		if (i == (_n - 1))
197
-			ret = snprintf(_b + len, _l - len, " ");
198
-		else
199
-			ret = snprintf(_b + len, _l - len, " AND ");
200
-		if (ret < 0 || ret >= (_l - len)) goto error;
201
-		len += ret;
202
-	}
203
-	return len;
204
-
205
- error:
206
-	LOG(L_ERR, "print_where: Error in snprintf\n");
207
-	return -1;
208
-}
209
-
210
-
211
-/*
212
- * Print set clause of update SQL statement
213
- */
214
-static int print_set(MYSQL* _c, char* _b, int _l, db_key_t* _k, db_val_t* _v, int _n)
215
-{
216
-	int i;
217
-	int len = 0, ret;
218
-	int l;
219
-
220
-	if (!_c || !_b || !_l || !_k || !_v || !_n) {
221
-		LOG(L_ERR, "print_set: Invalid parameter value\n");
222
-		return -1;
223
-	}
224
-
225
-	for(i = 0; i < _n; i++) {
226
-		ret = snprintf(_b + len, _l - len, "%s=", _k[i]);
227
-		if (ret < 0 || ret >= (_l - len)) goto error;
228
-		len += ret;
229
-
230
-		l = _l - len;
231
-		val2str(_c, &(_v[i]), _b + len, &l);
232
-		len += l;
233
-		if (i != (_n - 1)) {
234
-			if ((_l - len) >= 1) {
235
-				*(_b + len++) = ',';
236
-			}
237
-		}
238
-	}
239
-	return len;
240
-
241
- error:
242
-	LOG(L_ERR, "print_set: Error in snprintf\n");
243
-	return -1;
244
-}
245
-
246
-
247
-/*
248
- * Initialize database module
249
- * No function should be called before this
250
- */
251
-db_con_t* db_init(const char* _url)
252
-{
253
-	struct db_id* id;
254
-	struct my_con* con;
255
-	db_con_t* res;
256
-
257
-	id = 0;
258
-	res = 0;
259
-
260
-	/* if called from PROC_MAIN, allow it only from mod_init( when pt==0)*/
261
-	if (is_main && fixup_complete){
262
-		LOG(L_ERR, "BUG: mysql: db_init: called from the main process,"
263
-					" ignoring...\n");
264
-	}
265
-
266
-	if (!_url) {
267
-		LOG(L_ERR, "db_init: Invalid parameter value\n");
268
-		return 0;
269
-	}
270
-
271
-	res = pkg_malloc(sizeof(db_con_t) + sizeof(struct my_con*));
272
-	if (!res) {
273
-		LOG(L_ERR, "db_init: No memory left\n");
274
-		return 0;
275
-	}
276
-	memset(res, 0, sizeof(db_con_t) + sizeof(struct my_con*));
277
-
278
-	id = new_db_id(_url);
279
-	if (!id) {
280
-		LOG(L_ERR, "db_init: Cannot parse URL '%s'\n", _url);
281
-		goto err;
282
-	}
283
-
284
-	     /* Find the connection in the pool */
285
-	con = (struct my_con*)pool_get(id);
286
-	if (!con) {
287
-		DBG("db_init: Connection '%s' not found in pool\n", _url);
288
-		     /* Not in the pool yet */
289
-		con = new_connection(id);
290
-		if (!con) {
291
-			goto err;
292
-		}
293
-		pool_insert((struct pool_con*)con);
294
-	} else {
295
-		DBG("db_init: Connection '%s' found in pool\n", _url);
296
-	}
297
-
298
-	res->tail = (unsigned long)con;
299
-	return res;
300
-
301
- err:
302
-	if (id) free_db_id(id);
303
-	if (res) pkg_free(res);
304
-	return 0;
305
-}
306
-
307
-
308
-/*
309
- * Shut down database module
310
- * No function should be called after this
311
- */
312
-void db_close(db_con_t* _h)
313
-{
314
-	struct pool_con* con;
315
-
316
-	if (!_h) {
317
-		LOG(L_ERR, "db_close: Invalid parameter value\n");
318
-		return;
319
-	}
320
-
321
-	con = (struct pool_con*)_h->tail;
322
-	if (pool_remove(con) != 0) {
323
-		free_connection((struct my_con*)con);
324
-	}
325
-
326
-	pkg_free(_h);
327
-}
328
-
329
-
330
-/*
331
- * Retrieve result set
332
- */
333
-static int store_result(db_con_t* _h, db_res_t** _r)
334
-{
335
-	if ((!_h) || (!_r)) {
336
-		LOG(L_ERR, "store_result: Invalid parameter value\n");
337
-		return -1;
338
-	}
339
-
340
-	*_r = new_result();
341
-	if (*_r == 0) {
342
-		LOG(L_ERR, "store_result: No memory left\n");
343
-		return -2;
344
-	}
345
-
346
-	MYRES_RESULT(*_r) = mysql_store_result(CON_CONNECTION(_h));
347
-	if (!MYRES_RESULT(*_r)) {
348
-		if (mysql_field_count(CON_CONNECTION(_h)) == 0) {
349
-			(*_r)->col.n = 0;
350
-			(*_r)->n = 0;
351
-			return 0;
352
-		} else {
353
-			LOG(L_ERR, "store_result: %s\n", mysql_error(CON_CONNECTION(_h)));
354
-			free_result(*_r);
355
-			*_r = 0;
356
-			return -3;
357
-		}
358
-	}
359
-
360
-	if (convert_result(_h, *_r) < 0) {
361
-		LOG(L_ERR, "store_result: Error while converting result\n");
362
-		mysql_free_result(MYRES_RESULT(*_r));
363
-		pkg_free((*_r)->data);
364
-		pkg_free(*_r);
365
-
366
-		/* This cannot be used because if convert_result fails,
367
-		 * free_result will try to free rows and columns too 
368
-		 * and free will be called two times
369
-		 */
370
-		/* free_result(*_r); */
371
-		return -4;
372
-	}
373
-	
374
-	return 0;
375
-}
376
-
377
-
378
-/*
379
- * Release a result set from memory
380
- */
381
-int db_free_result(db_con_t* _h, db_res_t* _r)
382
-{
383
-     if ((!_h) || (!_r)) {
384
-	     LOG(L_ERR, "db_free_result: Invalid parameter value\n");
385
-	     return -1;
386
-     }
387
-
388
-     if (free_result(_r) < 0) {
389
-	     LOG(L_ERR, "db_free_result: Unable to free result structure\n");
390
-	     return -1;
391
-     }
392
-     return 0;
393
-}
394
-
395
-
396
-/*
397
- * Query table for specified rows
398
- * _h: structure representing database connection
399
- * _k: key names
400
- * _op: operators
401
- * _v: values of the keys that must match
402
- * _c: column names to return
403
- * _n: number of key=values pairs to compare
404
- * _nc: number of columns to return
405
- * _o: order by the specified column
406
- */
407
-int db_query(db_con_t* _h, db_key_t* _k, db_op_t* _op,
408
-	     db_val_t* _v, db_key_t* _c, int _n, int _nc,
409
-	     db_key_t _o, db_res_t** _r)
410
-{
411
-	int off, ret;
412
-
413
-	if (!_h) {
414
-		LOG(L_ERR, "db_query: Invalid parameter value\n");
415
-		return -1;
416
-	}
417
-
418
-	if (!_c) {
419
-		ret = snprintf(sql_buf, SQL_BUF_LEN, "select * from %s ", CON_TABLE(_h));
420
-		if (ret < 0 || ret >= SQL_BUF_LEN) goto error;
421
-		off = ret;
422
-	} else {
423
-		ret = snprintf(sql_buf, SQL_BUF_LEN, "select ");
424
-		if (ret < 0 || ret >= SQL_BUF_LEN) goto error;
425
-		off = ret;
426
-
427
-		ret = print_columns(sql_buf + off, SQL_BUF_LEN - off, _c, _nc);
428
-		if (ret < 0) return -1;
429
-		off += ret;
430
-
431
-		ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, "from %s ", CON_TABLE(_h));
432
-		if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error;
433
-		off += ret;
434
-	}
435
-	if (_n) {
436
-		ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, "where ");
437
-		if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error;
438
-		off += ret;
439
-
440
-		ret = print_where(CON_CONNECTION(_h), sql_buf + off, SQL_BUF_LEN - off, _k, _op, _v, _n);
441
-		if (ret < 0) return -1;;
442
-		off += ret;
443
-	}
444
-	if (_o) {
445
-		ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, "order by %s", _o);
446
-		if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error;
447
-		off += ret;
448
-	}
449
-	
450
-	*(sql_buf + off) = '\0';
451
-	if (submit_query(_h, sql_buf) < 0) {
452
-		LOG(L_ERR, "db_query: Error while submitting query\n");
453
-		return -2;
454
-	}
455
-
456
-	return store_result(_h, _r);
457
-
458
- error:
459
-	LOG(L_ERR, "db_query: Error in snprintf\n");
460
-	return -1;
461
-}
462
-
463
-
464
-/*
465
- * Execute a raw SQL query
466
- */
467
-int db_raw_query(db_con_t* _h, char* _s, db_res_t** _r)
468
-{
469
-	if ((!_h) || (!_s)) {
470
-		LOG(L_ERR, "db_raw_query: Invalid parameter value\n");
471
-		return -1;
472
-	}
473
-
474
-	if (submit_query(_h, _s) < 0) {
475
-		LOG(L_ERR, "db_raw_query: Error while submitting query\n");
476
-		return -2;
477
-	}
478
-
479
-	if(_r)
480
-	    return store_result(_h, _r);
481
-	return 0;
482
-}
483
-
484
-
485
-/*
486
- * Insert a row into specified table
487
- * _h: structure representing database connection
488
- * _k: key names
489
- * _v: values of the keys
490
- * _n: number of key=value pairs
491
- */
492
-int db_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n)
493
-{
494
-	int off, ret;
495
-
496
-	if ((!_h) || (!_k) || (!_v) || (!_n)) {
497
-		LOG(L_ERR, "db_insert: Invalid parameter value\n");
498
-		return -1;
499
-	}
500
-
501
-	ret = snprintf(sql_buf, SQL_BUF_LEN, "insert into %s (", CON_TABLE(_h));
502
-	if (ret < 0 || ret >= SQL_BUF_LEN) goto error;
503
-	off = ret;
504
-
505
-	ret = print_columns(sql_buf + off, SQL_BUF_LEN - off, _k, _n);
506
-	if (ret < 0) return -1;
507
-	off += ret;
508
-
509
-	ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, ") values (");
510
-	if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error;
511
-	off += ret;
512
-
513
-	ret = print_values(CON_CONNECTION(_h), sql_buf + off, SQL_BUF_LEN - off, _v, _n);
514
-	if (ret < 0) return -1;
515
-	off += ret;
516
-
517
-	*(sql_buf + off++) = ')';
518
-	*(sql_buf + off) = '\0';
519
-
520
-	if (submit_query(_h, sql_buf) < 0) {
521
-	        LOG(L_ERR, "db_insert: Error while submitting query\n");
522
-		return -2;
523
-	}
524
-	return 0;
525
-
526
- error:
527
-	LOG(L_ERR, "db_insert: Error in snprintf\n");
528
-	return -1;
529
-}
530
-
531
-
532
-/*
533
- * Delete a row from the specified table
534
- * _h: structure representing database connection
535
- * _k: key names
536
- * _o: operators
537
- * _v: values of the keys that must match
538
- * _n: number of key=value pairs
539
- */
540
-int db_delete(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, int _n)
541
-{
542
-	int off, ret;
543
-
544
-	if (!_h) {
545
-		LOG(L_ERR, "db_delete: Invalid parameter value\n");
546
-		return -1;
547
-	}
548
-
549
-	ret = snprintf(sql_buf, SQL_BUF_LEN, "delete from %s", CON_TABLE(_h));
550
-	if (ret < 0 || ret >= SQL_BUF_LEN) goto error;
551
-	off = ret;
552
-
553
-	if (_n) {
554
-		ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, " where ");
555
-		if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error;
556
-		off += ret;
557
-
558
-		ret = print_where(CON_CONNECTION(_h), sql_buf + off, SQL_BUF_LEN - off, _k, _o, _v, _n);
559
-		if (ret < 0) return -1;
560
-		off += ret;
561
-	}
562
-
563
-	*(sql_buf + off) = '\0';
564
-	if (submit_query(_h, sql_buf) < 0) {
565
-		LOG(L_ERR, "db_delete: Error while submitting query\n");
566
-		return -2;
567
-	}
568
-	return 0;
569
-
570
- error:
571
-	LOG(L_ERR, "db_delete: Error in snprintf\n");
572
-	return -1;
573
-}
574
-
575
-
576
-/*
577
- * Update some rows in the specified table
578
- * _h: structure representing database connection
579
- * _k: key names
580
- * _o: operators
581
- * _v: values of the keys that must match
582
- * _uk: updated columns
583
- * _uv: updated values of the columns
584
- * _n: number of key=value pairs
585
- * _un: number of columns to update
586
- */
587
-int db_update(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v,
588
-	      db_key_t* _uk, db_val_t* _uv, int _n, int _un)
589
-{
590
-	int off, ret;
591
-
592
-	if ((!_h) || (!_uk) || (!_uv) || (!_un)) {
593
-		LOG(L_ERR, "db_update: Invalid parameter value\n");
594
-		return -1;
595
-	}
596
-
597
-	ret = snprintf(sql_buf, SQL_BUF_LEN, "update %s set ", CON_TABLE(_h));
598
-	if (ret < 0 || ret >= SQL_BUF_LEN) goto error;
599
-	off = ret;
600
-
601
-	ret = print_set(CON_CONNECTION(_h), sql_buf + off, SQL_BUF_LEN - off, _uk, _uv, _un);
602
-	if (ret < 0) return -1;
603
-	off += ret;
604
-
605
-	if (_n) {
606
-		ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, " where ");
607
-		if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error;
608
-		off += ret;
609
-
610
-		ret = print_where(CON_CONNECTION(_h), sql_buf + off, SQL_BUF_LEN - off, _k, _o, _v, _n);
611
-		if (ret < 0) return -1;
612
-		off += ret;
613
-
614
-		*(sql_buf + off) = '\0';
615
-	}
616
-
617
-	if (submit_query(_h, sql_buf) < 0) {
618
-		LOG(L_ERR, "db_update: Error while submitting query\n");
619
-		return -2;
620
-	}
621
-	return 0;
622
-
623
- error:
624
-	LOG(L_ERR, "db_update: Error in snprintf\n");
625
-	return -1;
626
-}
627
-
628
-
629
-/*
630
- * Just like insert, but replace the row if it exists
631
- */
632
-int db_replace(db_con_t* handle, db_key_t* keys, db_val_t* vals, int n)
633
-{
634
-	int off, ret;
635
-
636
-	if (!handle || !keys || !vals) {
637
-		LOG(L_ERR, "db_replace: Invalid parameter value\n");
638
-		return -1;
639
-	}
640
-
641
-	ret = snprintf(sql_buf, SQL_BUF_LEN, "replace %s (", CON_TABLE(handle));
642
-	if (ret < 0 || ret >= SQL_BUF_LEN) goto error;
643
-	off = ret;
644
-
645
-	ret = print_columns(sql_buf + off, SQL_BUF_LEN - off, keys, n);
646
-	if (ret < 0) return -1;
647
-	off += ret;
648
-
649
-	ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, ") values (");
650
-	if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error;
651
-	off += ret;
652
-
653
-	ret = print_values(CON_CONNECTION(handle), sql_buf + off, SQL_BUF_LEN - off, vals, n);
654
-	if (ret < 0) return -1;
655
-	off += ret;
656
-
657
-	*(sql_buf + off++) = ')';
658
-	*(sql_buf + off) = '\0';
659
-
660
-	if (submit_query(handle, sql_buf) < 0) {
661
-	        LOG(L_ERR, "db_replace: Error while submitting query\n");
662
-		return -2;
663
-	}
664
-	return 0;
665
-
666
- error:
667
-	LOG(L_ERR, "db_replace: Error in snprintf\n");
668
-	return -1;
669
-}
670 0
deleted file mode 100644
... ...
@@ -1,105 +0,0 @@
1
-/*
2
- * $Id$
3
- *
4
- * MySQL module core functions
5
- *
6
- * Copyright (C) 2001-2003 FhG Fokus
7
- *
8
- * This file is part of ser, a free SIP server.
9
- *
10
- * ser is free software; you can redistribute it and/or modify
11
- * it under the terms of the GNU General Public License as published by
12
- * the Free Software Foundation; either version 2 of the License, or
13
- * (at your option) any later version
14
- *
15
- * For a license to use the ser software under conditions
16
- * other than those described here, or to purchase support for this
17
- * software, please contact iptel.org by e-mail at the following addresses:
18
- *    info@iptel.org
19
- *
20
- * ser is distributed in the hope that it will be useful,
21
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
- * GNU General Public License for more details.
24
- *
25
- * You should have received a copy of the GNU General Public License 
26
- * along with this program; if not, write to the Free Software 
27
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
- */
29
-
30
-
31
-#ifndef DBASE_H
32
-#define DBASE_H
33
-
34
-
35
-#include "../../db/db_con.h"
36
-#include "../../db/db_res.h"
37
-#include "../../db/db_key.h"
38
-#include "../../db/db_op.h"
39
-#include "../../db/db_val.h"
40
-
41
-
42
-/*
43
- * Initialize database connection
44
- */
45
-db_con_t* db_init(const char* _sqlurl);
46
-
47
-
48
-/*
49
- * Close a database connection
50
- */
51
-void db_close(db_con_t* _h);
52
-
53
-
54
-/*
55
- * Free all memory allocated by get_result
56
- */
57
-int db_free_result(db_con_t* _h, db_res_t* _r);
58
-
59
-
60
-/*
61
- * Do a query
62
- */
63
-int db_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, db_key_t* _c, int _n, int _nc,
64
-	     db_key_t _o, db_res_t** _r);
65
-
66
-
67
-/*
68
- * Raw SQL query
69
- */
70
-int db_raw_query(db_con_t* _h, char* _s, db_res_t** _r);
71
-
72
-
73
-/*
74
- * Insert a row into table
75
- */
76
-int db_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n);
77
-
78
-
79
-/*
80
- * Delete a row from table
81
- */
82
-int db_delete(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, int _n);
83
-
84
-
85
-/*
86
- * Update a row in table
87
- */
88
-int db_update(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v,
89
-	      db_key_t* _uk, db_val_t* _uv, int _n, int _un);
90
-
91
-
92
-/*
93
- * Just like insert, but replace the row if it exists
94
- */
95
-int db_replace(db_con_t* handle, db_key_t* keys, db_val_t* vals, int n);
96
-
97
-
98
-/*
99
- * Store name of table that will be used by
100
- * subsequent database functions
101
- */
102
-int use_table(db_con_t* _h, const char* _t);
103
-
104
-
105
-#endif /* DBASE_H */
106 0
new file mode 100644
... ...
@@ -0,0 +1,732 @@
1
+/* 
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2001-2003 FhG Fokus
5
+ * Copyright (C) 2006-2007 iptelorg GmbH
6
+ *
7
+ * This file is part of ser, a free SIP server.
8
+ *
9
+ * ser is free software; you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation; either version 2 of the License, or
12
+ * (at your option) any later version
13
+ *
14
+ * For a license to use the ser software under conditions
15
+ * other than those described here, or to purchase support for this
16
+ * software, please contact iptel.org by e-mail at the following addresses:
17
+ *    info@iptel.org
18
+ *
19
+ * ser is distributed in the hope that it will be useful,
20
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
+ * GNU General Public License for more details.
23
+ *
24
+ * You should have received a copy of the GNU General Public License 
25
+ * along with this program; if not, write to the Free Software 
26
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
+ */
28
+
29
+#define _XOPEN_SOURCE 4     /* bsd */
30
+#define _XOPEN_SOURCE_EXTENDED 1    /* solaris */
31
+#define _SVID_SOURCE 1 /* timegm */
32
+
33
+#include <strings.h>
34
+#include <stdio.h>
35
+#include <time.h>  /*strptime, XOPEN issue must be >=4 */
36
+#include <string.h>
37
+#include "../../mem/mem.h"
38
+#include "../../str.h"
39
+#include "../../db/db_cmd.h"
40
+#include "../../ut.h"
41
+#include "my_con.h"
42
+#include "my_fld.h"
43
+#include "my_cmd.h"
44
+
45
+#define STR_BUF_SIZE 256
46
+
47
+enum {
48
+	STR_DELETE,
49
+	STR_INSERT,
50
+	STR_UPDATE,
51
+	STR_SELECT,
52
+	STR_REPLACE,
53
+	STR_WHERE,
54
+	STR_IS,
55
+	STR_AND,
56
+	STR_OR,
57
+	STR_ESC,
58
+	STR_OP_EQ,
59
+	STR_OP_LT,
60
+	STR_OP_GT,
61
+	STR_OP_LEQ,
62
+	STR_OP_GEQ,
63
+	STR_VALUES,
64
+	STR_FROM
65
+};
66
+
67
+static str strings[] = {
68
+	STR_STATIC_INIT("delete from "),
69
+	STR_STATIC_INIT("insert into "),
70
+	STR_STATIC_INIT("update "),
71
+	STR_STATIC_INIT("select "),
72
+	STR_STATIC_INIT("replace "),
73
+	STR_STATIC_INIT(" where "),
74
+	STR_STATIC_INIT(" is "),
75
+	STR_STATIC_INIT(" and "),
76
+	STR_STATIC_INIT(" or "),
77
+	STR_STATIC_INIT("?"),
78
+	STR_STATIC_INIT("="),
79
+	STR_STATIC_INIT("<"),
80
+	STR_STATIC_INIT(">"),
81
+	STR_STATIC_INIT("<="),
82
+	STR_STATIC_INIT(">="),
83
+	STR_STATIC_INIT(") values ("),
84
+	STR_STATIC_INIT(" from ")
85
+};
86
+
87
+
88
+#define APPEND_STR(p, str) do {		 \
89
+	memcpy((p), (str).s, (str).len); \
90
+	(p) += (str).len;				 \
91
+} while(0)
92
+
93
+
94
+#define APPEND_CSTR(p, cstr) do { \
95
+    int _len = strlen(cstr);      \
96
+	memcpy((p), (cstr), _len);	  \
97
+	(p) += _len;				  \
98
+} while(0)
99
+
100
+
101
+
102
+static int my_cmd_free(db_cmd_t* cmd, struct my_cmd* payload)
103
+{
104
+	db_drv_free(&payload->gen);
105
+	if (payload->query.s) pkg_free(payload->query.s);
106
+	if (payload->st) mysql_stmt_close(payload->st);
107
+	pkg_free(payload);
108
+}
109
+
110
+
111
+static int build_delete_query(str* query, db_cmd_t* cmd)
112
+{
113
+	db_fld_t* fld;
114
+	int i;
115
+	char* p;
116
+
117
+	query->len = strings[STR_DELETE].len;
118
+	query->len += cmd->table.len;
119
+
120
+	if (!DB_FLD_EMPTY(cmd->params)) {
121
+		query->len += strings[STR_WHERE].len;
122
+
123
+		for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
124
+			query->len += strlen(fld[i].name);
125
+
126
+			switch(fld[i].op) {
127
+			case DB_EQ:  query->len += strings[STR_OP_EQ].len; break;
128
+			case DB_LT:  query->len += strings[STR_OP_LT].len; break;
129
+			case DB_GT:  query->len += strings[STR_OP_GT].len; break;
130
+			case DB_LEQ: query->len += strings[STR_OP_LEQ].len; break;
131
+			case DB_GEQ: query->len += strings[STR_OP_GEQ].len; break;
132
+			default:
133
+				ERR("Unsupported db_fld operator %d\n", fld[i].op);
134
+				return -1;
135
+			}
136
+
137
+			query->len += strings[STR_ESC].len;
138
+			
139
+			if (!DB_FLD_LAST(fld[i + 1])) query->len += strings[STR_AND].len;
140
+		}
141
+	}
142
+
143
+	query->s = pkg_malloc(query->len + 1);
144
+	if (query->s == NULL) {
145
+		ERR("No memory left\n");
146
+		return -1;
147
+	}
148
+	p = query->s;
149
+	
150
+	APPEND_STR(p, strings[STR_DELETE]);
151
+	APPEND_STR(p, cmd->table);
152
+
153
+	if (!DB_FLD_EMPTY(cmd->params)) {
154
+		APPEND_STR(p, strings[STR_WHERE]);
155
+
156
+		for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
157
+			APPEND_CSTR(p, fld[i].name);
158
+
159
+			switch(fld[i].op) {
160
+			case DB_EQ:  APPEND_STR(p, strings[STR_OP_EQ]);  break;
161
+			case DB_LT:  APPEND_STR(p, strings[STR_OP_LT]);  break;
162
+			case DB_GT:  APPEND_STR(p, strings[STR_OP_GT]);  break;
163
+			case DB_LEQ: APPEND_STR(p, strings[STR_OP_LEQ]); break;
164
+			case DB_GEQ: APPEND_STR(p, strings[STR_OP_GEQ]); break;
165
+			}
166
+			
167
+			APPEND_STR(p, strings[STR_ESC]);
168
+			if (!DB_FLD_LAST(fld[i + 1])) APPEND_STR(p, strings[STR_AND]);
169
+		}
170
+	}
171
+			
172
+	*p = '\0';
173
+	return 0;
174
+}
175
+
176
+
177
+static int build_select_query(str* query, db_cmd_t* cmd)
178
+{
179
+	db_fld_t* fld;
180
+	int i;
181
+	char* p;
182
+
183
+	query->len = strings[STR_SELECT].len;
184
+
185
+	if (DB_FLD_EMPTY(cmd->result)) {
186
+		query->len += 1; /* "*" */
187
+	} else {
188
+		for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
189
+			query->len += strlen(fld[i].name);
190
+			if (!DB_FLD_LAST(fld[i + 1])) query->len += 1; /* , */
191
+		}
192
+	}
193
+	query->len += strings[STR_FROM].len;
194
+	query->len += cmd->table.len;
195
+
196
+	if (!DB_FLD_EMPTY(cmd->params)) {
197
+		query->len += strings[STR_WHERE].len;
198
+
199
+		for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
200
+			query->len += strlen(fld[i].name);
201
+
202
+			switch(fld[i].op) {
203
+			case DB_EQ:  query->len += strings[STR_OP_EQ].len; break;
204
+			case DB_LT:  query->len += strings[STR_OP_LT].len; break;
205
+			case DB_GT:  query->len += strings[STR_OP_GT].len; break;
206
+			case DB_LEQ: query->len += strings[STR_OP_LEQ].len; break;
207
+			case DB_GEQ: query->len += strings[STR_OP_GEQ].len; break;
208
+			default:
209
+				ERR("Unsupported db_fld operator %d\n", fld[i].op);
210
+				return -1;
211
+			}
212
+
213
+			query->len += strings[STR_ESC].len;
214
+			
215
+			if (!DB_FLD_LAST(fld[i + 1])) query->len += strings[STR_AND].len;
216
+		}
217
+	}
218
+
219
+	query->s = pkg_malloc(query->len + 1);
220
+	if (query->s == NULL) {
221
+		ERR("No memory left\n");
222
+		return -1;
223
+	}
224
+	p = query->s;
225
+	
226
+	APPEND_STR(p, strings[STR_SELECT]);
227
+	if (DB_FLD_EMPTY(cmd->result)) {
228
+		*p++ = '*';
229
+	} else {
230
+		for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
231
+			APPEND_CSTR(p, fld[i].name);
232
+			if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
233
+		}
234
+	}
235
+	APPEND_STR(p, strings[STR_FROM]);
236
+	APPEND_STR(p, cmd->table);
237
+
238
+	if (!DB_FLD_EMPTY(cmd->params)) {
239
+		APPEND_STR(p, strings[STR_WHERE]);
240
+
241
+		for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
242
+			APPEND_CSTR(p, fld[i].name);
243
+
244
+			switch(fld[i].op) {
245
+			case DB_EQ:  APPEND_STR(p, strings[STR_OP_EQ]);  break;
246
+			case DB_LT:  APPEND_STR(p, strings[STR_OP_LT]);  break;
247
+			case DB_GT:  APPEND_STR(p, strings[STR_OP_GT]);  break;
248
+			case DB_LEQ: APPEND_STR(p, strings[STR_OP_LEQ]); break;
249
+			case DB_GEQ: APPEND_STR(p, strings[STR_OP_GEQ]); break;
250
+			}
251
+			
252
+			APPEND_STR(p, strings[STR_ESC]);
253
+			if (!DB_FLD_LAST(fld[i + 1])) APPEND_STR(p, strings[STR_AND]);
254
+		}
255
+	}
256
+			
257
+	*p = '\0';
258
+	return 0;
259
+}
260
+
261
+
262
+static int build_replace_query(str* query, db_cmd_t* cmd)
263
+{
264
+	db_fld_t* fld;
265
+	int i;
266
+	char* p;
267
+
268
+	query->len = strings[STR_REPLACE].len;
269
+	query->len += cmd->table.len;
270
+	query->len += 2; /* " (" */
271
+
272
+	for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
273
+		query->len += strlen(fld[i].name);
274
+		query->len += strings[STR_ESC].len;
275
+		if (!DB_FLD_LAST(fld[i + 1])) query->len += 2; /* , twice */
276
+	}
277
+	query->len += strings[STR_VALUES].len;
278
+	query->len += 1; /* ) */
279
+
280
+	query->s = pkg_malloc(query->len + 1);
281
+	if (query->s == NULL) {
282
+		ERR("No memory left\n");
283
+		return -1;
284
+	}
285
+	p = query->s;
286
+	
287
+	APPEND_STR(p, strings[STR_REPLACE]);
288
+	APPEND_STR(p, cmd->table);
289
+	*p++ = ' ';
290
+	*p++ = '(';
291
+
292
+	for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
293
+		APPEND_CSTR(p, fld[i].name);
294
+		if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
295
+	}
296
+	APPEND_STR(p, strings[STR_VALUES]);
297
+
298
+	for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
299
+		APPEND_STR(p, strings[STR_ESC]);
300
+		if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
301
+	}
302
+	*p++ = ')';
303
+	*p = '\0';
304
+	return 0;
305
+}
306
+
307
+
308
+static inline int update_params(MYSQL_STMT* st, db_fld_t* params)
309
+{
310
+	int i;
311
+	struct db_fld* f;  /* Current field */
312
+	struct my_fld* fp; /* Current field payload */
313
+	struct tm* t;
314
+
315
+	/* Iterate through all the query parameters and update
316
+	 * their values if needed
317
+	 */
318
+
319
+	/* FIXME: We are updating internals of the prepared statement here,
320
+	 * this is probably not nice but I could not find another way of
321
+	 * updating the pointer to the buffer without the need to run
322
+	 * mysql_stmt_bind_param again (which would be innefficient
323
+	 */
324
+
325
+	for(i = 0; i < st->param_count; i++) {
326
+		fp = DB_GET_PAYLOAD(params + i);
327
+
328
+		fp->is_null = params[i].flags & DB_NULL;
329
+		if (fp->is_null) continue;
330
+
331
+		switch(params[i].type) {
332
+		case DB_STR:
333
+			st->params[i].buffer = params[i].v.str.s;
334
+			fp->length = params[i].v.str.len;
335
+			break;
336
+
337
+		case DB_BLOB:
338
+			st->params[i].buffer = params[i].v.blob.s;
339
+			fp->length = params[i].v.blob.len;
340
+			break;
341
+
342
+		case DB_CSTR:
343
+			st->params[i].buffer = (char*)params[i].v.cstr;
344
+			fp->length = strlen(params[i].v.cstr);
345
+			break;
346
+
347
+		case DB_DATETIME:
348
+			t = gmtime(&params[i].v.time);
349
+			fp->time.second = t->tm_sec;
350
+			fp->time.minute = t->tm_min;
351
+			fp->time.hour = t->tm_hour;
352
+			fp->time.day = t->tm_mday;
353
+			fp->time.month = t->tm_mon + 1;
354
+			fp->time.year = t->tm_year + 1900;
355
+			break;
356
+		}
357
+	}
358
+
359
+	return 0;
360
+}
361
+
362
+
363
+
364
+static inline int update_result(db_fld_t* result, MYSQL_STMT* st)
365
+{
366
+	int i;
367
+	struct db_fld* r;  /* Current field in the result */
368
+	struct my_fld* rp; /* Payload of the current field in result */
369
+	struct tm t;
370
+
371
+	/* Iterate through all the query parameters and update
372
+	 * their values if needed
373
+	 */
374
+
375
+	for(i = 0; i < st->field_count; i++) {
376
+		rp = DB_GET_PAYLOAD(result + i);
377
+
378
+		if (rp->is_null) {
379
+			result[i].flags |= DB_NULL;
380
+			continue;
381
+		} else {
382
+			result[i].flags &= ~DB_NULL;
383
+		}
384
+
385
+		switch(result[i].type) {
386
+		case DB_STR:
387
+			result[i].v.str.len = rp->length;
388
+			break;
389
+
390
+		case DB_BLOB:
391
+			result[i].v.blob.len = rp->length;
392
+			break;
393
+
394
+		case DB_CSTR:
395
+			result[i].v.cstr[rp->length] = '\0';
396
+			break;
397
+
398
+		case DB_DATETIME:
399
+			memset(&t, '\0', sizeof(struct tm));
400
+			t.tm_sec = rp->time.second;
401
+			t.tm_min = rp->time.minute;
402
+			t.tm_hour = rp->time.hour;
403
+			t.tm_mday = rp->time.day;
404
+			t.tm_mon = rp->time.month - 1;
405
+			t.tm_year = rp->time.year - 1900;;
406
+
407
+			/* Daylight saving information got lost in the database
408
+			 * so let timegm to guess it. This eliminates the bug when
409
+			 * contacts reloaded from the database have different time
410
+			 * of expiration by one hour when daylight saving is used
411
+			 */ 
412
+			t.tm_isdst = -1;
413
+#ifdef HAVE_TIMEGM
414
+			result[i].v.time = timegm(&t);
415
+#else
416
+			result[i].v.time = _timegm(&t);
417
+#endif /* HAVE_TIMEGM */
418
+			break;
419
+		}
420
+	}
421
+
422
+	return 0;
423
+}
424
+
425
+
426
+int my_cmd_write(db_res_t* res, db_cmd_t* cmd)
427
+{
428
+	struct my_cmd* mcmd;
429
+
430
+	mcmd = DB_GET_PAYLOAD(cmd);
431
+	if (mcmd->st->param_count && update_params(mcmd->st, cmd->params) < 0) return -1;
432
+	if (mysql_stmt_execute(mcmd->st)) {
433
+		ERR("Error while executing query: %s\n", mysql_stmt_error(mcmd->st));
434
+		return -1;
435
+	}
436
+	return 0;
437
+}
438
+
439
+
440
+int my_cmd_read(db_res_t* res, db_cmd_t* cmd)
441
+{
442
+	db_res_t* r;
443
+	struct my_cmd* mcmd;
444
+   
445
+	mcmd = DB_GET_PAYLOAD(cmd);
446
+	if (mcmd->st->param_count && update_params(mcmd->st, cmd->params) < 0) return -1;
447
+	if (mysql_stmt_execute(mcmd->st)) {
448
+		ERR("Error while executing query: %s\n", mysql_stmt_error(mcmd->st));
449
+		return -1;
450
+	}
451
+	return 0;
452
+}
453
+
454
+
455
+static int bind_params(MYSQL_STMT* st, db_fld_t* fld)
456
+{
457
+	int i, n;
458
+	struct my_fld* f;
459
+	MYSQL_BIND* params;
460
+
461
+	/* Calculate the number of parameters */
462
+	for(n = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[n]); n++);
463
+
464
+	params = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * n);
465
+	if (params == NULL) {
466
+		ERR("No memory left\n");
467
+		return -1;
468
+	}
469
+	memset(params, '\0', sizeof(MYSQL_BIND) * n);
470
+	
471
+	for(i = 0; i < n; i++) {
472
+		f = DB_GET_PAYLOAD(fld + i);
473
+		params[i].is_null = &f->is_null;
474
+		/* We can do it for all the types here, mysql will ignore it
475
+		 * for fixed-size types such as MYSQL_TYPE_LONG
476
+		 */
477
+		params[i].length = &f->length;
478
+		switch(fld[i].type) {
479
+		case DB_INT:
480
+		case DB_BITMAP:
481
+			params[i].buffer_type = MYSQL_TYPE_LONG;
482
+			params[i].buffer = &fld[i].v.int4;
483
+			break;
484
+
485
+		case DB_FLOAT:
486
+			params[i].buffer_type = MYSQL_TYPE_FLOAT;
487
+			params[i].buffer = &fld[i].v.flt;
488
+			break;
489
+			
490
+		case DB_DOUBLE:
491
+			params[i].buffer_type = MYSQL_TYPE_DOUBLE;
492
+			params[i].buffer = &fld[i].v.dbl;
493
+			break;
494
+
495
+		case DB_DATETIME:
496
+			params[i].buffer_type = MYSQL_TYPE_DATETIME;
497
+			params[i].buffer = &f->time;
498
+			break;
499
+
500
+		case DB_STR:
501
+		case DB_CSTR:
502
+			params[i].buffer_type = MYSQL_TYPE_VAR_STRING;
503
+			params[i].buffer = ""; /* Updated on runtime */
504
+			break;
505
+
506
+		case DB_BLOB:
507
+			params[i].buffer_type = MYSQL_TYPE_BLOB;
508
+			params[i].buffer = ""; /* Updated on runtime */
509
+			break;
510
+
511
+		}
512
+	}
513
+
514
+	if (mysql_stmt_bind_param(st, params)) {
515
+		ERR("Error while binding parameters: %s\n", mysql_stmt_error(st));
516
+		goto error;
517
+	}
518
+
519
+	/* We do not need the array of MYSQL_BIND anymore, mysql_stmt_bind_param
520
+	 * creates a copy in the statement and we will update it there
521
+	 */
522
+	pkg_free(params);
523
+	return 0;
524
+   
525
+ error:
526
+	if (params) pkg_free(params);
527
+	return -1;
528
+}
529
+
530
+
531
+static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
532
+{
533
+	int i, n;
534
+	struct my_fld* f;
535
+	MYSQL_BIND* result;
536
+
537
+	/* Calculate the number of fields in the result */
538
+	for(n = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[n]); n++);
539
+
540
+	result = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * n);
541
+	if (result == NULL) {
542
+		ERR("No memory left\n");
543
+		return -1;
544
+	}
545
+	memset(result, '\0', sizeof(MYSQL_BIND) * n);
546
+	
547
+	for(i = 0; i < n; i++) {
548
+		f = DB_GET_PAYLOAD(fld + i);
549
+		result[i].is_null = &f->is_null;
550
+		/* We can do it for all the types here, mysql will ignore it
551
+		 * for fixed-size types such as MYSQL_TYPE_LONG
552
+		 */
553
+		result[i].length = &f->length;
554
+		switch(fld[i].type) {
555
+		case DB_INT:
556
+		case DB_BITMAP:
557
+			result[i].buffer_type = MYSQL_TYPE_LONG;
558
+			result[i].buffer = &fld[i].v.int4;
559
+			break;
560
+
561
+		case DB_FLOAT:
562
+			result[i].buffer_type = MYSQL_TYPE_FLOAT;
563
+			result[i].buffer = &fld[i].v.flt;
564
+			break;
565
+			
566
+		case DB_DOUBLE:
567
+			result[i].buffer_type = MYSQL_TYPE_DOUBLE;
568
+			result[i].buffer = &fld[i].v.dbl;
569
+			break;
570
+
571
+		case DB_DATETIME:
572
+			result[i].buffer_type = MYSQL_TYPE_DATETIME;
573
+			result[i].buffer = &f->time;
574
+			break;
575
+
576
+		case DB_STR:
577
+			result[i].buffer_type = MYSQL_TYPE_VAR_STRING;
578
+			f->buf.s = pkg_malloc(STR_BUF_SIZE);
579
+			if (f->buf.s == NULL) {
580
+				ERR("No memory left\n");
581
+				return -1;
582
+			}
583
+			result[i].buffer = f->buf.s;
584
+			fld[i].v.str.s = f->buf.s;
585
+			result[i].buffer_length = STR_BUF_SIZE - 1;
586
+			break;
587
+
588
+		case DB_CSTR:
589
+			result[i].buffer_type = MYSQL_TYPE_VAR_STRING;
590
+			f->buf.s = pkg_malloc(STR_BUF_SIZE);
591
+			if (f->buf.s == NULL) {
592
+				ERR("No memory left\n");
593
+				return -1;
594
+			}
595
+			result[i].buffer = f->buf.s;
596
+			fld[i].v.cstr = f->buf.s;
597
+			result[i].buffer_length = STR_BUF_SIZE - 1;
598
+			break;
599
+
600
+		case DB_BLOB:
601
+			result[i].buffer_type = MYSQL_TYPE_BLOB;
602
+			f->buf.s = pkg_malloc(STR_BUF_SIZE);
603
+			if (f->buf.s == NULL) {
604
+				ERR("No memory left\n");
605
+				return -1;
606
+			}
607
+			result[i].buffer = f->buf.s;
608
+			fld[i].v.blob.s = f->buf.s;
609
+			result[i].buffer_length = STR_BUF_SIZE - 1;
610
+			break;
611
+
612
+		}
613
+	}
614
+
615
+	if (mysql_stmt_bind_result(st, result)) {
616
+		ERR("Error while binding result: %s\n", mysql_stmt_error(st));
617
+		goto error;
618
+	}
619
+
620
+	/* We do not need the array of MYSQL_BIND anymore, mysql_stmt_bind_param
621
+	 * creates a copy in the statement and we will update it there
622
+	 */
623
+	pkg_free(result);
624
+	return 0;
625
+   
626
+ error:
627
+	if (result) pkg_free(result);
628
+	return -1;
629
+}
630
+
631
+
632
+int my_cmd(db_cmd_t* cmd)
633
+{
634
+	struct my_cmd* res;
635
+	struct my_con* mcon;
636
+
637
+	res = (struct my_cmd*)pkg_malloc(sizeof(struct my_cmd));
638
+	if (res == NULL) {
639
+		ERR("No memory left\n");
640
+		goto error;
641