Browse code

- reordered included header files for better detection of missing headers - disable automatic database reconnects, they do not work with pre-compiled statements - error/info/log message cleanup - auto_reconnect module parameter removed - introduced new module parameter retries which controls the number of times queries are tried to execute on server on failures

Jan Janak authored on 16/01/2008 14:17:28
Showing 9 changed files
... ...
@@ -34,28 +34,34 @@
34 34
 #define _XOPEN_SOURCE_EXTENDED 1    /* solaris */
35 35
 #define _SVID_SOURCE 1 /* timegm */
36 36
 
37
+#include "my_cmd.h"
38
+
39
+#include "my_con.h"
40
+#include "mysql_mod.h"
41
+#include "my_fld.h"
42
+
43
+#include "../../mem/mem.h"
44
+#include "../../str.h"
45
+#include "../../db/db_cmd.h"
46
+#include "../../ut.h"
47
+
37 48
 #include <strings.h>
38 49
 #include <stdio.h>
39 50
 #include <time.h>  /*strptime, XOPEN issue must be >=4 */
40 51
 #include <string.h>
41 52
 #include <mysql/errmsg.h>
42 53
 #include <mysql/mysqld_error.h>
43
-#include "../../mem/mem.h"
44
-#include "../../str.h"
45
-#include "../../db/db_cmd.h"
46
-#include "../../ut.h"
47
-#include "my_con.h"
48
-#include "my_fld.h"
49
-#include "my_cmd.h"
50 54
 
51 55
 #define STR_BUF_SIZE 256
52 56
 
53 57
 #ifdef MYSQL_FAKE_NULL
58
+
54 59
 #define FAKE_NULL_STRING "[~NULL~]"
55 60
 static str  FAKE_NULL_STR=STR_STATIC_INIT(FAKE_NULL_STRING);
61
+
56 62
 /* avoid warning: this decimal constant is unsigned only in ISO C90 :-) */
57
-#define FAKE_NULL_INT (-2147483647-1)
58
-#define STR_EQ(x,y) ((x.len==y.len) && (strncmp(x.s, y.s, x.len)==0))
63
+#define FAKE_NULL_INT (-2147483647 - 1)
64
+#define STR_EQ(x,y) ((x.len == y.len) && (strncmp(x.s, y.s, x.len) == 0))
59 65
 #endif
60 66
 
61 67
 enum {
... ...
@@ -116,62 +122,62 @@ static str strings[] = {
116 122
 } while(0)
117 123
 
118 124
 
119
-static int upload_query(db_cmd_t* cmd);
125
+static int upload_cmd(db_cmd_t* cmd);
120 126
 
121 127
 
122 128
 static void my_cmd_free(db_cmd_t* cmd, struct my_cmd* payload)
123 129
 {
124 130
 	db_drv_free(&payload->gen);
125
-	if (payload->query.s) pkg_free(payload->query.s);
131
+	if (payload->sql_cmd.s) pkg_free(payload->sql_cmd.s);
126 132
 	if (payload->st) mysql_stmt_close(payload->st);
127 133
 	pkg_free(payload);
128 134
 }
129 135
 
130 136
 
131 137
 /**
132
- *  Builds DELETE statement where cmd->match specify WHERE clause.
133
- * @param query  SQL statement as a result of this function
134
- * @param cmd    input for statement creation
138
+ * Builds DELETE statement where cmd->match specify WHERE clause.
139
+ * @param cmd SQL statement as a result of this function
140
+ * @param cmd input for statement creation
135 141
  */
136
-static int build_delete_query(str* query, db_cmd_t* cmd)
142
+static int build_delete_cmd(str* sql_cmd, db_cmd_t* cmd)
137 143
 {
138 144
 	db_fld_t* fld;
139 145
 	int i;
140 146
 	char* p;
141 147
 
142
-	query->len = strings[STR_DELETE].len;
143
-	query->len += cmd->table.len;
148
+	sql_cmd->len = strings[STR_DELETE].len;
149
+	sql_cmd->len += cmd->table.len;
144 150
 
145 151
 	if (!DB_FLD_EMPTY(cmd->match)) {
146
-		query->len += strings[STR_WHERE].len;
152
+		sql_cmd->len += strings[STR_WHERE].len;
147 153
 
148 154
 		for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
149
-			query->len += strlen(fld[i].name);
155
+			sql_cmd->len += strlen(fld[i].name);
150 156
 
151 157
 			switch(fld[i].op) {
152
-			case DB_EQ:  query->len += strings[STR_OP_EQ].len; break;
153
-			case DB_NE:  query->len += strings[STR_OP_NE].len; break;
154
-			case DB_LT:  query->len += strings[STR_OP_LT].len; break;
155
-			case DB_GT:  query->len += strings[STR_OP_GT].len; break;
156
-			case DB_LEQ: query->len += strings[STR_OP_LEQ].len; break;
157
-			case DB_GEQ: query->len += strings[STR_OP_GEQ].len; break;
158
+			case DB_EQ:  sql_cmd->len += strings[STR_OP_EQ].len; break;
159
+			case DB_NE:  sql_cmd->len += strings[STR_OP_NE].len; break;
160
+			case DB_LT:  sql_cmd->len += strings[STR_OP_LT].len; break;
161
+			case DB_GT:  sql_cmd->len += strings[STR_OP_GT].len; break;
162
+			case DB_LEQ: sql_cmd->len += strings[STR_OP_LEQ].len; break;
163
+			case DB_GEQ: sql_cmd->len += strings[STR_OP_GEQ].len; break;
158 164
 			default:
159
-				ERR("Unsupported db_fld operator %d\n", fld[i].op);
165
+				ERR("mysql: Unsupported db_fld operator %d\n", fld[i].op);
160 166
 				return -1;
161 167
 			}
162 168
 
163
-			query->len += strings[STR_ESC].len;
169
+			sql_cmd->len += strings[STR_ESC].len;
164 170
 			
165
-			if (!DB_FLD_LAST(fld[i + 1])) query->len += strings[STR_AND].len;
171
+			if (!DB_FLD_LAST(fld[i + 1])) sql_cmd->len += strings[STR_AND].len;
166 172
 		}
167 173
 	}
168 174
 
169
-	query->s = pkg_malloc(query->len + 1);
170
-	if (query->s == NULL) {
171
-		ERR("No memory left\n");
175
+	sql_cmd->s = pkg_malloc(sql_cmd->len + 1);
176
+	if (sql_cmd->s == NULL) {
177
+		ERR("mysql: No memory left\n");
172 178
 		return -1;
173 179
 	}
174
-	p = query->s;
180
+	p = sql_cmd->s;
175 181
 	
176 182
 	APPEND_STR(p, strings[STR_DELETE]);
177 183
 	APPEND_STR(p, cmd->table);
... ...
@@ -204,58 +210,58 @@ static int build_delete_query(str* query, db_cmd_t* cmd)
204 210
 /**
205 211
  *  Builds SELECT statement where cmd->values specify column names
206 212
  *  and cmd->match specify WHERE clause.
207
- * @param query  SQL statement as a result of this function
208
- * @param cmd    input for statement creation
213
+ * @param sql_cmd SQL statement as a result of this function
214
+ * @param cmd     input for statement creation
209 215
  */
210
-static int build_select_query(str* query, db_cmd_t* cmd)
216
+static int build_select_cmd(str* sql_cmd, db_cmd_t* cmd)
211 217
 {
212 218
 	db_fld_t* fld;
213 219
 	int i;
214 220
 	char* p;
215 221
 
216
-	query->len = strings[STR_SELECT].len;
222
+	sql_cmd->len = strings[STR_SELECT].len;
217 223
 
218 224
 	if (DB_FLD_EMPTY(cmd->result)) {
219
-		query->len += 1; /* "*" */
225
+		sql_cmd->len += 1; /* "*" */
220 226
 	} else {
221 227
 		for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
222
-			query->len += strlen(fld[i].name);
223
-			if (!DB_FLD_LAST(fld[i + 1])) query->len += 1; /* , */
228
+			sql_cmd->len += strlen(fld[i].name);
229
+			if (!DB_FLD_LAST(fld[i + 1])) sql_cmd->len += 1; /* , */
224 230
 		}
225 231
 	}
226
-	query->len += strings[STR_FROM].len;
227
-	query->len += cmd->table.len;
232
+	sql_cmd->len += strings[STR_FROM].len;
233
+	sql_cmd->len += cmd->table.len;
228 234
 
229 235
 	if (!DB_FLD_EMPTY(cmd->match)) {
230
-		query->len += strings[STR_WHERE].len;
236
+		sql_cmd->len += strings[STR_WHERE].len;
231 237
 
232 238
 		for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
233
-			query->len += strlen(fld[i].name);
239
+			sql_cmd->len += strlen(fld[i].name);
234 240
 
235 241
 			switch(fld[i].op) {
236
-			case DB_EQ:  query->len += strings[STR_OP_EQ].len; break;
237
-			case DB_NE:  query->len += strings[STR_OP_NE].len; break;
238
-			case DB_LT:  query->len += strings[STR_OP_LT].len; break;
239
-			case DB_GT:  query->len += strings[STR_OP_GT].len; break;
240
-			case DB_LEQ: query->len += strings[STR_OP_LEQ].len; break;
241
-			case DB_GEQ: query->len += strings[STR_OP_GEQ].len; break;
242
+			case DB_EQ:  sql_cmd->len += strings[STR_OP_EQ].len; break;
243
+			case DB_NE:  sql_cmd->len += strings[STR_OP_NE].len; break;
244
+			case DB_LT:  sql_cmd->len += strings[STR_OP_LT].len; break;
245
+			case DB_GT:  sql_cmd->len += strings[STR_OP_GT].len; break;
246
+			case DB_LEQ: sql_cmd->len += strings[STR_OP_LEQ].len; break;
247
+			case DB_GEQ: sql_cmd->len += strings[STR_OP_GEQ].len; break;
242 248
 			default:
243
-				ERR("Unsupported db_fld operator %d\n", fld[i].op);
249
+				ERR("mysql: Unsupported db_fld operator %d\n", fld[i].op);
244 250
 				return -1;
245 251
 			}
246 252
 
247
-			query->len += strings[STR_ESC].len;
253
+			sql_cmd->len += strings[STR_ESC].len;
248 254
 			
249
-			if (!DB_FLD_LAST(fld[i + 1])) query->len += strings[STR_AND].len;
255
+			if (!DB_FLD_LAST(fld[i + 1])) sql_cmd->len += strings[STR_AND].len;
250 256
 		}
251 257
 	}
252 258
 
253
-	query->s = pkg_malloc(query->len + 1);
254
-	if (query->s == NULL) {
255
-		ERR("No memory left\n");
259
+	sql_cmd->s = pkg_malloc(sql_cmd->len + 1);
260
+	if (sql_cmd->s == NULL) {
261
+		ERR("mysql: No memory left\n");
256 262
 		return -1;
257 263
 	}
258
-	p = query->s;
264
+	p = sql_cmd->s;
259 265
 	
260 266
 	APPEND_STR(p, strings[STR_SELECT]);
261 267
 	if (DB_FLD_EMPTY(cmd->result)) {
... ...
@@ -288,7 +294,7 @@ static int build_select_query(str* query, db_cmd_t* cmd)
288 294
 			if (!DB_FLD_LAST(fld[i + 1])) APPEND_STR(p, strings[STR_AND]);
289 295
 		}
290 296
 	}
291
-			
297
+
292 298
 	*p = '\0';
293 299
 	return 0;
294 300
 }
