Browse code

Preparation for implementation of UPDATE db statement. First of all we need two sets of params in db_cmd. First for match clause and the second as column-value pairs of changed columns. Currently it uses three sets of parameters: result, match and vals. - result - DB_GET output - match - DB_GET, DB_DEL (and DB_UPD in the future) - vals - DB_PUT (and DB_UPD)

Libor Chocholaty authored on 25/06/2007 17:51:27
Showing 15 changed files
... ...
@@ -719,7 +719,7 @@ int log_request(struct sip_msg *rq, str* ouri, struct hdr_field *to, db_cmd_t* c
719 719
 	int cnt;
720 720
 	if (skip_cancel(rq)) return 1;
721 721
 
722
-	cnt = fmt2strar(log_fmt, rq, ouri, to, code, req_timestamp, cmd->params);
722
+	cnt = fmt2strar(log_fmt, rq, ouri, to, code, req_timestamp, cmd->vals);
723 723
 	if (cnt == 0) {
724 724
 		LOG(L_ERR, "ERROR:acc:log_request: fmt2strar failed\n");
725 725
 		return -1;
... ...
@@ -954,14 +954,14 @@ static int child_init(int rank)
954 954
 		if (db_add_db(acc_db, db_url.s) < 0) return -1;
955 955
 		if (db_connect(acc_db) < 0) return -1;
956 956
 
957
-		write_acc = db_cmd(DB_PUT, acc_db, acc_table.s, NULL, fld);
957
+		write_acc = db_cmd(DB_PUT, acc_db, acc_table.s, NULL, NULL, fld);
958 958
 		if (write_acc == NULL) {
959 959
 			ERR("Error while compiling database query\n");
960 960
 			db_ctx_free(acc_db);
961 961
 			return -1;
962 962
 		}
963 963
 
964
-		write_mc = db_cmd(DB_PUT, acc_db, mc_table.s, NULL, fld);
964
+		write_mc = db_cmd(DB_PUT, acc_db, mc_table.s, NULL, NULL, fld);
965 965
 		if (write_mc == NULL) {
966 966
 			ERR("Error while compiling database query\n");
967 967
 			db_cmd_free(write_acc);
... ...
@@ -163,61 +163,61 @@ static authdb_table_info_t *registered_tables = NULL;
163 163
 
164 164
 static int generate_queries(authdb_table_info_t *info)
165 165
 {
166
-	db_fld_t params_with_did[] = {
166
+	db_fld_t match_with_did[] = {
167 167
 		{ .name = username_column.s, .type = DB_STR }, 
168 168
 		{ .name = realm_column.s, .type = DB_STR }, 
169 169
 		{ .name = did_column.s, .type = DB_STR }, 
170 170
 		{ .name = NULL }
171 171
 	};
172
-	db_fld_t params_without_did[] = {
172
+	db_fld_t match_without_did[] = {
173 173
 		{ .name = username_column.s, .type = DB_STR }, 
174 174
 		{ .name = realm_column.s, .type = DB_STR }, 
175 175
 		{ .name = NULL }
176 176
 	};
177
-	db_fld_t *results = NULL;
177
+	db_fld_t *result_cols = NULL;
178 178
 	int len, i;
179 179
 
180
-	len = sizeof(*results) * (credentials_n + 3);
181
-	results = pkg_malloc(len);
182
-	if (!results) {
180
+len = sizeof(*result_cols) * (credentials_n + 3);
181
+	result_cols = pkg_malloc(len);
182
+	if (!result_cols) {
183 183
 		ERR("can't allocate pkg mem\n");
184 184
 		return -1;
185 185
 	}
186
-	memset(results, 0, len);
186
+	memset(result_cols, 0, len);
187 187
 
188
-	results[0].name = pass_column.s;
189
-	results[0].type = DB_CSTR;
188
+	result_cols[0].name = pass_column.s;
189
+	result_cols[0].type = DB_CSTR;
190 190
 	
191
-	results[1].name = flags_column.s;
192
-	results[1].type = DB_INT;
191
+	result_cols[1].name = flags_column.s;
192
+	result_cols[1].type = DB_INT;
193 193
 	for (i = 0; i < credentials_n; i++) {
194
-		results[2 + i].name = credentials[i].s;
195
-		results[2 + i].type = DB_STR;
194
+		result_cols[2 + i].name = credentials[i].s;
195
+		result_cols[2 + i].type = DB_STR;
196 196
 	}
197
-	results[2 + i].name = NULL;
197
+	result_cols[2 + i].name = NULL;
198 198
 
199 199
 	if (use_did) {
200 200
 		info->query_pass = db_cmd(DB_GET, auth_db_handle, info->table.s, 
201
-				results, params_with_did);
202
-		results[0].name = pass_column_2.s;
201
+				result_cols, match_with_did, NULL);
202
+		result_cols[0].name = pass_column_2.s;
203 203
 		info->query_pass2 = db_cmd(DB_GET, auth_db_handle, info->table.s, 
204
-				results, params_with_did);
205
-		results[0].name = plain_password_column.s;
204
+				result_cols, match_with_did, NULL);
205
+		result_cols[0].name = plain_password_column.s;
206 206
 		info->query_password = db_cmd(DB_GET, auth_db_handle, info->table.s, 
207
-				results, params_with_did);
207
+				result_cols, match_with_did, NULL);
208 208
 	}
209 209
 	else {
210 210
 		info->query_pass = db_cmd(DB_GET, auth_db_handle, info->table.s, 
211
-				results, params_without_did);
212
-		results[0].name = pass_column_2.s;
211
+				result_cols, match_without_did, NULL);
212
+		result_cols[0].name = pass_column_2.s;
213 213
 		info->query_pass2 = db_cmd(DB_GET, auth_db_handle, info->table.s, 
214
-				results, params_without_did);
215
-		results[0].name = plain_password_column.s;
214
+				result_cols, match_without_did, NULL);
215
+		result_cols[0].name = plain_password_column.s;
216 216
 		info->query_password = db_cmd(DB_GET, auth_db_handle, info->table.s, 
217
-				results, params_without_did);
217
+				result_cols, match_without_did, NULL);
218 218
 	}
219 219
 
220
-	pkg_free(results);
220
+	pkg_free(result_cols);
221 221
 	if (info->query_pass && info->query_pass2 && info->query_password) return 0;
222 222
 	else return -1;
223 223
 }
... ...
@@ -76,10 +76,10 @@ static inline int get_ha1(struct username* username, str* did, str* realm,
76 76
 		}
77 77
 	}
78 78
     
79
-    q->params[0].v.lstr = username->user;
80
-    q->params[1].v.lstr = *realm;
79
+    q->match[0].v.lstr = username->user;
80
+    q->match[1].v.lstr = *realm;
81 81
 
82
-	if (use_did) q->params[2].v.lstr = *did;
82
+	if (use_did) q->match[2].v.lstr = *did;
83 83
 