... ...
@@ -296,33 +302,33 @@ static int build_select_query(str* query, db_cmd_t* cmd)
296 302
 
297 303
 /**
298 304
  *  Builds REPLACE statement where cmd->values specify column names.
299
- * @param query  SQL statement as a result of this function
300
- * @param cmd    input for statement creation
305
+ * @param sql_cmd SQL statement as a result of this function
306
+ * @param cmd     input for statement creation
301 307
  */
302
-static int build_replace_query(str* query, db_cmd_t* cmd)
308
+static int build_replace_cmd(str* sql_cmd, db_cmd_t* cmd)
303 309
 {
304 310
 	db_fld_t* fld;
305 311
 	int i;
306 312
 	char* p;
307 313
 
308
-	query->len = strings[STR_REPLACE].len;
309
-	query->len += cmd->table.len;
310
-	query->len += 2; /* " (" */
314
+	sql_cmd->len = strings[STR_REPLACE].len;
315
+	sql_cmd->len += cmd->table.len;
316
+	sql_cmd->len += 2; /* " (" */
311 317
 
312 318
 	for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {
313
-		query->len += strlen(fld[i].name);
314
-		query->len += strings[STR_ESC].len;
315
-		if (!DB_FLD_LAST(fld[i + 1])) query->len += 2; /* , twice */
319
+		sql_cmd->len += strlen(fld[i].name);
320
+		sql_cmd->len += strings[STR_ESC].len;
321
+		if (!DB_FLD_LAST(fld[i + 1])) sql_cmd->len += 2; /* , twice */
316 322
 	}
317
-	query->len += strings[STR_VALUES].len;
318
-	query->len += 1; /* ) */
323
+	sql_cmd->len += strings[STR_VALUES].len;
324
+    sql_cmd->len += 1; /* ) */
319 325
 
320
-	query->s = pkg_malloc(query->len + 1);
321
-	if (query->s == NULL) {
322
-		ERR("No memory left\n");
326
+	sql_cmd->s = pkg_malloc(sql_cmd->len + 1);
327
+	if (sql_cmd->s == NULL) {
328
+		ERR("mysql: No memory left\n");
323 329
 		return -1;
324 330
 	}
325
-	p = query->s;
331
+	p = sql_cmd->s;
326 332
 	
327 333
 	APPEND_STR(p, strings[STR_REPLACE]);
328 334
 	APPEND_STR(p, cmd->table);
... ...
@@ -344,6 +350,7 @@ static int build_replace_query(str* query, db_cmd_t* cmd)
344 350
 	return 0;
345 351
 }
346 352
 
353
+
347 354
 /**
348 355
  *  Reallocatable string buffer.
349 356
  */
... ...
@@ -353,6 +360,8 @@ struct string_buffer {
353 360
 	int   size;			/**< total size of allocated memory */
354 361
 	int   increment;	/**< increment when realloc is necessary */ 
355 362
 };
363
+
364
+
356 365
 /**
357 366
  *  Add new string into string buffer.
358 367
  * @param sb    string buffer
... ...
@@ -371,7 +380,7 @@ static inline int sb_add(struct string_buffer *sb, str *nstr)
371 380
 		new_size = sb->size + (asize / sb->increment  + (asize % sb->increment > 0)) * sb->increment;
372 381
 		newp = pkg_malloc(new_size);
373 382
 		if (!newp) {
374
-			ERR("not enough memory\n");
383
+			ERR("mysql: No memory left\n");
375 384
 			return -1;
376 385
 		}
377 386
 		if (sb->s) {
... ...
@@ -385,6 +394,8 @@ static inline int sb_add(struct string_buffer *sb, str *nstr)
385 394
 	sb->len += nstr->len;
386 395
 	return 0;
387 396
 }
397
+
398
+
388 399
 /**
389 400
  *  Set members of str variable.
390 401
  *  Used for temporary str variables. 
... ...
@@ -400,10 +411,10 @@ static inline str* set_str(str *str, const char *s)
400 411
 /**
401 412
  *  Builds UPDATE statement where cmd->valss specify column name-value pairs
402 413
  *  and cmd->match specify WHERE clause.
403
- * @param query  SQL statement as a result of this function
404
- * @param cmd    input for statement creation
414
+ * @param sql_cmd  SQL statement as a result of this function
415
+ * @param cmd      input for statement creation
405 416
  */
406
-static int build_update_query(str* query, db_cmd_t* cmd)
417
+static int build_update_cmd(str* sql_cmd, db_cmd_t* cmd)
407 418
 {
408 419
 	struct string_buffer sql_buf = {.s = NULL, .len = 0, .size = 0, .increment = 128};
409 420
 	db_fld_t* fld;
... ...
@@ -449,8 +460,8 @@ static int build_update_query(str* query, db_cmd_t* cmd)
449 460
 	if (rv) {
450 461
 		goto err;
451 462
 	}
452
-	query->s = sql_buf.s;
453
-	query->len = sql_buf.len;
463
+	sql_cmd->s = sql_buf.s;
464
+	sql_cmd->len = sql_buf.len;
454 465
 	return 0;
455 466
 
456 467
 err:
... ...
@@ -530,54 +541,35 @@ static inline void update_field(MYSQL_BIND *param, db_fld_t* fld)
530 541
 	}
531 542
 }
532 543
 
544
+
533 545
 /**
534
- *  Update params with given values.
535
- *  Up to two sets of parameters are provided.
536
- *  Both of them are used in UPDATE query, params1 as colspecs and values and
537
- *  params2 as WHERE clause.
538
- * @param st MySQL query statement
539
- * @param params1 first set of params
540
- * @param params2 second set of params
541
- * @see bind_params
546
+ * Update values of MySQL bound parameters with values from
547
+ * the DB API.
548
+ * @param cmd Command structure which contains pointers to MYSQL_STMT and parameters values
549
+ * @see bind_mysql_params
542 550
  */
543
-static inline int update_params(MYSQL_STMT* st, db_fld_t* params1, db_fld_t* params2)
551
+static inline void set_mysql_params(db_cmd_t* cmd)
544 552
 {
545
-	int  my_idx, fld_idx;
546
-	int  count1, count2;
547
-	
548
-	/* Calculate the number of parameters */
549
-	for(count1 = 0; !DB_FLD_EMPTY(params1) && !DB_FLD_LAST(params1[count1]); count1++);
550
-	for(count2 = 0; !DB_FLD_EMPTY(params2) && !DB_FLD_LAST(params2[count2]); count2++);
551
-	
552
-	if (st->param_count != count1 + count2) {
553
-		ERR("MySQL param count do not match with given parameter arrays\n");
554
-		return -1;
555
-	}
553
+	struct my_cmd* mcmd;
554
+	int i;
556 555
 
557
-	/* Iterate through all the query parameters and update
558
-	 * their values if needed
559
-	 */
556
+	mcmd = DB_GET_PAYLOAD(cmd);
560 557
 
561 558
 	/* FIXME: We are updating internals of the prepared statement here,
562 559
 	 * this is probably not nice but I could not find another way of
563 560
 	 * updating the pointer to the buffer without the need to run
564 561
 	 * mysql_stmt_bind_param again (which would be innefficient)
565 562
 	 */
566
-	/* params1 */
567
-	my_idx = 0;
568
-	for (fld_idx = 0; fld_idx < count1; fld_idx++, my_idx++) {
569
-		update_field(&st->params[my_idx], params1 + fld_idx);
570
-	}
571
-	/* params2 */
572
-	for (fld_idx = 0; fld_idx < count2; fld_idx++, my_idx++) {
573
-		update_field(&st->params[my_idx], params2 + fld_idx);
563
+	for(i = 0; i < cmd->vals_count; i++) {
564
+		update_field(mcmd->st->params + i, cmd->vals + i);
574 565
 	}
575 566
 
576
-	return 0;
567
+	for(i = 0; i < cmd->match_count; i++) {
568
+		update_field(mcmd->st->params + cmd->vals_count + i, cmd->match + i);
569
+	}
577 570
 }
578 571
 
579 572
 
580
-
581 573
 static inline int update_result(db_fld_t* result, MYSQL_STMT* st)
582 574
 {
583 575
 	int i;
... ...
@@ -662,162 +654,91 @@ static inline int update_result(db_fld_t* result, MYSQL_STMT* st)
662 654
 	return 0;
663 655
 }
664 656
 
657
+
665 658
 /**
666
- *  DB_DEL uses cmd-&gt;match
667
- *  DB_PUT uses cmd-&gt;vals
659
+ * This is the main command execution function. The function contains
660
+ * all the necessary logic to detect reset or disconnected database
661
+ * connections and uploads commands to the server if necessary.
662
+ * @param cmd Command to be executed
663
+ * @return    0 if OK, <0 on MySQL failure, >0 on DB API failure
668 664
  */
669
-int my_cmd_write(db_res_t* res, db_cmd_t* cmd)
665
+static int exec_cmd_safe(db_cmd_t* cmd)
670 666
 {
667
+	int i, err;
668
+	db_con_t* con;
671 669
 	struct my_cmd* mcmd;
672
-	int ret, myerr;
673
-	
674
-	mcmd = DB_GET_PAYLOAD(cmd);
675
-	if (cmd->type == DB_DEL && mcmd->st->param_count && update_params(mcmd->st, cmd->match, NULL) < 0) return -1;
676
-	if (cmd->type == DB_PUT && mcmd->st->param_count && update_params(mcmd->st, cmd->vals, NULL) < 0) return -1;
677
-	ret = mysql_stmt_execute(mcmd->st);
670
+	struct my_con* mcon;
678 671
 
679
-	/* If the connection to the server was lost then try to resubmit the query,
680
-	 * it will fail if the connection is not yet working, and try to execute
681
-	 * it again if the upload was successful
672
+	/* First things first: retrieve connection info
673
+	 * from the currently active connection and also
674
+	 * mysql payload from the database command
682 675
 	 */
683
-	if (ret) {
684
-		myerr = mysql_stmt_errno(mcmd->st);
685
-		if (myerr == ER_UNKNOWN_STMT_HANDLER || myerr == CR_SERVER_LOST) {
686
-			if (upload_query(cmd) < 0) {
687
-				LOG(L_CRIT, "Failed to re-initialize DB connection, DB server is not working\n");
688
-				return -1;
676
+	mcmd = DB_GET_PAYLOAD(cmd);
677
+	con = cmd->ctx->con[db_payload_idx];
678
+	mcon = DB_GET_PAYLOAD(con);
679
+
680
+	for(i = 0; i <= my_retries; i++) {
681
+		/* Next check the number of resets in the database connection,
682
+		 * if this number is higher than the number we keep in my_cmd
683
+		 * structure in last_reset variable then the connection was
684
+		 * reset and we need to upload the command again to the server
685
+		 * before executing it, because the server recycles all server
686
+		 * side information upon disconnect.
687
+		 */
688
+		if (mcon->resets > mcmd->last_reset) {
689
+			INFO("mysql: Connection reset detected, uploading command to server\n");
690
+			err = upload_cmd(cmd);
691
+			if (err < 0) {
692
+				INFO("mysql: Error while uploading command\n");
693
+				/* MySQL error, skip execution and try again if we have attempts left */
694
+				continue;
695
+			} else if (err > 0) {
696
+				/* DB API error, this is a serious problem such
697
+				 * as memory allocation failure, bail out
698
+				 */
699
+				return 1;
689 700
 			}
690
-
691
-			if (cmd->type == DB_DEL && mcmd->st->param_count && update_params(mcmd->st, cmd->match, NULL) < 0) return -1;
692
-			if (cmd->type == DB_PUT && mcmd->st->param_count && update_params(mcmd->st, cmd->vals, NULL) < 0) return -1;
693
-			ret = mysql_stmt_execute(mcmd->st);
694 701
 		}
695
-	}
696 702
 
697
-	if (ret) {
698
-		ERR("Error while executing query: %d, %s\n", mysql_stmt_errno(mcmd->st), mysql_stmt_error(mcmd->st));
699
-		return -1;
700
-	}
701
-
702
-	mcmd->next_flag = -1;
703
-	return 0;
704
-}
705
-
706
-
707
-int my_cmd_read(db_res_t* res, db_cmd_t* cmd)
708
-{
709
-	int ret, myerr;
710
-	struct my_cmd* mcmd;
711
-   
712
-	mcmd = DB_GET_PAYLOAD(cmd);
713
-
714
-	if (mcmd->st->param_count && update_params(mcmd->st, cmd->match, NULL) < 0) return -1;
715
-	ret = mysql_stmt_execute(mcmd->st);
716
-
717
-
718
-	/* If the connection to the server was lost then try to resubmit the query,
719
-	 * it will fail if the connection is not yet working, and try to execute
720
-	 * it again if the upload was successful
721
-	 */
722
-	if (ret) {
723
-		myerr = mysql_stmt_errno(mcmd->st);
724
-		if (myerr == ER_UNKNOWN_STMT_HANDLER || myerr == CR_SERVER_LOST) {
725
-			if (upload_query(cmd) < 0) {
726
-				LOG(L_CRIT, "Failed to re-initialize DB connection, DB server is not working\n");
727
-				return -1;
703
+		set_mysql_params(cmd);
704
+		err = mysql_stmt_execute(mcmd->st);
705
+		if (err == 0) return 0;
706
+		else {
707
+			/* Command execution failed, log a message and try to reconnect */
708
+			INFO("mysql: libmysql: %d, %s\n", mysql_stmt_errno(mcmd->st),
709
+				 mysql_stmt_error(mcmd->st));
710
+			INFO("mysql: Error while executing command on server, trying to reconnect\n");
711
+			my_con_disconnect(con);
712
+			if (my_con_connect(con)) {
713
+				INFO("mysql: Failed to reconnect server\n");
714
+			} else {
715
+				INFO("mysql: Successfully reconnected server\n");
728 716
 			}
729
-
730
-			if (mcmd->st->param_count && update_params(mcmd->st, cmd->match, NULL) < 0) return -1;
731
-			ret = mysql_stmt_execute(mcmd->st);
732 717
 		}
733 718
 	}
734 719
 
735
-	if (ret) {
736
-		ERR("Error while executing query: %d, %s\n", mysql_stmt_errno(mcmd->st), mysql_stmt_error(mcmd->st));
737
-		return -1;
738
-	}
739
-
740
-	mcmd->next_flag = -1;
741
-	return 0;
720
+	INFO("mysql: Failed to execute command, giving up\n");
721
+	return -1;
742 722
 }
743 723
 
744 724
 
745
-int my_cmd_update(db_res_t* res, db_cmd_t* cmd)
725
+int my_cmd_exec(db_res_t* res, db_cmd_t* cmd)
746 726
 {
747 727
 	struct my_cmd* mcmd;
748
-	int ret, myerr;
749 728
 
750 729
 	mcmd = DB_GET_PAYLOAD(cmd);
751
-	if (mcmd->st->param_count && update_params(mcmd->st, cmd->vals, cmd->match) < 0) return -1;
752
-	ret = mysql_stmt_execute(mcmd->st);
753
-
754
-	/* If the connection to the server was lost then try to resubmit the query,
755
-	 * it will fail if the connection is not yet working, and try to execute
756
-	 * it again if the upload was successful
757
-	 */
758
-	if (ret) {
759
-		myerr = mysql_stmt_errno(mcmd->st);
760
-		if (myerr == ER_UNKNOWN_STMT_HANDLER || myerr == CR_SERVER_LOST) {
761
-			if (upload_query(cmd) < 0) {
762
-				LOG(L_CRIT, "Failed to re-initialize DB connection, DB server is not working\n");
763
-				return -1;
764
-			}
765
-
766
-			if (mcmd->st->param_count && update_params(mcmd->st, cmd->vals, cmd->match) < 0) return -1;
767
-			ret = mysql_stmt_execute(mcmd->st);
768
-		}
769
-	}
770
-
771
-	if (ret) {
772
-		ERR("Error while executing query: %d, %s\n", mysql_stmt_errno(mcmd->st), mysql_stmt_error(mcmd->st));
773
-		return -1;
774
-	}
775 730
 
776 731
 	mcmd->next_flag = -1;
777
-	return 0;
732
+	return exec_cmd_safe(cmd);
778 733
 }
779 734
 
780 735
 
781
-int my_cmd_sql(db_res_t* res, db_cmd_t* cmd)
782
-{
783
-	struct my_cmd* mcmd;
784
-	int ret, myerr;
785
-   
786
-	mcmd = DB_GET_PAYLOAD(cmd);
787
-	if (mcmd->st->param_count && update_params(mcmd->st, NULL, cmd->match) < 0) return -1;
788
-	ret = mysql_stmt_execute(mcmd->st);
789
-
790
-	/* If the connection to the server was lost then try to resubmit the query,
791
-	 * it will fail if the connection is not yet working, and try to execute
792
-	 * it again if the upload was successful
793
-	 */
794
-	if (ret) {
795
-		myerr = mysql_stmt_errno(mcmd->st);
796
-		if (myerr == ER_UNKNOWN_STMT_HANDLER || myerr == CR_SERVER_LOST) {
797
-			if (upload_query(cmd) < 0) {
798
-				LOG(L_CRIT, "Failed to re-initialize DB connection, DB server is not working\n");
799
-				return -1;
800
-			}
801
-
802
-			ret = mysql_stmt_execute(mcmd->st);
803
-		}
804
-	}
805
-
806
-	if (ret) {
807
-		ERR("Error while executing query: %d, %s\n", mysql_stmt_errno(mcmd->st), mysql_stmt_error(mcmd->st));
808
-		return -1;
809
-	}
810
-
811
-	mcmd->next_flag = -1;
812
-	return 0;
813
-}
814
-
815 736
 /**
816 737
  * Set MYSQL_BIND item.
817 738
  * @param bind destination
818 739
  * @param fld  source
819 740
  */
820
-static void set_field(MYSQL_BIND *bind, db_fld_t* fld )
741
+static void set_field(MYSQL_BIND *bind, db_fld_t* fld)
821 742
 {
822 743
 	struct my_fld* f;
823 744
 	
... ...
@@ -867,38 +788,40 @@ static void set_field(MYSQL_BIND *bind, db_fld_t* fld )
867 788
 	}
868 789
 }
869 790
 
791
+
870 792
 /**
871
- *  Bind params, give real values into prepared statement.
872
- *  Up to two sets of parameters are provided.
873
- *  Both of them are used in UPDATE query, params1 as colspecs and values and
874
- *  params2 as WHERE clause. In other cases one set could be enough because values
875
- *  or match (WHERE clause) is needed.
876
- * @param st MySQL query statement
793
+ * Bind params, give real values into prepared statement.
794
+ * Up to two sets of parameters are provided.
795
+ * Both of them are used in UPDATE command, params1 as colspecs and values and
796
+ * params2 as WHERE clause. In other cases one set could be enough because values
797
+ * or match (WHERE clause) is needed.
798
+ * @param st MySQL command statement
877 799
  * @param params1 first set of params
878 800
  * @param params2 second set of params
801
+ * @return 0 if OK, <0 on MySQL error, >0 on DB API error
879 802
  * @see update_params
880 803
  */
881
-static int bind_params(MYSQL_STMT* st, db_fld_t* params1, db_fld_t* params2)
804
+static int bind_mysql_params(MYSQL_STMT* st, db_fld_t* params1, db_fld_t* params2)
882 805
 {
883 806
 	int my_idx, fld_idx;
884 807
 	int count1, count2;
885 808
 	MYSQL_BIND* my_params;
809
+	int err = 0;
886 810
 
887 811
 	/* Calculate the number of parameters */
888 812
 	for(count1 = 0; !DB_FLD_EMPTY(params1) && !DB_FLD_LAST(params1[count1]); count1++);
889 813
 	for(count2 = 0; !DB_FLD_EMPTY(params2) && !DB_FLD_LAST(params2[count2]); count2++);
890
-	if (st->param_count != count1+ count2) {
891
-		ERR("MySQL param count do not match the given parameter arrays\n");
892
-		return -1;
814
+	if (st->param_count != count1 + count2) {
815
+		BUG("mysql: Number of parameters in SQL command does not match number of DB API parameters\n");
816
+		return 1;
893 817
 	}
894 818
 	
895
-
896
-	my_params = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * (count1+count2));
819
+	my_params = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * (count1 + count2));
897 820
 	if (my_params == NULL) {
898
-		ERR("No memory left\n");
821
+		ERR("mysql: No memory left\n");
899 822
 		return -1;
900 823
 	}
901
-	memset(my_params, '\0', sizeof(MYSQL_BIND) * (count1+count2));
824
+	memset(my_params, '\0', sizeof(MYSQL_BIND) * (count1 + count2));
902 825
 
903 826
 	/* params1 */
904 827
 	my_idx = 0;
... ...
@@ -909,8 +832,11 @@ static int bind_params(MYSQL_STMT* st, db_fld_t* params1, db_fld_t* params2)
909 832
 	for (fld_idx = 0; fld_idx < count2; fld_idx++, my_idx++) {
910 833
 		set_field(&my_params[my_idx], params2 + fld_idx);
911 834
 	}
912
-	if (mysql_stmt_bind_param(st, my_params)) {
913
-		ERR("Error while binding parameters: %s\n", mysql_stmt_error(st));
835
+
836
+	err = mysql_stmt_bind_param(st, my_params);
837
+	if (err) {
838
+		ERR("mysql: libmysqlclient: %d, %s\n", 
839
+			mysql_stmt_errno(st), mysql_stmt_error(st));
914 840
 		goto error;
915 841
 	}
916 842
 
... ...
@@ -918,11 +844,11 @@ static int bind_params(MYSQL_STMT* st, db_fld_t* params1, db_fld_t* params2)
918 844
 	 * creates a copy in the statement and we will update it there
919 845
 	 */
920 846
 	pkg_free(my_params);
921
-	return 0;
847
+	return err;
922 848
    
923 849
  error:
924 850
 	if (my_params) pkg_free(my_params);
925
-	return -1;
851
+	return err;
926 852
 }
927 853
 
928 854
 
... ...
@@ -935,21 +861,21 @@ static int check_result_columns(db_cmd_t* cmd, struct my_cmd* payload)
935 861
 {
936 862
 	int i, n;
937 863
 	MYSQL_FIELD *fld;
938
-	MYSQL_RES *meta = 0;
864
+	MYSQL_RES *meta = NULL;
939 865
 
940 866
 	meta = mysql_stmt_result_metadata(payload->st);
941 867
 	if (meta == NULL) {
942
-		ERR("Error while getting metadata of SQL query: %s\n",
943
-			mysql_stmt_error(payload->st));
944
-		goto error;
868
+		ERR("mysql: Error while getting metadata of SQL command: %d, %s\n",
869
+			mysql_stmt_errno(payload->st), mysql_stmt_error(payload->st));
870
+		return -1;
945 871
 	}
946 872
 	n = mysql_num_fields(meta);
947 873
 	if (cmd->result == NULL) {
948 874
 		/* The result set parameter of db_cmd function was empty, that
949
-		 * means the query is select * and we have to create the array
875
+		 * means the command is select * and we have to create the array
950 876
 		 * of result fields in the cmd structure manually.
951 877
 		 */
952
-                cmd->result = db_fld(n + 1);
878
+		cmd->result = db_fld(n + 1);
953 879
 		cmd->result_count = n;
954 880
 		for(i = 0; i < cmd->result_count; i++) {
955 881
 			struct my_fld *f;
... ...
@@ -957,21 +883,24 @@ static int check_result_columns(db_cmd_t* cmd, struct my_cmd* payload)
957 883
 			f = DB_GET_PAYLOAD(cmd->result + i);
958 884
 			fld = mysql_fetch_field_direct(meta, i);
959 885
 			f->name = pkg_malloc(strlen(fld->name)+1);
960
-			if (!f->name) goto error;
886
+			if (f->name == NULL) {
887
+				ERR("mysql: Out of private memory\n");
888
+				goto error;
889
+			}
961 890
 			strcpy(f->name, fld->name);
962 891
 			cmd->result[i].name = f->name;
963 892
 		}
964
-	}
965
-	else {
893
+	} else {
966 894
 		if (cmd->result_count != n) {
967
-			BUG("number of fields do not correspond\n");
895
+			BUG("mysql: Number of fields in MySQL result does not match number of parameters in DB API\n");
968 896
 			goto error;
969 897
 		}
970 898
 	}
899
+
971 900
 	/* Now iterate through all the columns in the result set and replace
972 901
 	 * any occurrence of DB_UNKNOWN type with the type of the column
973 902
 	 * retrieved from the database and if no column name was provided then
974
-         * update it from the database as well. 
903
+	 * update it from the database as well. 
975 904
 	 */
976 905
 	for(i = 0; i < cmd->result_count; i++) {
977 906
 		fld = mysql_fetch_field_direct(meta, i);
... ...
@@ -1003,26 +932,27 @@ static int check_result_columns(db_cmd_t* cmd, struct my_cmd* payload)
1003 932
 			break;
1004 933
 
1005 934
 		default:
1006
-			ERR("Unsupported MySQL column type: %d, table: %s, column: %s\n",
935
+			ERR("mysql: Unsupported MySQL column type: %d, table: %s, column: %s\n",
1007 936
 				fld->type, cmd->table.s, fld->name);
1008 937
 			goto error;
1009 938
 		}
1010 939
 	}
1011
-	mysql_free_result(meta);
940
+	
941
+	if (meta) mysql_free_result(meta);
1012 942
 	return 0;
943
+
1013 944
 error:
1014 945
 	if (meta) mysql_free_result(meta);
1015
-	return -1;
946
+	return 1;
1016 947
 }
1017 948
 
1018 949
 
1019
-
1020 950
 /* FIXME: Add support for DB_NONE, in this case the function should determine
1021 951
  * the type of the column in the database and set the field type appropriately
1022 952
  */
1023 953
 static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
1024 954
 {
1025
-	int i, n;
955
+	int i, n, err = 0;
1026 956
 	struct my_fld* f;
1027 957
 	MYSQL_BIND* result;
1028 958
 
... ...
@@ -1030,8 +960,8 @@ static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
1030 960
 	for(n = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[n]); n++);
1031 961
 	result = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * n);
1032 962
 	if (result == NULL) {
1033
-		ERR("No memory left\n");
1034
-		return -1;
963
+		ERR("mysql: No memory left\n");
964
+		return 1;
1035 965
 	}
1036 966
 	memset(result, '\0', sizeof(MYSQL_BIND) * n);
1037 967
 	
... ...
@@ -1068,7 +998,8 @@ static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
1068 998
 			result[i].buffer_type = MYSQL_TYPE_VAR_STRING;
1069 999
 			if (!f->buf.s) f->buf.s = pkg_malloc(STR_BUF_SIZE);
1070 1000
 			if (f->buf.s == NULL) {
1071
-				ERR("No memory left\n");
1001
+				ERR("mysql: No memory left\n");
1002
+				err = 1;
1072 1003
 				goto error;
1073 1004
 			}
1074 1005
 			result[i].buffer = f->buf.s;
... ...
@@ -1080,7 +1011,8 @@ static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
1080 1011
 			result[i].buffer_type = MYSQL_TYPE_VAR_STRING;
1081 1012
 			if (!f->buf.s) f->buf.s = pkg_malloc(STR_BUF_SIZE);
1082 1013
 			if (f->buf.s == NULL) {
1083
-				ERR("No memory left\n");
1014
+				ERR("mysql: No memory left\n");
1015
+				err = 1;
1084 1016
 				goto error;
1085 1017
 			}
1086 1018
 			result[i].buffer = f->buf.s;
... ...
@@ -1092,7 +1024,8 @@ static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
1092 1024
 			result[i].buffer_type = MYSQL_TYPE_BLOB;
1093 1025
 			if (!f->buf.s) f->buf.s = pkg_malloc(STR_BUF_SIZE);
1094 1026
 			if (f->buf.s == NULL) {
1095
-				ERR("No memory left\n");
1027
+				ERR("mysql: No memory left\n");
1028
+				err = 1;
1096 1029
 				goto error;
1097 1030
 			}
1098 1031
 			result[i].buffer = f->buf.s;
... ...
@@ -1106,99 +1039,84 @@ static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
1106 1039
 
1107 1040
 		}
1108 1041
 	}
1109
-	if (mysql_stmt_bind_result(st, result)) {
1110
-		ERR("Error while binding result: %s\n", mysql_stmt_error(st));
1042
+
1043
+	err = mysql_stmt_bind_result(st, result);
1044
+	if (err) {
1045
+		ERR("mysql: Error while binding result: %s\n", mysql_stmt_error(st));
1111 1046
 		goto error;
1112 1047
 	}
1113 1048
 
1114 1049
 	/* We do not need the array of MYSQL_BIND anymore, mysql_stmt_bind_param
1115 1050
 	 * creates a copy in the statement and we will update it there
1116 1051
 	 */
1117
-	pkg_free(result);
1052
+	if (result) pkg_free(result);
1118 1053
 	return 0;
1119 1054
    
1120 1055
  error:
1121
- 	ERR("bind_result failed\n");
1122 1056
 	if (result) pkg_free(result);
1123
-	return -1;
1057
+	return err;
1124 1058
 }
1125 1059
 
1126 1060
 
1127
-static int upload_query(db_cmd_t* cmd)
1061
+/**
1062
+ * Upload database command to the server
1063
+ * @param cmd  Command to be uploaded
1064
+ * @return     0 if OK, >0 on DB API errors, <0 on MySQL errors
1065
+ */
1066
+static int upload_cmd(db_cmd_t* cmd)
1128 1067
 {
1129 1068
 	struct my_cmd* res;
1130 1069
 	struct my_con* mcon;
1131
-	MYSQL_STMT* st;
1132
-	int n;
1070
+	int err = 0;
1133 1071
 
1134 1072
 	res = DB_GET_PAYLOAD(cmd);
1135 1073
 
1136 1074
 	/* FIXME: The function should take the connection as one of parameters */
1137 1075
 	mcon = DB_GET_PAYLOAD(cmd->ctx->con[db_payload_idx]);
1138 1076
 
1139
-	st = mysql_stmt_init(mcon->con);
1140
-	if (st == NULL) goto error;
1141
-
1142
-	/* Close the previously created statement if exists */
1077
+	/* If there is a previous pre-compiled statement, close it first */
1143 1078
 	if (res->st) mysql_stmt_close(res->st);
1144
-    res->st = st;
1079
+	res->st = NULL;
1145 1080
 
1146
-	if (mysql_stmt_prepare(res->st, res->query.s, res->query.len)) {
1081
+	/* Create a new pre-compiled statement data structure */
1082
+	res->st = mysql_stmt_init(mcon->con);
1083
+	if (res->st == NULL) {
1084
+		ERR("mysql: Error while creating new MySQL_STMT data structure (no memory left)\n");
1085
+		err = 1;
1147 1086
 		goto error;
1148 1087
 	}
1149 1088
 
1150
-	switch(cmd->type) {
1151
-	case DB_PUT:
1152
-		if (bind_params(res->st, cmd->vals, NULL) < 0) goto error;
1153
-		break;
1154
-
1155
-	case DB_DEL:
1156
-		if (!DB_FLD_EMPTY(cmd->match)) {
1157
-			if (bind_params(res->st, NULL, cmd->match) < 0) goto error;
1158
-		}
1159
-		break;
1160
-
1161
-	case DB_GET:
1162
-		if (!DB_FLD_EMPTY(cmd->match)) {
1163
-			if (bind_params(res->st, NULL, cmd->match) < 0) goto error;
1164
-		}
1165
-		if (check_result_columns(cmd, res) < 0) goto error;
1166
-		if (bind_result(res->st, cmd->result) < 0) goto error;
1167
-		break;
1168
-
1169
-	case DB_UPD:
1170
-		if (mysql_stmt_prepare(res->st, res->query.s, res->query.len)) {
1171
-			goto error;
1172
-		}
1089
+	/* Try to upload the command to the server */
1090
+	err = mysql_stmt_prepare(res->st, res->sql_cmd.s, res->sql_cmd.len);
1091
+	if (err) {
1092
+		ERR("mysql: libmysql: %d, %s\n", mysql_stmt_errno(res->st), 
1093
+			mysql_stmt_error(res->st));
1094
+		ERR("mysql: An error occurred while uploading a command to MySQL server\n");
1095
+		goto error;
1096
+	}
1173 1097
 
1174
-        /* FIXME: remove ELSE */
1175
-        if (!DB_FLD_EMPTY(cmd->vals)) {
1176
-            if (bind_params(res->st, cmd->vals, cmd->match) < 0) goto error;
1177
-        } else {
1178
-            if (bind_params(res->st, NULL, cmd->match) < 0) goto error;
1179
-        }
1180
-		break;
1098
+	err = bind_mysql_params(res->st, cmd->vals, cmd->match);
1099
+	if (err) goto error;
1181 1100
 
1182
-	case DB_SQL:
1183
-		if (!DB_FLD_EMPTY(cmd->match)) {
1184
-			if (bind_params(res->st, NULL, cmd->match) < 0) goto error;
1185
-		}
1186
-
1187
-		n = mysql_stmt_field_count(res->st);
1188
-		/* create result fields and pass them to client */
1189
-		if (n > 0) {
1190
-			if (check_result_columns(cmd, res) < 0) goto error;
1191
-			if (bind_result(res->st, cmd->result) < 0) goto error;
1192
-		}
1193
-		break;
1101
+	if (cmd->type == DB_GET || cmd->type == DB_SQL) {
1102
+		err = check_result_columns(cmd, res);
1103
+		if (err) goto error;
1104
+		err = bind_result(res->st, cmd->result);
1105
+		if (err) goto error;
1194 1106
 	}
1107
+
1108
+	res->last_reset = mcon->resets;
1195 1109
 	return 0;
1196 1110
 
1197 1111
  error:
1198
-	ERR("Error while uploading query to server: %s\n", 
1199
-		mysql_stmt_error(res->st));
1200
-
1201
-	return -1;
1112
+	if (res->st) {
1113
+		ERR("mysql: libmysqlclient: %d, %s\n", 
1114
+			mysql_stmt_errno(res->st), 
1115
+			mysql_stmt_error(res->st));
1116
+		mysql_stmt_close(res->st);
1117
+		res->st = NULL;
1118
+	}
1119
+	return err;
1202 1120
 }
1203 1121
 
1204 1122
 
... ...
@@ -1208,7 +1126,7 @@ int my_cmd(db_cmd_t* cmd)
1208 1126
  
1209 1127
 	res = (struct my_cmd*)pkg_malloc(sizeof(struct my_cmd));
1210 1128
 	if (res == NULL) {
1211
-		ERR("No memory left\n");
1129
+		ERR("mysql: No memory left\n");
1212 1130
 		goto error;
1213 1131
 	}
1214 1132
 	memset(res, '\0', sizeof(struct my_cmd));
... ...
@@ -1217,41 +1135,45 @@ int my_cmd(db_cmd_t* cmd)
1217 1135
 	switch(cmd->type) {
1218 1136
 	case DB_PUT:
1219 1137
 		if (DB_FLD_EMPTY(cmd->vals)) {
1220
-			ERR("BUG: No parameters provided for DB_PUT in context '%.*s'\n", 
1138
+			BUG("mysql: No parameters provided for DB_PUT in context '%.*s'\n", 
1221 1139
 				cmd->ctx->id.len, ZSW(cmd->ctx->id.s));
1222 1140
 			goto error;
1223 1141
 		}
1224
-		if (build_replace_query(&res->query, cmd) < 0) goto error;
1142
+		if (build_replace_cmd(&res->sql_cmd, cmd) < 0) goto error;
1225 1143
 		break;
1226 1144
 
1227 1145
 	case DB_DEL:
1228
-		if (build_delete_query(&res->query, cmd) < 0) goto error;
1146
+		if (build_delete_cmd(&res->sql_cmd, cmd) < 0) goto error;
1229 1147
 		break;
1230 1148
 
1231 1149
 	case DB_GET:
1232
-		if (build_select_query(&res->query, cmd) < 0) goto error;
1150
+		if (build_select_cmd(&res->sql_cmd, cmd) < 0) goto error;
1233 1151
 		break;
1234 1152
 
1235 1153
 	case DB_UPD:
1236
-		if (build_update_query(&res->query, cmd) < 0) goto error;
1154
+		if (build_update_cmd(&res->sql_cmd, cmd) < 0) goto error;
1237 1155
 		break;
1238 1156
 
1239 1157
 	case DB_SQL:
1240
-		if (NULL == (res->query.s = (char*)pkg_malloc(cmd->table.len))) goto error;
1241
-		memcpy(res->query.s,cmd->table.s, cmd->table.len);
1242
-		res->query.len = cmd->table.len;
1158
+		res->sql_cmd.s = (char*)pkg_malloc(cmd->table.len);
1159
+		if (res->sql_cmd.s == NULL) {
1160
+			ERR("mysql: Out of private memory\n");
1161
+			goto error;
1162
+		}
1163
+		memcpy(res->sql_cmd.s,cmd->table.s, cmd->table.len);
1164
+		res->sql_cmd.len = cmd->table.len;
1243 1165
         break;
1244 1166
 	}
1245 1167
 
1246 1168
 	DB_SET_PAYLOAD(cmd, res);
1247
-	if (upload_query(cmd) < 0) goto error;
1169
+	if (upload_cmd(cmd) != 0) goto error;
1248 1170
 	return 0;
1249 1171
 
1250 1172
  error:
1251 1173
 	if (res) {
1252 1174
 		DB_SET_PAYLOAD(cmd, NULL);
1253 1175
 		db_drv_free(&res->gen);
1254
-		if (res->query.s) pkg_free(res->query.s);
1176
+		if (res->sql_cmd.s) pkg_free(res->sql_cmd.s);
1255 1177
 		pkg_free(res);
1256 1178
 	}
1257 1179
 	return -1;
... ...
@@ -1269,7 +1191,7 @@ int my_cmd_first(db_res_t* res) {
1269 1191
 		return 0;
1270 1192
 	case 1:  /* next row */
1271 1193
 	case 2:  /* EOF */
1272
-		ERR("my_cmd_first cannot reset cursor position. It's not supported for unbuffered mysql queries\n");
1194
+		ERR("mysql: Unbuffered queries do not support cursor reset.\n");
1273 1195
 		return -1;
1274 1196
 	default:
1275 1197
 		return my_cmd_next(res);
... ...
@@ -1292,10 +1214,11 @@ int my_cmd_next(db_res_t* res)
1292 1214
 	}
1293 1215
 	if (ret == MYSQL_DATA_TRUNCATED) {
1294 1216
 		int i;
1295
-		ERR("my_cmd_next: mysql_stmt_fetch, data truncated, fields: %d\n", res->cmd->result_count);
1217
+		ERR("mysql: mysql_stmt_fetch, data truncated, fields: %d\n", res->cmd->result_count);
1296 1218
 		for (i = 0; i < res->cmd->result_count; i++) {
1297 1219
 			if (mcmd->st->bind[i].error /*&& mcmd->st->bind[i].buffer_length*/) {
1298
-				ERR("truncation, bind %d, length: %lu, buffer_length: %lu\n", i, *(mcmd->st->bind[i].length), mcmd->st->bind[i].buffer_length);
1220
+				ERR("mysql: truncation, bind %d, length: %lu, buffer_length: %lu\n", 
1221
+					i, *(mcmd->st->bind[i].length), mcmd->st->bind[i].buffer_length);
1299 1222
 			}
1300 1223
 		}
1301 1224
 	}
... ...
@@ -1303,7 +1226,7 @@ int my_cmd_next(db_res_t* res)
1303 1226
 		mcmd->next_flag++;
1304 1227
 	}
1305 1228
 	if (ret != 0 && ret != MYSQL_DATA_TRUNCATED) {
1306
-		ERR("Error in mysql_stmt_fetch (ret=%d): %s\n", ret, mysql_stmt_error(mcmd->st));
1229
+		ERR("mysql: Error in mysql_stmt_fetch (ret=%d): %s\n", ret, mysql_stmt_error(mcmd->st));
1307 1230
 		return -1;
1308 1231
 	}
1309 1232
 
... ...
@@ -36,24 +36,24 @@
36 36
 struct my_cmd {
37 37
 	db_drv_t gen;
38 38
 
39
-	str query;
39
+	str sql_cmd; /**< Database command represented in SQL language */
40 40
 	int next_flag;
41
-	MYSQL_STMT* st;
41
+	MYSQL_STMT* st; /**< MySQL pre-compiled statement handle */
42
+
43
+	/** This is the sequential number of the last
44
+	 * connection reset last time the command was
45
+	 * uploaded to the server. If the reset number
46
+	 * in the corresponding my_con structure is higher
47
+	 * than the number in this variable then we need
48
+	 * to upload the command again, because the
49
+	 * the connection was reconnected meanwhile.
50
+	 */
51
+	unsigned int last_reset;
42 52
 };
43 53
 
44 54
 int my_cmd(db_cmd_t* cmd);
45 55
 
46
-/* Runtime execution function for DB_GET */
47
-int my_cmd_read(db_res_t* res, db_cmd_t* cmd);
48
-
49
-/* Runtime execution function for DB_PUT and DB_DEL */
50
-int my_cmd_write(db_res_t* res, db_cmd_t* cmd);
51
-
52
-/* Runtime execution function for DB_UPD */
53
-int my_cmd_update(db_res_t* res, db_cmd_t* cmd);
54
-
55
-/* Raw SQL query */
56
-int my_cmd_sql(db_res_t* res, db_cmd_t* cmd);
56
+int my_cmd_exec(db_res_t* res, db_cmd_t* cmd);
57 57
 
58 58
 int my_cmd_first(db_res_t* res);
59 59
 
... ...
@@ -26,14 +26,17 @@
26 26
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27 27
  */
28 28
 
29
+#include "my_con.h"
30
+
31
+#include "mysql_mod.h"
32
+#include "my_uri.h"
33
+
29 34
 #include "../../mem/mem.h"
30 35
 #include "../../dprint.h"
31 36
 #include "../../ut.h"
37
+
32 38
 #include <string.h>
33 39
 #include <time.h>
34
-#include "mysql_mod.h"
35
-#include "my_uri.h"
36
-#include "my_con.h"
37 40
 
38 41
 
39 42
 /*
... ...
@@ -47,45 +50,34 @@ static void my_con_free(db_con_t* con, struct my_con* payload)
47 50
 	 * to it in the connection pool
48 51
 	 */
49 52
 	if (db_pool_remove((db_pool_entry_t*)payload) == 0) return;
50
-
53
+	
51 54
 	db_pool_entry_free(&payload->gen);
52 55
 	if (payload->con) pkg_free(payload->con);
53 56
 	pkg_free(payload);
54 57
 }
55 58
 
56 59
 
57
-static int my_con_connect(db_con_t* con)
60
+int my_con_connect(db_con_t* con)
58 61
 {
59 62
 	struct my_con* mcon;
60 63
 	struct my_uri* muri;
61
-#if MYSQL_VERSION_ID >= 50013 
62
-	my_bool my_auto_reconnect;
63
-#endif
64
-
65
-
64
+	
66 65
 	mcon = DB_GET_PAYLOAD(con);
67 66
 	muri = DB_GET_PAYLOAD(con->uri);
68
-
67
+	
69 68
 	/* Do not reconnect already connected connections */
70 69
 	if (mcon->flags & MY_CONNECTED) return 0;
71 70
 
72
-	DBG("my_con_connect: Connecting to %.*s:%.*s\n",
71
+	DBG("mysql: Connecting to %.*s:%.*s\n",
73 72
 		con->uri->scheme.len, ZSW(con->uri->scheme.s),
74 73
 		con->uri->body.len, ZSW(con->uri->body.s));
75 74
 
76
-#if MYSQL_VERSION_ID >= 50013 
77
-	my_auto_reconnect = 1;
78
-	if (my_client_ver >= 50013) {
79
-		if (mysql_options(mcon->con, MYSQL_OPT_RECONNECT , 
80
-						  (char*)&my_auto_reconnect))
81
-			WARN("mysql: failed to set MYSQL_OPT_RECONNECT\n");
82
-	}
83
-#endif
84 75
 	if (my_connect_to) {
85 76
 		if (mysql_options(mcon->con, MYSQL_OPT_CONNECT_TIMEOUT, 
86 77
 						  (char*)&my_connect_to))
87 78
 			WARN("mysql: failed to set MYSQL_OPT_CONNECT_TIMEOUT\n");
88 79
 	}
80
+
89 81
 #if MYSQL_VERSION_ID >= 40101 
90 82
 	if ((my_client_ver >= 50025) || 
91 83
 		((my_client_ver >= 40122) && 
... ...
@@ -105,24 +97,29 @@ static int my_con_connect(db_con_t* con)
105 97
 	
106 98
 	if (!mysql_real_connect(mcon->con, muri->host, muri->username, 
107 99
 							muri->password, muri->database, muri->port, 0, 0)) {
108
-		LOG(L_ERR, "my_con_connect: %s\n", mysql_error(mcon->con));
100
+		LOG(L_ERR, "mysql: %s\n", mysql_error(mcon->con));
109 101
 		return -1;
110 102
 	}
111 103
 	
112
-	/* Enable reconnection explicitly */
113
-	mcon->con->reconnect = 1;
114
-	
115
-	DBG("my_con_connect: Connection type is %s\n", mysql_get_host_info(mcon->con));
116
-	DBG("my_con_connect: Protocol version is %d\n", mysql_get_proto_info(mcon->con));
117
-	DBG("my_con_connect: Server version is %s\n", mysql_get_server_info(mcon->con));
104
+	DBG("mysql: Connection type is %s\n", mysql_get_host_info(mcon->con));
105
+	DBG("mysql: Protocol version is %d\n", mysql_get_proto_info(mcon->con));
106
+	DBG("mysql: Server version is %s\n", mysql_get_server_info(mcon->con));
118 107
 
119
-	mcon->timestamp = time(0);
120 108
 	mcon->flags |= MY_CONNECTED;
109
+
110
+	/* Increase the variable that keeps track of number of connects performed
111
+	 * on this connection. The mysql module uses the variable to determine
112
+	 * when a pre-compiled command needs to be uploaded to the server again.
113
+	 * If the number in the my_con structure is large than the number kept
114
+	 * in my_cmd then it means that we have to upload the command to the server
115
+	 * again because the connection was reconnected meanwhile.
116
+	 */
117
+	mcon->resets++;
121 118
 	return 0;
122 119
 }
123 120
 
124 121
 
125
-static void my_con_disconnect(db_con_t* con)
122
+void my_con_disconnect(db_con_t* con)
126 123
 {
127 124
 	struct my_con* mcon;
128 125
 
... ...
@@ -130,7 +127,7 @@ static void my_con_disconnect(db_con_t* con)
130 127
 
131 128
 	if ((mcon->flags & MY_CONNECTED) == 0) return;
132 129
 
133
-	DBG("my_con_disconnect: Disconnecting from %.*s:%.*s\n",
130
+	DBG("mysql: Disconnecting from %.*s:%.*s\n",
134 131
 		con->uri->scheme.len, ZSW(con->uri->scheme.s),
135 132
 		con->uri->body.len, ZSW(con->uri->body.s));
136 133
 
... ...
@@ -149,7 +146,7 @@ int my_con(db_con_t* con)
149 146
 	 */
150 147
 	ptr = (struct my_con*)db_pool_get(con->uri);
151 148
 	if (ptr) {
152
-		DBG("my_con: Connection to %.*s:%.*s found in connection pool\n",
149
+		DBG("mysql: Connection to %.*s:%.*s found in connection pool\n",
153 150
 			con->uri->scheme.len, ZSW(con->uri->scheme.s),
154 151
 			con->uri->body.len, ZSW(con->uri->body.s));
155 152
 		goto found;
... ...
@@ -157,7 +154,7 @@ int my_con(db_con_t* con)
157 154
 
158 155
 	ptr = (struct my_con*)pkg_malloc(sizeof(struct my_con));
159 156
 	if (!ptr) {
160
-		LOG(L_ERR, "my_con: No memory left\n");
157
+		LOG(L_ERR, "mysql: No memory left\n");
161 158
 		goto error;
162 159
 	}
163 160
 	memset(ptr, '\0', sizeof(struct my_con));
... ...
@@ -165,19 +162,19 @@ int my_con(db_con_t* con)
165 162
 
166 163
 	ptr->con = (MYSQL*)pkg_malloc(sizeof(MYSQL));
167 164
 	if (!ptr->con) {
168
-		LOG(L_ERR, "my_con: No enough memory\n");
165
+		LOG(L_ERR, "mysql: No enough memory\n");
169 166
 		goto error;
170 167
 	}
171 168
 	mysql_init(ptr->con);
172 169
 
173 170
 	uri = DB_GET_PAYLOAD(con->uri);
174
-	DBG("my_con: Creating new connection to: %.*s:%.*s\n",
171
+	DBG("mysql: Creating new connection to: %.*s:%.*s\n",
175 172
 		con->uri->scheme.len, ZSW(con->uri->scheme.s),
176 173
 		con->uri->body.len, ZSW(con->uri->body.s));
177 174
 
178 175
 	/* Put the newly created mysql connection into the pool */
179 176
 	db_pool_put((struct db_pool_entry*)ptr);
180
-	DBG("my_con: Connection stored in connection pool\n");
177
+	DBG("mysql: Connection stored in connection pool\n");
181 178
 
182 179
  found:
183 180
 	/* Attach driver payload to the db_con structure and set connect and
... ...
@@ -40,14 +40,21 @@ enum my_flags {
40 40
 	MY_CONNECTED = 1
41 41
 };
42 42
 
43
-struct my_con {
43
+typedef struct my_con {
44 44
 	/* Generic part of the structure */
45 45
 	db_pool_entry_t gen;
46 46
 
47 47
 	MYSQL* con;
48 48
 	unsigned int flags;
49
-	time_t timestamp;
50
-};
49
+	
50
+	/* We keep the number of connection resets in this variable,
51
+	 * this variable is incremented each time the module performs
52
+	 * a re-connect on the connection. This is used by my_cmd
53
+	 * related functions to check if a pre-compiled command needs
54
+	 * to be uploaded to the server before executing it.
55
+	 */
56
+	unsigned int resets;
57
+} my_con_t;
51 58
 
52 59
 
53 60
 /*
... ...
@@ -56,4 +63,7 @@ struct my_con {
56 63
  */
57 64
 int my_con(db_con_t* con);
58 65
 
66
+int my_con_connect(db_con_t* con);
67
+void my_con_disconnect(db_con_t* con);
68
+
59 69
 #endif /* _MY_CON_H */
... ...
@@ -26,11 +26,13 @@
26 26
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27 27
  */
28 28
 
29
-#include <string.h>
29
+#include "my_fld.h"
30
+
30 31
 #include "../../mem/mem.h"
31 32
 #include "../../dprint.h"
32 33
 #include "../../db/db_gen.h"
33
-#include "my_fld.h"
34
+
35
+#include <string.h>
34 36
 
35 37
 
36 38
 static void my_fld_free(db_fld_t* fld, struct my_fld* payload)
... ...
@@ -48,7 +50,7 @@ int my_fld(db_fld_t* fld, char* table)
48 50
 
49 51
 	res = (struct my_fld*)pkg_malloc(sizeof(struct my_fld));
50 52
 	if (res == NULL) {
51
-		ERR("No memory left\n");
53
+		ERR("mysql: No memory left\n");
52 54
 		return -1;
53 55
 	}
54 56
 	memset(res, '\0', sizeof(struct my_fld));
... ...
@@ -26,12 +26,15 @@
26 26
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27 27
  */
28 28
 
29
-#include <mysql/mysql.h>
29
+#include "my_res.h"
30
+
31
+#include "my_cmd.h"
32
+
30 33
 #include "../../mem/mem.h"
31 34
 #include "../../dprint.h"
32 35
 #include "../../db/db_gen.h"
33
-#include "my_cmd.h"
34
-#include "my_res.h"
36
+
37
+#include <mysql/mysql.h>
35 38
 
36 39
 
37 40
 void my_res_free(db_res_t* res, struct my_res* payload)
... ...
@@ -41,7 +44,8 @@ void my_res_free(db_res_t* res, struct my_res* payload)
41 44
 	mcmd = DB_GET_PAYLOAD(res->cmd);
42 45
 
43 46
 	if (mcmd->st && mysql_stmt_free_result(mcmd->st)) {
44
-		ERR("Error while freeing MySQL result: %s\n", mysql_stmt_error(mcmd->st));
47
+		ERR("mysql: Error while freeing MySQL result: %d, %s\n", 
48
+			mysql_stmt_errno(mcmd->st), mysql_stmt_error(mcmd->st));
45 49
 	}
46 50
 
47 51
 	db_drv_free(&payload->gen);
... ...
@@ -60,7 +64,7 @@ int my_res(db_res_t* res)
60 64
 
61 65
 	mr = (struct my_res*)pkg_malloc(sizeof(struct my_res));
62 66
 	if (mr == NULL) {
63
-		ERR("No memory left\n");
67
+		ERR("mysql: No memory left\n");
64 68
 		return -1;
65 69
 	}
66 70
 	if (db_drv_init(&mr->gen, my_res_free) < 0) goto error;
... ...
@@ -28,13 +28,15 @@
28 28
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 29
  */
30 30
 
31
-#include <stdlib.h>
32
-#include <string.h>
31
+#include "my_uri.h"
32
+
33 33
 #include "../../dprint.h"
34 34
 #include "../../mem/mem.h"
35 35
 #include "../../ut.h"
36 36
 #include "../../db/db_gen.h"
37
-#include "my_uri.h"
37
+
38
+#include <stdlib.h>
39
+#include <string.h>
38 40
 
39 41
 
40 42
 /* compare s1 & s2  with a function f (which should return 0 if ==);
... ...
@@ -259,7 +261,7 @@ int my_uri(db_uri_t* uri)
259 261
 
260 262
 	res = (struct my_uri*)pkg_malloc(sizeof(struct my_uri));
261 263
 	if (res == NULL) {
262
-		ERR("No memory left\n");
264
+		ERR("mysql: No memory left\n");
263 265
 		goto error;
264 266
 	}
265 267
 	memset(res, '\0', sizeof(struct my_uri));
... ...
@@ -37,20 +37,22 @@
37 37
  *  @{
38 38
  */
39 39
  
40
-#include "../../sr_module.h"
41
-#include "../../db/db.h"
40
+#include "mysql_mod.h"
41
+
42 42
 #include "my_uri.h"
43 43
 #include "my_con.h"
44 44
 #include "my_cmd.h"
45 45
 #include "my_fld.h"
46 46
 #include "my_res.h"
47
-#include "mysql_mod.h"
48 47
 
49
-int ping_interval = 5 * 60; /* Default is 5 minutes */
50
-int auto_reconnect = 1;     /* Default is enabled */
48
+#include "../../sr_module.h"
49
+#include "../../db/db.h"
50
+
51
+int my_ping_interval = 5 * 60; /* Default is 5 minutes */
51 52
 unsigned int my_connect_to = 2; /* 2 s by default */
52 53
 unsigned int my_send_to = 0; /*  enabled only for mysql >= 5.25  */
53 54
 unsigned int my_recv_to = 0; /* enabled only for mysql >= 5.25 */