84 84
 	if (db_exec(res, q) < 0 ) {
85 85
 		ERR("Error while querying database\n");
... ...
@@ -136,20 +136,20 @@ static int mod_init(void)
136 136
 
137 137
 static int child_init(int rank)
138 138
 {
139
-	db_fld_t res[] = {
139
+	db_fld_t res_cols[] = {
140 140
 		{.name = name_column, .type = DB_STR},
141 141
 		{.name = type_column, .type = DB_INT},
142 142
 		{.name = val_column, .type = DB_STR},
143 143
 		{.name = flags_column, .type = DB_BITMAP},
144 144
 		{.name = NULL}
145 145
 	};
146
-	db_fld_t params_uri[] = {
146
+	db_fld_t match_uri[] = {
147 147
 		{.name = username_column, .type = DB_STR, .op = DB_EQ},
148 148
 		{.name = did_column, .type = DB_STR, .op = DB_EQ},
149 149
 		{.name = scheme_column, .type = DB_STR, .op = DB_EQ},
150 150
 		{.name = NULL}
151 151
 	};
152
-	db_fld_t params_user[] = {
152
+	db_fld_t match_user[] = {
153 153
 		{.name = uid_column, .type = DB_STR, .op = DB_EQ},
154 154
 		{.name = NULL}
155 155
 	};
... ...
@@ -162,10 +162,10 @@ static int child_init(int rank)
162 162
 	if (db_add_db(ctx, db_url) < 0) goto err;
163 163
 	if (db_connect(ctx) < 0) goto err;
164 164
 	
165
-	load_uri_attrs_cmd = db_cmd(DB_GET, ctx, uri_attrs_table, res, params_uri);
165
+	load_uri_attrs_cmd = db_cmd(DB_GET, ctx, uri_attrs_table, res_cols, match_uri, NULL);
166 166
 	if (!load_uri_attrs_cmd) goto err;
167 167
 
168
-	load_user_attrs_cmd = db_cmd(DB_GET, ctx, user_attrs_table, res, params_user);
168
+	load_user_attrs_cmd = db_cmd(DB_GET, ctx, user_attrs_table, res_cols, match_user, NULL);
169 169
 	if (!load_user_attrs_cmd) goto err;
170 170
 
171 171
 	if (init_extra_avp_queries(ctx) < 0) goto err;
... ...
@@ -266,21 +266,21 @@ static int load_uri_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp
266 266
 		return -1;
267 267
 	}
268 268
 
269
-    load_uri_attrs_cmd->params[0].v.lstr = puri.user;
269
+    load_uri_attrs_cmd->match[0].v.lstr = puri.user;
270 270
 
271 271
 	if (puri.host.len) {
272 272
 		/* domain name is present */
273
-		if (dm_get_did(&load_uri_attrs_cmd->params[1].v.lstr, &puri.host) < 0) {
273
+		if (dm_get_did(&load_uri_attrs_cmd->match[1].v.lstr, &puri.host) < 0) {
274 274
 			DBG("Cannot lookup DID for domain %.*s, using default value\n", puri.host.len, ZSW(puri.host.s));
275
-			load_uri_attrs_cmd->params[1].v.lstr = default_did;
275
+			load_uri_attrs_cmd->match[1].v.lstr = default_did;
276 276
 		}
277 277
 	} else {
278 278
 		/* domain name is missing -- can be caused by tel: URI */
279 279
 		DBG("There is no domain name, using default value\n");
280
-		load_uri_attrs_cmd->params[1].v.lstr = default_did;
280
+		load_uri_attrs_cmd->match[1].v.lstr = default_did;
281 281
 	}
282 282
 
283
-    uri_type_to_str(puri.type, &(load_uri_attrs_cmd->params[2].v.lstr));
283
+    uri_type_to_str(puri.type, &(load_uri_attrs_cmd->match[2].v.lstr));
284 284
 
285 285
 	if (db_exec(&res, load_uri_attrs_cmd) < 0) {
286 286
 		ERR("Error while quering database\n");
... ...
@@ -299,7 +299,7 @@ static int load_user_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* f
299 299
 {
300 300
     db_res_t* res;
301 301
 
302
-	if (get_str_fparam(&load_user_attrs_cmd->params[0].v.lstr, msg, (fparam_t*)fp) < 0) {
302
+	if (get_str_fparam(&load_user_attrs_cmd->match[0].v.lstr, msg, (fparam_t*)fp) < 0) {
303 303
 		ERR("Unable to get UID\n");
304 304
 		return -1;
305 305
 	}
... ...
@@ -196,7 +196,7 @@ int declare_attr_group(modparam_t type, char* _param)
196 196
  * Variable default_res holds columns which can used by read_attrs. */
197 197
 static int init_queries(db_ctx_t *ctx, registered_table_t *t)
198 198
 {
199
-	db_fld_t params[] = {
199
+	db_fld_t match[] = {
200 200
 		{ .name = t->key_column, .type = DB_STR, .op = DB_EQ },
201 201
 		{ .name = NULL }
202 202
 	};
... ...
@@ -209,7 +209,7 @@ static int init_queries(db_ctx_t *ctx, registered_table_t *t)
209 209
 		{ .name = t->flags_column, .type = DB_BITMAP, .op = DB_EQ },
210 210
 		{ .name = NULL }
211 211
 	};
212
-	db_fld_t add_params[] = {
212
+	db_fld_t add_values[] = {
213 213
 		{ .name = t->key_column, .type = DB_STR, .op = DB_EQ },
214 214
 		{ .name = t->name_column, .type = DB_STR, .op = DB_EQ },
215 215
 		{ .name = t->type_column, .type = DB_INT, .op = DB_EQ },
... ...
@@ -218,9 +218,9 @@ static int init_queries(db_ctx_t *ctx, registered_table_t *t)
218 218
 		{ .name = NULL }
219 219
 	};
220 220
 
221
-	t->query = db_cmd(DB_GET, ctx, t->table_name, query_res, params);
222
-	t->remove = db_cmd(DB_DEL, ctx, t->table_name, NULL, params);
223
-	t->add = db_cmd(DB_PUT, ctx, t->table_name, NULL, add_params);
221
+	t->query = db_cmd(DB_GET, ctx, t->table_name, query_res, match, NULL);
222
+	t->remove = db_cmd(DB_DEL, ctx, t->table_name, NULL, match, NULL);
223
+	t->add = db_cmd(DB_PUT, ctx, t->table_name, NULL, NULL, add_values);
224 224
 
225 225
 	if (t->query && t->remove && t->add) return 0;
226 226
 	else return -1; /* not all queries were initialized */
... ...
@@ -261,16 +261,16 @@ static inline int save_avp(registered_table_t *t, avp_t *avp, str *id) /* id MUS
261 261
 	int type;
262 262
 	static str empty = STR_STATIC_INIT("");
263 263
 	
264
-	set_str_val(t->add->params[0], *id);
264
+	set_str_val(t->add->vals[0], *id);
265 265
 	
266 266
 	s = get_avp_name(avp);
267 267
 	if (!s) s = &empty;
268
-	set_str_val(t->add->params[1], *s);
268
+	set_str_val(t->add->vals[1], *s);
269 269
 	
270 270
 	get_avp_value_ex(avp, &v, &type);
271
-	set_int_val(t->add->params[2], type);
272
-	set_str_val(t->add->params[3], v);
273
-	set_int_val(t->add->params[4], avp->flags & (AVP_CLASS_ALL | AVP_TRACK_ALL | AVP_NAME_STR | AVP_VAL_STR));
271
+	set_int_val(t->add->vals[2], type);
272
+	set_str_val(t->add->vals[3], v);
273
+	set_int_val(t->add->vals[4], avp->flags & (AVP_CLASS_ALL | AVP_TRACK_ALL | AVP_NAME_STR | AVP_VAL_STR));
274 274
 	
275 275
 	if (db_exec(NULL, t->add) < 0) {
276 276
 		ERR("Can't insert record into DB\n");
... ...
@@ -315,7 +315,7 @@ static int read_avps(db_res_t *res, avp_flags_t flag) /* id must not be NULL */
315 315
 /** Removes all attributes with given ID.  The ID must not be NULL.  */
316 316
 static inline int remove_all_avps(registered_table_t *t, str *id)
317 317
 {
318
-	set_str_val(t->remove->params[0], *id);
318
+	set_str_val(t->remove->match[0], *id);
319 319
 	if (db_exec(NULL, t->remove) < 0) {
320 320
 		ERR("can't remove attrs\n");
321 321
 		return -1;
... ...
@@ -337,7 +337,7 @@ int load_extra_attrs(struct sip_msg* msg, char* _table, char* _id)
337 337
 		return -1;
338 338
 	}
339 339
 	
340
-	set_str_val(t->query->params[0], id);
340
+	set_str_val(t->query->match[0], id);
341 341
 	if (db_exec(&res, t->query) < 0) {
342 342
 		ERR("DB query failed\n");
343 343
 		return -1;
... ...
@@ -183,7 +183,7 @@ int db_load_domain_attrs(domain_t* d)
183 183
 	db_rec_t* rec;
184 184
     unsigned short flags;
185 185
     
186
-	load_attrs_cmd->params[0].v.lstr = d->did;
186
+	load_attrs_cmd->match[0].v.lstr = d->did;
187 187
 
188 188
 	if (db_exec(&res, load_attrs_cmd) < 0) {
189 189
 		ERR("Error while quering database\n");
... ...
@@ -174,28 +174,28 @@ struct module_exports exports = {
174 174
 
175 175
 static int init_db(void)
176 176
 {
177
-	db_fld_t res1[] = {
177
+	db_fld_t load_domains_columns[] = {
178 178
 		{.name = did_col.s,    DB_STR},
179 179
 		{.name = domain_col.s, DB_STR},
180 180
 		{.name = flags_col.s,  DB_BITMAP},
181 181
 		{.name = NULL}
182 182
 	};
183
-	db_fld_t res2[] = {
183
+	db_fld_t get_did_columns[] = {
184 184
 		{.name = did_col.s, DB_STR},
185 185
 		{.name = NULL}
186 186
 	};
187
-	db_fld_t res3[] = {
187
+	db_fld_t load_attrs_columns[] = {
188 188
 		{.name = domattr_name.s, .type = DB_STR},
189 189
 		{.name = domattr_type.s, .type = DB_INT},
190 190
 		{.name = domattr_value.s, .type = DB_STR},
191 191
 		{.name = domattr_flags.s, .type = DB_BITMAP},
192 192
 		{.name = NULL}
193 193
 	};
194
-	db_fld_t params[] = {
194
+	db_fld_t get_did_match[] = {
195 195
 		{.name = domain_col.s, DB_STR},
196 196
 		{.name = NULL}
197 197
 	};
198
-	db_fld_t params2[] = {
198
+	db_fld_t load_attrs_match[] = {
199 199
 		{.name = domattr_did.s, .type = DB_STR},
200 200
 		{.name = NULL}
201 201
 	};
... ...
@@ -208,19 +208,22 @@ static int init_db(void)
208 208
 	if (db_add_db(db, db_url.s) < 0) return -1;
209 209
 	if (db_connect(db) < 0) return -1;
210 210
 	
211
-	load_domains_cmd = db_cmd(DB_GET, db, domain_table.s, res1, NULL);
211
+	INFO("prepare load_domains_cmd\n");
212
+	load_domains_cmd = db_cmd(DB_GET, db, domain_table.s, load_domains_columns, NULL, NULL);
212 213
 	if (load_domains_cmd == NULL) {
213 214
 		ERR("Error while preparing load_domains database command\n");
214 215
 		return -1;
215 216
 	}
216 217
 	
217
-	get_did_cmd = db_cmd(DB_GET, db, domain_table.s, res2, params);
218
+	INFO("prepare get_did_cmd\n");
219
+	get_did_cmd = db_cmd(DB_GET, db, domain_table.s, get_did_columns, get_did_match, NULL);
218 220
 	if (get_did_cmd == NULL) {
219
-		ERR("Error while preparing load_domains database command\n");
221
+		ERR("Error while preparing get_did database command\n");
220 222
 		return -1;
221 223
 	}
222 224
 
223
-	load_attrs_cmd = db_cmd(DB_GET, db, domattr_table.s, res3, params2);
225
+	INFO("prepare load_attrs_cmd\n");
226
+	load_attrs_cmd = db_cmd(DB_GET, db, domattr_table.s, load_attrs_columns, load_attrs_match, NULL);
224 227
 	if (load_attrs_cmd == NULL) {
225 228
 		ERR("Error while preparing load_attrs database command\n");
226 229
 		return -1;
... ...
@@ -396,7 +399,7 @@ static int db_get_did(str* did, str* domain)
396 399
 		goto err;
397 400
     }
398 401
     
399
-	get_did_cmd->params[0].v.lstr = *domain;
402
+	get_did_cmd->match[0].v.lstr = *domain;
400 403
 
401 404
 	if (db_exec(&res, get_did_cmd) < 0) {
402 405
 		ERR("Error in database query\n");
... ...
@@ -132,7 +132,7 @@ static int init_db(void)
132 132
 		{.name = NULL}
133 133
 	};
134 134
 
135
-	db_fld_t params[] = {
135
+	db_fld_t values[] = {
136 136
 		{.name = attr_name,  DB_CSTR},
137 137
 		{.name = attr_type,  DB_INT},
138 138
 		{.name = attr_value, DB_STR},
... ...
@@ -148,13 +148,14 @@ static int init_db(void)
148 148
 	if (db_add_db(db, db_url) < 0) return -1;
149 149
 	if (db_connect(db) < 0) return -1;
150 150
 	
151
-	load_attrs_cmd = db_cmd(DB_GET, db, attr_table, attr_res, NULL);
151
+	/* SELECT name, type, value, flags FROM global_attrs */
152
+	load_attrs_cmd = db_cmd(DB_GET, db, attr_table, attr_res, NULL, NULL);
152 153
 	if (load_attrs_cmd == NULL) {
153 154
 		ERR("Error while building db query to load global attributes\n");
154 155
 		return -1;
155 156
 	}
156 157
 
157
-	save_gflags_cmd = db_cmd(DB_PUT, db, attr_table, NULL, params);
158
+	save_gflags_cmd = db_cmd(DB_PUT, db, attr_table, NULL, NULL, values);
158 159
 	if (save_gflags_cmd == NULL) {
159 160
 		ERR("Error while building db query to save global flags\n");
160 161
 		return -1;
... ...
@@ -361,10 +362,10 @@ int save_gflags(unsigned int flags)
361 362
 
362 363
 	fl.s = int2str(flags, &fl.len);
363 364
 
364
-	save_gflags_cmd->params[0].v.cstr = AVP_GFLAGS;
365
-	save_gflags_cmd->params[1].v.int4 = 0;
366
-	save_gflags_cmd->params[2].v.lstr = fl;
367
-	save_gflags_cmd->params[3].v.bitmap = DB_LOAD_SER;
365
+	save_gflags_cmd->vals[0].v.cstr = AVP_GFLAGS;
366
+	save_gflags_cmd->vals[1].v.int4 = 0;
367
+	save_gflags_cmd->vals[2].v.lstr = fl;
368
+	save_gflags_cmd->vals[3].v.bitmap = DB_LOAD_SER;
368 369
 
369 370
 	if (db_exec(NULL, save_gflags_cmd) < 0) {
370 371
 		LOG(L_ERR, "gflags:save_gflag: Unable to store new value\n");
... ...
@@ -26,6 +26,10 @@
26 26
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27 27
  */
28 28
 
29
+/** @addtogroup mysql
30
+ *  @{
31
+ */
32
+
29 33
 #define _XOPEN_SOURCE 4     /* bsd */
30 34
 #define _XOPEN_SOURCE_EXTENDED 1    /* solaris */
31 35
 #define _SVID_SOURCE 1 /* timegm */
... ...
@@ -50,6 +54,7 @@ enum {
50 54
 	STR_UPDATE,
51 55
 	STR_SELECT,
52 56
 	STR_REPLACE,
57
+	STR_SET,
53 58
 	STR_WHERE,
54 59
 	STR_IS,
55 60
 	STR_AND,
... ...
@@ -67,9 +72,10 @@ enum {
67 72
 static str strings[] = {
68 73
 	STR_STATIC_INIT("delete from "),
69 74
 	STR_STATIC_INIT("insert into "),
70
-	STR_STATIC_INIT("update "),
75
+	STR_STATIC_INIT("UPDATE "),
71 76
 	STR_STATIC_INIT("select "),
72 77
 	STR_STATIC_INIT("replace "),
78
+	STR_STATIC_INIT(" SET "),
73 79
 	STR_STATIC_INIT(" where "),
74 80
 	STR_STATIC_INIT(" is "),
75 81
 	STR_STATIC_INIT(" and "),
... ...
@@ -108,6 +114,11 @@ static void my_cmd_free(db_cmd_t* cmd, struct my_cmd* payload)
108 114
 }
109 115
 
110 116
 
117
+/**
118
+ *  Builds DELETE statement where cmd->match specify WHERE clause.
119
+ * @param query  SQL statement as a result of this function
120
+ * @param cmd    input for statement creation
121
+ */
111 122
 static int build_delete_query(str* query, db_cmd_t* cmd)
112 123
 {
113 124
 	db_fld_t* fld;
... ...
@@ -117,10 +128,10 @@ static int build_delete_query(str* query, db_cmd_t* cmd)
117 128
 	query->len = strings[STR_DELETE].len;
118 129
 	query->len += cmd->table.len;
119 130
 
120
-	if (!DB_FLD_EMPTY(cmd->params)) {
131
+	if (!DB_FLD_EMPTY(cmd->match)) {
121 132
 		query->len += strings[STR_WHERE].len;
122 133
 
123
-		for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
134
+		for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
124 135
 			query->len += strlen(fld[i].name);
125 136
 
126 137
 			switch(fld[i].op) {
... ...
@@ -150,10 +161,10 @@ static int build_delete_query(str* query, db_cmd_t* cmd)
150 161
 	APPEND_STR(p, strings[STR_DELETE]);
151 162
 	APPEND_STR(p, cmd->table);
152 163
 
153
-	if (!DB_FLD_EMPTY(cmd->params)) {
164
+	if (!DB_FLD_EMPTY(cmd->match)) {
154 165
 		APPEND_STR(p, strings[STR_WHERE]);
155 166
 
156
-		for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
167
+		for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
157 168
 			APPEND_CSTR(p, fld[i].name);
158 169
 
159 170
 			switch(fld[i].op) {
... ...
@@ -174,6 +185,12 @@ static int build_delete_query(str* query, db_cmd_t* cmd)
174 185
 }
175 186
 
176 187
 
188
+/**
189
+ *  Builds SELECT statement where cmd->values specify column names
190
+ *  and cmd->match specify WHERE clause.
191
+ * @param query  SQL statement as a result of this function
192
+ * @param cmd    input for statement creation
193
+ */
177 194
 static int build_select_query(str* query, db_cmd_t* cmd)
178 195
 {
179 196
 	db_fld_t* fld;
... ...
@@ -193,10 +210,10 @@ static int build_select_query(str* query, db_cmd_t* cmd)
193 210
 	query->len += strings[STR_FROM].len;
194 211
 	query->len += cmd->table.len;
195 212
 
196
-	if (!DB_FLD_EMPTY(cmd->params)) {
213
+	if (!DB_FLD_EMPTY(cmd->match)) {
197 214
 		query->len += strings[STR_WHERE].len;
198 215
 
199
-		for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
216
+		for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
200 217
 			query->len += strlen(fld[i].name);
201 218
 
202 219
 			switch(fld[i].op) {
... ...
@@ -235,10 +252,10 @@ static int build_select_query(str* query, db_cmd_t* cmd)
235 252
 	APPEND_STR(p, strings[STR_FROM]);
236 253
 	APPEND_STR(p, cmd->table);
237 254
 
238
-	if (!DB_FLD_EMPTY(cmd->params)) {
255
+	if (!DB_FLD_EMPTY(cmd->match)) {
239 256
 		APPEND_STR(p, strings[STR_WHERE]);
240 257
 
241
-		for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
258
+		for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
242 259
 			APPEND_CSTR(p, fld[i].name);
243 260
 
244 261
 			switch(fld[i].op) {
... ...
@@ -259,6 +276,11 @@ static int build_select_query(str* query, db_cmd_t* cmd)
259 276
 }
260 277
 
261 278
 
279
+/**
280
+ *  Builds REPLACE statement where cmd->values specify column names.
281
+ * @param query  SQL statement as a result of this function
282
+ * @param cmd    input for statement creation
283
+ */
262 284
 static int build_replace_query(str* query, db_cmd_t* cmd)
263 285
 {
264 286
 	db_fld_t* fld;
... ...
@@ -269,7 +291,7 @@ static int build_replace_query(str* query, db_cmd_t* cmd)
269 291
 	query->len += cmd->table.len;
270 292
 	query->len += 2; /* " (" */
271 293
 
272
-	for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
294
+	for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {
273 295
 		query->len += strlen(fld[i].name);
274 296
 		query->len += strings[STR_ESC].len;
275 297
 		if (!DB_FLD_LAST(fld[i + 1])) query->len += 2; /* , twice */
... ...
@@ -289,13 +311,13 @@ static int build_replace_query(str* query, db_cmd_t* cmd)
289 311
 	*p++ = ' ';
290 312
 	*p++ = '(';
291 313
 
292
-	for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
314
+	for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {
293 315
 		APPEND_CSTR(p, fld[i].name);
294 316
 		if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
295 317
 	}
296 318
 	APPEND_STR(p, strings[STR_VALUES]);
297 319
 
298
-	for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
320
+	for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {
299 321
 		APPEND_STR(p, strings[STR_ESC]);
300 322
 		if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
301 323
 	}
... ...
@@ -304,6 +326,117 @@ static int build_replace_query(str* query, db_cmd_t* cmd)
304 326
 	return 0;
305 327
 }
306 328
 
329
+/**
330
+ *  Reallocatable string buffer.
331
+ */
332
+struct string_buffer {
333
+	char *s;			/**< allocated memory itself */
334
+	int   len;			/**< used memory */
335
+	int   size;			/**< total size of allocated memory */
336
+	int   increment;	/**< increment when realloc is necessary */ 
337
+};
338
+/**
339
+ *  Add new string into string buffer.
340
+ * @param sb    string buffer
341
+ * @param nstr  string to add
342
+ * @return      0 if OK, -1 if failed
343
+ */
344
+static inline int sb_add(struct string_buffer *sb, str *nstr)
345
+{
346
+	int new_size = 0;
347
+	int rsize = sb->len + nstr->len;
348
+	int asize;
349
+	char *newp;
350
+	
351
+	if ( rsize > sb->size ) {
352
+		asize = rsize - sb->size;
353
+		new_size = sb->size + (asize / sb->increment  + (asize % sb->increment > 0)) * sb->increment;
354
+		newp = pkg_malloc(new_size);
355
+		if (!newp) {
356
+			ERR("not enough memory\n");
357
+			return -1;
358
+		}
359
+		memcpy(newp, sb->s, sb->len);
360
+		pkg_free(sb->s);
361
+		sb->s = newp;
362
+		sb->size = new_size;
363
+	}
364
+	memcpy(sb->s + sb->len, nstr->s, nstr->len);
365
+	sb->len += nstr->len;
366
+	return 0;
367
+}
368
+/**
369
+ *  Set members of str variable.
370
+ *  Used for temporary str variables. 
371
+ */
372
+static inline str* set_str(str *str, const char *s)
373
+{
374
+	str->s = (char *)s;
375
+	str->len = strlen(s);
376
+	return str;
377
+}
378
+
379
+
380
+/**
381
+ *  Builds UPDATE statement where cmd->valss specify column name-value pairs
382
+ *  and cmd->match specify WHERE clause.
383
+ * @param query  SQL statement as a result of this function
384
+ * @param cmd    input for statement creation
385
+ */
386
+static int build_update_query(str* query, db_cmd_t* cmd)
387
+{
388
+	struct string_buffer sql_buf = {.s = NULL, .len = 0, .size = 0, .increment = 128};
389
+	db_fld_t* fld;
390
+	int i;
391
+	int rv = 0;
392
+	str tmpstr;
393
+
394
+	rv = sb_add(&sql_buf, &strings[STR_UPDATE]);	/* "UPDATE " */
395
+	rv |= sb_add(&sql_buf, &cmd->table);			/* table name */
396
+	rv |= sb_add(&sql_buf, &strings[STR_SET]);		/* " SET " */
397
+
398
+	/* column name-value pairs */
399
+	for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {
400
+		rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
401
+		rv |= sb_add(&sql_buf, set_str(&tmpstr, " = "));
402
+		rv |= sb_add(&sql_buf, &strings[STR_ESC]);
403
+		if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, set_str(&tmpstr, ", "));
404
+	}
405
+	if (rv) {
406
+		goto err;
407
+	}
408
+
409
+	if (!DB_FLD_EMPTY(cmd->match)) {
410
+		rv |= sb_add(&sql_buf, &strings[STR_WHERE]);
411
+
412
+		for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
413
+			rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
414
+
415
+			switch(fld[i].op) {
416
+			case DB_EQ:  rv |= sb_add(&sql_buf, &strings[STR_OP_EQ]);  break;
417
+			case DB_LT:  rv |= sb_add(&sql_buf, &strings[STR_OP_LT]);  break;
418
+			case DB_GT:  rv |= sb_add(&sql_buf, &strings[STR_OP_GT]);  break;
419
+			case DB_LEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_LEQ]); break;
420
+			case DB_GEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_GEQ]); break;
421
+			}
422
+			
423
+			rv |= sb_add(&sql_buf, &strings[STR_ESC]);
424
+			if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, &strings[STR_AND]);
425
+		}
426
+	}
427
+	rv |= sb_add(&sql_buf, set_str(&tmpstr, "\0"));
428
+	if (rv) {
429
+		goto err;
430
+	}
431
+	query->s = sql_buf.s;
432
+
433
+	return 0;
434
+
435
+err:
436
+	if (sql_buf.s) pkg_free(sql_buf.s);
437
+	return -1;
438
+}
439
+
307 440
 
308 441
 static inline int update_params(MYSQL_STMT* st, db_fld_t* params)
309 442
 {
... ...
@@ -437,13 +570,17 @@ static inline int update_result(db_fld_t* result, MYSQL_STMT* st)
437 570
 	return 0;
438 571
 }
439 572
 
440
-
573
+/**
574
+ *  DB_DEL uses cmd->match
575
+ *  DB_PUT uses cmd->vals
576
+ */
441 577
 int my_cmd_write(db_res_t* res, db_cmd_t* cmd)
442 578
 {
443 579
 	struct my_cmd* mcmd;
444 580
 
445 581
 	mcmd = DB_GET_PAYLOAD(cmd);
446
-	if (mcmd->st->param_count && update_params(mcmd->st, cmd->params) < 0) return -1;
582
+	if (cmd->type == DB_DEL && mcmd->st->param_count && update_params(mcmd->st, cmd->match) < 0) return -1;
583
+	if (cmd->type == DB_PUT && mcmd->st->param_count && update_params(mcmd->st, cmd->vals) < 0) return -1;
447 584
 	if (mysql_stmt_execute(mcmd->st)) {
448 585
 		ERR("Error while executing query: %s\n", mysql_stmt_error(mcmd->st));
449 586
 		return -1;
... ...
@@ -457,7 +594,22 @@ int my_cmd_read(db_res_t* res, db_cmd_t* cmd)
457 594
 	struct my_cmd* mcmd;
458 595
    
459 596
 	mcmd = DB_GET_PAYLOAD(cmd);
460
-	if (mcmd->st->param_count && update_params(mcmd->st, cmd->params) < 0) return -1;
597
+	if (mcmd->st->param_count && update_params(mcmd->st, cmd->match) < 0) return -1;
598
+	if (mysql_stmt_execute(mcmd->st)) {
599
+		ERR("Error while executing query: %s\n", mysql_stmt_error(mcmd->st));
600
+		return -1;
601
+	}
602
+	return 0;
603
+}
604
+
605
+
606
+int my_cmd_update(db_res_t* res, db_cmd_t* cmd)
607
+{
608
+	struct my_cmd* mcmd;
609
+
610
+	mcmd = DB_GET_PAYLOAD(cmd);
611
+	if (mcmd->st->param_count && update_params(mcmd->st, cmd->match) < 0) return -1;
612
+	if (mcmd->st->param_count && update_params(mcmd->st, cmd->vals) < 0) return -1;
461 613
 	if (mysql_stmt_execute(mcmd->st)) {
462 614
 		ERR("Error while executing query: %s\n", mysql_stmt_error(mcmd->st));
463 615
 		return -1;
... ...
@@ -478,71 +630,87 @@ int my_cmd_sql(db_res_t* res, db_cmd_t* cmd)
478 630
 	return 0;
479 631
 }
480 632
 
481
-
482
-static int bind_params(MYSQL_STMT* st, db_fld_t* fld)
633
+static void set_field(MYSQL_BIND *bind, db_fld_t* fld )
483 634
 {
484
-	int i, n;
485 635
 	struct my_fld* f;
486
-	MYSQL_BIND* params;
636
+	
637
+	f = DB_GET_PAYLOAD(fld);
638
+	bind->is_null = &f->is_null;
639
+	/* We can do it for all the types here, mysql will ignore it
640
+	 * for fixed-size types such as MYSQL_TYPE_LONG
641
+	 */
642
+	bind->length = &f->length;
643
+	switch(fld->type) {
644
+	case DB_INT:
645
+	case DB_BITMAP:
646
+		bind->buffer_type = MYSQL_TYPE_LONG;
647
+		bind->buffer = &fld->v.int4;
648
+		break;
649
+	
650
+	case DB_FLOAT:
651
+		bind->buffer_type = MYSQL_TYPE_FLOAT;
652
+		bind->buffer = &fld->v.flt;
653
+		break;
654
+		
655
+	case DB_DOUBLE:
656
+		bind->buffer_type = MYSQL_TYPE_DOUBLE;
657
+		bind->buffer = &fld->v.dbl;
658
+		break;
659
+	
660
+	case DB_DATETIME:
661
+		bind->buffer_type = MYSQL_TYPE_DATETIME;
662
+		bind->buffer = &f->time;
663
+		break;
664
+	
665
+	case DB_STR:
666
+	case DB_CSTR:
667
+		bind->buffer_type = MYSQL_TYPE_VAR_STRING;
668
+		bind->buffer = ""; /* Updated on runtime */
669
+		break;
670
+	
671
+	case DB_BLOB:
672
+		bind->buffer_type = MYSQL_TYPE_BLOB;
673
+		bind->buffer = ""; /* Updated on runtime */
674
+		break;
675
+	
676
+	case DB_NONE:
677
+		/* Eliminates gcc warning */
678
+		break;
679
+	
680
+	}
681
+}
682
+
683
+/**
684
+ *  Bind params, values first and match after them.
685
+ */
686
+static int bind_params(MYSQL_STMT* st, db_fld_t* fld_value, db_fld_t* fld_match)
687
+{
688
+	int my_idx, fld_idx;
689
+	int value_count, match_count;
690
+	MYSQL_BIND* my_params;
487 691
 
488 692
 	/* Calculate the number of parameters */
489
-	for(n = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[n]); n++);
693
+	for(value_count = 0; !DB_FLD_EMPTY(fld_value) && !DB_FLD_LAST(fld_value[value_count]); value_count++);
694
+	for(match_count = 0; !DB_FLD_EMPTY(fld_match) && !DB_FLD_LAST(fld_match[match_count]); match_count++);
490 695
 
491
-	params = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * n);
492
-	if (params == NULL) {
696
+	my_params = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * (value_count+match_count));
697
+	if (my_params == NULL) {
493 698
 		ERR("No memory left\n");
494 699
 		return -1;
495 700
 	}
496
-	memset(params, '\0', sizeof(MYSQL_BIND) * n);
497
-	
498
-	for(i = 0; i < n; i++) {
499
-		f = DB_GET_PAYLOAD(fld + i);
500
-		params[i].is_null = &f->is_null;
501
-		/* We can do it for all the types here, mysql will ignore it
502
-		 * for fixed-size types such as MYSQL_TYPE_LONG
503
-		 */
504
-		params[i].length = &f->length;
505
-		switch(fld[i].type) {
506
-		case DB_INT:
507
-		case DB_BITMAP:
508
-			params[i].buffer_type = MYSQL_TYPE_LONG;
509
-			params[i].buffer = &fld[i].v.int4;
510
-			break;
511
-
512
-		case DB_FLOAT:
513
-			params[i].buffer_type = MYSQL_TYPE_FLOAT;
514
-			params[i].buffer = &fld[i].v.flt;
515
-			break;
516
-			
517
-		case DB_DOUBLE:
518
-			params[i].buffer_type = MYSQL_TYPE_DOUBLE;
519
-			params[i].buffer = &fld[i].v.dbl;
520
-			break;
521
-
522
-		case DB_DATETIME:
523
-			params[i].buffer_type = MYSQL_TYPE_DATETIME;
524
-			params[i].buffer = &f->time;
525
-			break;
701
+	memset(my_params, '\0', sizeof(MYSQL_BIND) * (value_count+match_count));
526 702
 
527
-		case DB_STR:
528
-		case DB_CSTR:
529
-			params[i].buffer_type = MYSQL_TYPE_VAR_STRING;
530
-			params[i].buffer = ""; /* Updated on runtime */
531
-			break;
532
-
533
-		case DB_BLOB:
534
-			params[i].buffer_type = MYSQL_TYPE_BLOB;
535
-			params[i].buffer = ""; /* Updated on runtime */
536
-			break;
537
-
538
-		case DB_NONE:
539
-			/* Eliminates gcc warning */
540
-			break;
541
-
542
-		}
703
+	/* values */
704
+	my_idx = 0;
705
+	for (fld_idx = 0; fld_idx < value_count; fld_idx++, my_idx++) {
706
+		set_field(&my_params[my_idx], fld_value + fld_idx);
543 707
 	}
544
-
545
-	if (mysql_stmt_bind_param(st, params)) {
708
+	/* match */
709
+	for (fld_idx = 0; fld_idx < match_count; fld_idx++, my_idx++) {
710
+		set_field(&my_params[my_idx], fld_match + fld_idx);
711
+	}
712
+	
713
+	if (mysql_stmt_bind_param(st, my_params)) {
546 714
 		ERR("Error while binding parameters: %s\n", mysql_stmt_error(st));
547 715
 		goto error;
548 716
 	}
... ...
@@ -550,28 +718,31 @@ static int bind_params(MYSQL_STMT* st, db_fld_t* fld)
550 718
 	/* We do not need the array of MYSQL_BIND anymore, mysql_stmt_bind_param
551 719
 	 * creates a copy in the statement and we will update it there
552 720
 	 */
553
-	pkg_free(params);
721
+	pkg_free(my_params);
554 722
 	return 0;
555 723
    
556 724
  error:
557
-	if (params) pkg_free(params);
725
+	if (my_params) pkg_free(my_params);
558 726
 	return -1;
559 727
 }
560 728
 
729
+#include <stdlib.h>
561 730
 /* FIXME: Add support for DB_NONE, in this case the function should determine
562 731
  * the type of the column in the database and set the field type appropriately
563 732
  */
564
-
565 733
 static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
566 734
 {
567 735
 	int i, n;
568 736
 	struct my_fld* f;
569 737
 	MYSQL_BIND* result;
570 738
 
739
+INFO("bind_result(st = %p, fld = %p)\n", st, fld);
740
+INFO("bind_result: field count: %d\n", st->field_count);
571 741
 	/* Calculate the number of fields in the result */
572 742
 	for(n = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[n]); n++);
573
-
743
+INFO("bind_result: n = %d\n", n);
574 744
 	result = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * n);
745
+INFO("bind_result: result = %p\n", result);
575 746
 	if (result == NULL) {
576 747
 		ERR("No memory left\n");
577 748
 		return -1;
... ...
@@ -579,6 +750,8 @@ static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
579 750
 	memset(result, '\0', sizeof(MYSQL_BIND) * n);
580 751
 	
581 752
 	for(i = 0; i < n; i++) {
753
+INFO("bind_result: i = %d\n", i);
754
+INFO("bind_result: fld[%d].type = %d\n", i, fld[i].type);
582 755
 		f = DB_GET_PAYLOAD(fld + i);
583 756
 		result[i].is_null = &f->is_null;
584 757
 		/* We can do it for all the types here, mysql will ignore it
... ...
@@ -649,7 +822,7 @@ static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
649 822
 
650 823
 		}
651 824
 	}
652
-
825
+INFO("bind_result: result = %p\n", result);
653 826
 	if (mysql_stmt_bind_result(st, result)) {
654 827
 		ERR("Error while binding result: %s\n", mysql_stmt_error(st));
655 828
 		goto error;
... ...
@@ -662,6 +835,7 @@ static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
662 835
 	return 0;
663 836
    
664 837
  error:
838
+ 	abort();
665 839
 	if (result) pkg_free(result);
666 840
 	return -1;
667 841
 }
... ...
@@ -672,6 +846,7 @@ int my_cmd(db_cmd_t* cmd)
672 846
 	struct my_cmd* res;
673 847
 	struct my_con* mcon;
674 848
 
849
+INFO("my_cmd(cmd = %p, res = %p, match = %p, vals = %p)\n", cmd, cmd->result, cmd->match, cmd->vals);
675 850
 	res = (struct my_cmd*)pkg_malloc(sizeof(struct my_cmd));
676 851
 	if (res == NULL) {
677 852
 		ERR("No memory left\n");
... ...
@@ -690,48 +865,77 @@ int my_cmd(db_cmd_t* cmd)
690 865
 
691 866
 	switch(cmd->type) {
692 867
 	case DB_PUT:
693
-		if (DB_FLD_EMPTY(cmd->params)) {
868
+		if (DB_FLD_EMPTY(cmd->vals)) {
694 869
 			ERR("BUG: No parameters provided for DB_PUT in context '%.*s'\n", 
695 870
 				cmd->ctx->id.len, ZSW(cmd->ctx->id.s));
696 871
 			goto error;
697 872
 		}
698 873
 		if (build_replace_query(&res->query, cmd) < 0) goto error;
874
+		INFO("build_replace_query: query = '%.*s'\n", res->query.len, res->query.s);
699 875
 		if (mysql_stmt_prepare(res->st, res->query.s, res->query.len)) {
700 876
 			ERR("Error while preparing replace query: %s\n", 
701 877
 				mysql_stmt_error(res->st));
702 878
 			goto error;
703 879
 		}
704
-		if (bind_params(res->st, cmd->params) < 0) goto error;
880
+		if (bind_params(res->st, cmd->vals, NULL) < 0) goto error;
705 881
 		break;
706 882
 
707 883
 	case DB_DEL:
708 884
 		if (build_delete_query(&res->query, cmd) < 0) goto error;
885
+		INFO("build_delete_query: query = '%.*s'\n", res->query.len, res->query.s);
709 886
 		if (mysql_stmt_prepare(res->st, res->query.s, res->query.len)) {
710 887
 			ERR("Error while preparing delete query: %s\n",
711 888
 				mysql_stmt_error(res->st));
712 889
 				goto error;
713 890
 		}
714
-		if (!DB_FLD_EMPTY(cmd->params)) {
715
-			if (bind_params(res->st, cmd->params) < 0) goto error;
891
+		if (!DB_FLD_EMPTY(cmd->match)) {
892
+			if (bind_params(res->st, NULL, cmd->match) < 0) goto error;
716 893
 		}
717 894
 		break;
718 895
 
719 896
 	case DB_GET:
720 897
 		if (build_select_query(&res->query, cmd) < 0) goto error;
898
+		INFO("build_select_query: query = '%.*s'\n", res->query.len, res->query.s);
721 899
 		if (mysql_stmt_prepare(res->st, res->query.s, res->query.len)) {
722 900
 			ERR("Error while preparing select query: %s\n",
723 901
 				mysql_stmt_error(res->st));
724 902
 			goto error;
725 903
 		}
726
-		if (!DB_FLD_EMPTY(cmd->params)) {
727
-			if (bind_params(res->st, cmd->params) < 0) goto error;
904
+		if (!DB_FLD_EMPTY(cmd->match)) {
905
+			if (bind_params(res->st, NULL, cmd->match) < 0) goto error;
906
+		}
907
+		if (bind_result(res->st, cmd->result) < 0) {
908
+			ERR("mysql: DB_GET bind_result() failed\n");
909
+			goto error;
910
+		}
911
+		break;
912
+
913
+	case DB_UPD:
914
+		if (build_update_query(&res->query, cmd) < 0) goto error;
915
+		INFO("build_update_query: query = '%.*s'\n", res->query.len, res->query.s);
916
+		if (mysql_stmt_prepare(res->st, res->query.s, res->query.len)) {
917
+			ERR("mysql: Error while preparing UPDATE query: %s\n",
918
+				mysql_stmt_error(res->st));
919
+			goto error;
920
+		}
921
+		/* FIXME: remove ELSE */
922
+		if (!DB_FLD_EMPTY(cmd->vals)) {
923
+			if (bind_params(res->st, cmd->vals, cmd->match) < 0) {
924
+				ERR("mysql: DB_UPD bind_params() failed\n");
925
+				goto error;
926
+			}
927
+		}
928
+		else {
929
+			if (bind_params(res->st, NULL, cmd->match) < 0) {
930
+				ERR("mysql: DB_UPD bind_params() failed\n");
931
+				goto error;
932
+			}
728 933
 		}
729
-		if (bind_result(res->st, cmd->result) < 0) goto error;
730 934
 		break;
731 935
 
732 936
 	case DB_SQL:
733 937
 		if (mysql_stmt_prepare(res->st, cmd->table.s, cmd->table.len)) {
734
-			ERR("Error while preparing raw SQL query: %s\n",
938
+			ERR("mysql: Error while preparing raw SQL query: %s\n",
735 939
 				mysql_stmt_error(res->st));
736 940
 			goto error;
737 941
 		}
... ...
@@ -751,6 +955,7 @@ int my_cmd(db_cmd_t* cmd)
751 955
 		if (res->st) mysql_stmt_close(res->st);
752 956
 		pkg_free(res);
753 957
 	}
958
+	ERR("mysql: my_cmd() failed\n");
754 959
 	return -1;
755 960
 }
756 961
 
... ...
@@ -779,3 +984,4 @@ int my_cmd_next(db_res_t* res)
779 984
 	return 0;
780 985
 }
781 986
 
987
+/** @} */
... ...
@@ -48,6 +48,9 @@ int my_cmd_read(db_res_t* res, db_cmd_t* cmd);
48 48
 /* Runtime execution function for DB_PUT and DB_DEL */
49 49
 int my_cmd_write(db_res_t* res, db_cmd_t* cmd);
50 50
 
51
+/* Runtime execution function for DB_UPD */
52
+int my_cmd_update(db_res_t* res, db_cmd_t* cmd);
53
+
51 54
 /* Raw SQL query */
52 55
 int my_cmd_sql(db_res_t* res, db_cmd_t* cmd);
53 56
 
... ...
@@ -69,6 +69,7 @@ static cmd_export_t cmds[] = {
69 69
 	{"db_put",         (cmd_function)my_cmd_write, 0, 0, 0},
70 70
 	{"db_del",         (cmd_function)my_cmd_write, 0, 0, 0},
71 71
 	{"db_get",         (cmd_function)my_cmd_read, 0, 0, 0},
72
+	{"db_upd",         (cmd_function)my_cmd_update, 0, 0, 0},
72 73
 	{"db_sql",         (cmd_function)my_cmd_sql, 0, 0, 0},
73 74
 	{"db_res",         (cmd_function)my_res,  0, 0, 0},
74 75
 	{"db_fld",         (cmd_function)my_fld,  0, 0, 0},
... ...
@@ -153,13 +153,13 @@ struct module_exports exports = {
153 153
  */
154 154
 static int child_init(int rank)
155 155
 {
156
-	db_fld_t res[] = {
156
+	db_fld_t lookup_uid_columns[] = {
157 157
 		{.name = uid_col.s,   DB_STR},
158 158
 		{.name = flags_col.s, DB_BITMAP},
159 159
 		{.name = NULL}
160 160
 	};
161 161
 
162
-	db_fld_t params[] = {
162
+	db_fld_t lookup_uid_match[] = {
163 163
 		{.name = username_col.s, DB_STR},
164 164
 		{.name = did_col.s,      DB_STR},
165 165
 		{.name = scheme_col.s,   DB_STR},
... ...
@@ -177,7 +177,7 @@ static int child_init(int rank)
177 177
 	if (db_add_db(db, db_url.s) < 0) goto error;
178 178
 	if (db_connect(db) < 0) goto error;
179 179
 	
180
-	lookup_uid_cmd = db_cmd(DB_GET, db, uri_table.s, res, params);
180
+	lookup_uid_cmd = db_cmd(DB_GET, db, uri_table.s, lookup_uid_columns, lookup_uid_match, NULL);
181 181
 	if (lookup_uid_cmd == NULL) {
182 182
 		ERR("Error while building db query to load global attributes\n");
183 183
 		goto error;
... ...
@@ -233,8 +233,8 @@ static int lookup_uid(struct sip_msg* msg, long id, int store)
233 233
 			LOG(L_ERR, "uri_db:lookup_uid: Error while parsing From URI\n");
234 234
 			return -1;
235 235
 		}
236
-		lookup_uid_cmd->params[0].v.lstr = puri.user;
237
-		uri_type_to_str(puri.type, &(lookup_uid_cmd->params[2].v.lstr));
236
+		lookup_uid_cmd->match[0].v.lstr = puri.user;
237
+		uri_type_to_str(puri.type, &(lookup_uid_cmd->match[2].v.lstr));
238 238
 	} else if (id == USE_TO) {
239 239
 		get_to_did(&did, msg);
240 240
 		if (!msg->to) {
... ...
@@ -252,23 +252,23 @@ static int lookup_uid(struct sip_msg* msg, long id, int store)
252 252
 			LOG(L_ERR, "uri_db:lookup_uid: Error while parsing To URI\n");
253 253
 			return -1;
254 254
 		}
255
-		lookup_uid_cmd->params[0].v.lstr = puri.user;
256
-		uri_type_to_str(puri.type, &(lookup_uid_cmd->params[2].v.lstr));
255
+		lookup_uid_cmd->match[0].v.lstr = puri.user;
256
+		uri_type_to_str(puri.type, &(lookup_uid_cmd->match[2].v.lstr));
257 257
 		flag = DB_IS_TO;
258 258
 	} else {
259 259
 		get_to_did(&did, msg);
260 260
 		flag = DB_IS_TO;
261 261
 
262 262
 		if (parse_sip_msg_uri(msg) < 0) return -1;
263
-		lookup_uid_cmd->params[0].v.lstr = msg->parsed_uri.user;
264
-		uri_type_to_str(msg->parsed_uri.type, &(lookup_uid_cmd->params[2].v.lstr));
263
+		lookup_uid_cmd->match[0].v.lstr = msg->parsed_uri.user;
264
+		uri_type_to_str(msg->parsed_uri.type, &(lookup_uid_cmd->match[2].v.lstr));
265 265
 	}
266 266
 
267 267
 	if (did.s && did.len) {
268
-		lookup_uid_cmd->params[1].v.lstr = did;
268
+		lookup_uid_cmd->match[1].v.lstr = did;
269 269
 	} else {
270 270
 		LOG(L_DBG, "uri_db:lookup_uid: DID not found, using default value\n");
271
-		lookup_uid_cmd->params[1].v.lstr = default_did;
271
+		lookup_uid_cmd->match[1].v.lstr = default_did;
272 272
 	}
273 273
 
274 274
 	if (db_exec(&res, lookup_uid_cmd) < 0) {
... ...
@@ -378,9 +378,9 @@ static int lookup_user_2(struct sip_msg* msg, char* attr, char* select)
378 378
 		did = default_did;
379 379
     }
380 380
 
381
-	lookup_uid_cmd->params[0].v.lstr = puri.user;
382
-    lookup_uid_cmd->params[1].v.lstr = did;
383
-    uri_type_to_str(puri.type, &(lookup_uid_cmd->params[2].v.lstr));
381
+	lookup_uid_cmd->match[0].v.lstr = puri.user;
382
+    lookup_uid_cmd->match[1].v.lstr = did;
383
+    uri_type_to_str(puri.type, &(lookup_uid_cmd->match[2].v.lstr));
384 384
 
385 385
     if (db_exec(&res, lookup_uid_cmd) < 0) {
386 386
 		LOG(L_ERR, "lookup_user: Error in db_query\n");
... ...
@@ -501,41 +501,41 @@ int db_store_ucontact(ucontact_t* _c)
501 501
 
502 502
 	avps.s = NULL;
503 503
 
504
-	ins_contact[cur_cmd]->params[0].v.lstr = *_c->uid;
505
-	ins_contact[cur_cmd]->params[1].v.lstr.s = _c->c.s;
506
-	ins_contact[cur_cmd]->params[1].v.lstr.len = MIN(_c->c.len, 255);
507
-	ins_contact[cur_cmd]->params[2].v.time = _c->expires;
508
-	ins_contact[cur_cmd]->params[3].v.flt = (float)q2double(_c->q);
509
-	ins_contact[cur_cmd]->params[4].v.lstr.s = _c->callid.s;
510
-	ins_contact[cur_cmd]->params[4].v.lstr.len = MIN(_c->callid.len, 255);
511
-	ins_contact[cur_cmd]->params[5].v.int4 = _c->cseq;
512
-	ins_contact[cur_cmd]->params[6].v.bitmap = _c->flags;
513
-	ins_contact[cur_cmd]->params[7].v.lstr.s = _c->user_agent.s;
514
-	ins_contact[cur_cmd]->params[7].v.lstr.len = MIN(_c->user_agent.len, 64);
504
+	ins_contact[cur_cmd]->vals[0].v.lstr = *_c->uid;
505
+	ins_contact[cur_cmd]->vals[1].v.lstr.s = _c->c.s;
506
+	ins_contact[cur_cmd]->vals[1].v.lstr.len = MIN(_c->c.len, 255);
507
+	ins_contact[cur_cmd]->vals[2].v.time = _c->expires;
508
+	ins_contact[cur_cmd]->vals[3].v.flt = (float)q2double(_c->q);
509
+	ins_contact[cur_cmd]->vals[4].v.lstr.s = _c->callid.s;
510
+	ins_contact[cur_cmd]->vals[4].v.lstr.len = MIN(_c->callid.len, 255);
511
+	ins_contact[cur_cmd]->vals[5].v.int4 = _c->cseq;
512
+	ins_contact[cur_cmd]->vals[6].v.bitmap = _c->flags;
513
+	ins_contact[cur_cmd]->vals[7].v.lstr.s = _c->user_agent.s;
514
+	ins_contact[cur_cmd]->vals[7].v.lstr.len = MIN(_c->user_agent.len, 64);
515 515
 
516 516
 	if (_c->received.s == 0) {
517
-		ins_contact[cur_cmd]->params[8].flags |= DB_NULL;
517
+		ins_contact[cur_cmd]->vals[8].flags |= DB_NULL;
518 518
 	} else {
519
-		ins_contact[cur_cmd]->params[8].flags &= ~DB_NULL;
520
-		ins_contact[cur_cmd]->params[8].v.lstr = _c->received;
519
+		ins_contact[cur_cmd]->vals[8].flags &= ~DB_NULL;
520
+		ins_contact[cur_cmd]->vals[8].v.lstr = _c->received;
521 521
 	}
522 522
 
523 523
 	if (_c->instance.s == 0) {
524
-		ins_contact[cur_cmd]->params[9].flags |= DB_NULL;
524
+		ins_contact[cur_cmd]->vals[9].flags |= DB_NULL;
525 525
 	} else {
526
-		ins_contact[cur_cmd]->params[9].flags &= ~DB_NULL;
527
-		ins_contact[cur_cmd]->params[9].v.lstr = _c->instance;
526
+		ins_contact[cur_cmd]->vals[9].flags &= ~DB_NULL;
527
+		ins_contact[cur_cmd]->vals[9].v.lstr = _c->instance;
528 528
 	}
529 529
 
530
-	ins_contact[cur_cmd]->params[10].v.lstr.s = _c->aor.s;
531
-	ins_contact[cur_cmd]->params[10].v.lstr.len = MIN(_c->aor.len, 255);
530
+	ins_contact[cur_cmd]->vals[10].v.lstr.s = _c->aor.s;
531
+	ins_contact[cur_cmd]->vals[10].v.lstr.len = MIN(_c->aor.len, 255);
532 532
 
533 533
 	if (use_reg_avps()) {
534 534
 		if (serialize_avps(_c->avps, &avps) < 0) {
535 535
 			ERR("Error while serializing AVPs\n");
536 536
 			return -1;
537 537
 		}
538
-		ins_contact[cur_cmd]->params[11].v.lstr = avps;
538
+		ins_contact[cur_cmd]->vals[11].v.lstr = avps;
539 539
 	}
540 540
 
541 541
 	     /* FIXME */
... ...
@@ -559,8 +559,8 @@ int db_delete_ucontact(ucontact_t* _c)
559 559
 		return 0;
560 560
 	}
561 561
 
562
-	del_contact[cur_cmd]->params[0].v.lstr = *_c->uid;
563
-	del_contact[cur_cmd]->params[1].v.lstr = _c->c;
562
+	del_contact[cur_cmd]->match[0].v.lstr = *_c->uid;
563
+	del_contact[cur_cmd]->match[1].v.lstr = _c->c;
564 564
 
565 565
 	if (db_exec(NULL, del_contact[cur_cmd]) < 0) {
566 566
 		ERR("Error while deleting contact from database\n");
... ...
@@ -309,7 +309,7 @@ int preload_udomain(udomain_t* _d)
309 309
 	urecord_t* r;
310 310
 	ucontact_t* c;
311 311
 
312
-	get_all = db_cmd(DB_GET, db, _d->name->s, columns, NULL);
312
+	get_all = db_cmd(DB_GET, db, _d->name->s, columns, NULL, NULL);
313 313
 	if (get_all == NULL) {
314 314
 		ERR("Error while compiling DB_GET command\n");
315 315
 		return -1;
... ...
@@ -203,13 +203,14 @@ static int mod_init(void)
203 203
 
204 204
 static int build_db_cmds(void)
205 205
 {
206
-	db_fld_t del_contact_params[] = {
206
+	INFO("usrloc: build_db_cmds()\n");
207
+	db_fld_t del_contact_match[] = {
207 208
 		{.name = uid_col.s, .type = DB_STR},
208 209
 		{.name = contact_col.s, .type = DB_STR},
209 210
 		{.name = NULL},
210 211
 	};
211 212
 	
212
-	db_fld_t ins_contact_params[] = {
213
+	db_fld_t ins_contact_values[] = {
213 214
 		{.name = uid_col.s,        .type = DB_STR},
214 215
 		{.name = contact_col.s,    .type = DB_STR},
215 216
 		{.name = expires_col.s,    .type = DB_DATETIME},
... ...
@@ -244,13 +245,15 @@ static int build_db_cmds(void)
244 245
 	}
245 246
 	memset(ins_contact, '\0', sizeof(ins_contact) * cmd_n);
246 247
 
248
+	INFO("usrloc: building del_contact queries()\n");
247 249
 	for(i = 0, ptr = root; ptr; ptr = ptr->next, i++) {
248
-		del_contact[i] = db_cmd(DB_DEL, db, ptr->name.s, NULL, del_contact_params);
250
+		del_contact[i] = db_cmd(DB_DEL, db, ptr->name.s, NULL, del_contact_match, NULL);
249 251
 		if (del_contact[i] == NULL) return -1;
250 252
 	}
251 253
 
254
+	INFO("usrloc: building inst_contact queries()\n");
252 255
 	for(i = 0, ptr = root; ptr; ptr = ptr->next, i++) {
253
-		ins_contact[i] = db_cmd(DB_PUT, db, ptr->name.s, NULL, ins_contact_params);
256
+		ins_contact[i] = db_cmd(DB_PUT, db, ptr->name.s, NULL, NULL, ins_contact_values);
254 257
 		if (ins_contact[i] == NULL) return -1;
255 258
 	}
256 259
 	return 0;
... ...
@@ -260,8 +263,13 @@ static int build_db_cmds(void)
260 263
 
261 264
 static int child_init(int _rank)
262 265
 {
263
-	if (_rank==PROC_INIT || _rank==PROC_MAIN || _rank==PROC_TCP_MAIN)
266
+	INFO("usrloc: child_init( rank: %d)\n", _rank);
267
+	if (_rank==PROC_INIT || _rank==PROC_MAIN || _rank==PROC_TCP_MAIN) {
268
+		INFO("usrloc: do nothing for the init, main or tcp_main processes\n");
264 269
 		return 0; /* do nothing for the main or tcp_main processes */
270
+	}
271
+	
272
+	INFO("usrloc: db_mode = %d\n", db_mode);
265 273
 	     /* Shall we use database ? */
266 274
 	if ( db_mode != NO_DB) { /* Yes */
267 275
 		db = db_ctx("usrloc");
... ...
@@ -274,6 +282,7 @@ static int child_init(int _rank)
274 282
 		if (db_connect(db) < 0) return -1;
275 283
 		if (build_db_cmds() < 0) return -1;
276 284
 	}
285
+	INFO("usrloc: child_init( rank: %d), done OK\n", _rank);
277 286
 
278 287
 	return 0;
279 288
 }