Now also parse new diffs
[handlerosm.git] / handler_osm_put.c
blobec94b9634752ef0a3fc40b8c7f6df029995d8a80
1 #include <cherokee/common-internal.h>
2 #include <cherokee/cherokee.h>
3 #include <Mapi.h>
4 #include <axl.h>
6 #include "handler_osm.h"
7 #include "handler_osm_db.h"
8 #include "handler_osm_put.h"
9 #include "handler_osm_sql.h"
10 #include "handler_osm_delete.h"
12 static ret_t result_node_last_id(cherokee_handler_osm_t *hdl, MapiHdl *hdl1, cherokee_buffer_t *buf) {
13 cherokee_buffer_add_va (buf, "%d", mapi_get_last_id(*hdl1));
14 return ret_ok;
17 static ret_t node_update_or_insert (cherokee_handler_osm_t *hdl, MapiHdl *hdl1, cherokee_buffer_t *buf) {
18 if (mapi_rows_affected(*hdl1) == 0)
19 return ret_error;
21 return ret_ok;
24 static void do_members(cherokee_handler_osm_t *hdl, axlNode *node, unsigned long int relationid, unsigned short int update) {
25 axlNode * member;
26 if ((member = axl_node_get_first_child(node)) != NULL) {
27 cherokee_buffer_t members_node = CHEROKEE_BUF_INIT;
28 cherokee_buffer_t members_way = CHEROKEE_BUF_INIT;
29 cherokee_buffer_t members_relation = CHEROKEE_BUF_INIT;
30 unsigned long int idx = 0;
31 do {
32 if (NODE_CMP_NAME (member, "member") &&
33 axl_node_has_attribute(member, "type") &&
34 axl_node_has_attribute(member, "ref") &&
35 axl_node_has_attribute(member, "role")) {
37 unsigned long int ref = strtod(axl_node_get_attribute_value(member, "ref"), NULL);
38 if (errno != ERANGE && ref > 0) {
39 const char *type = axl_node_get_attribute_value(member, "type");
40 const char *role = axl_node_get_attribute_value(member, "role");
42 if (strcmp(type, "node") == 0) {
43 cherokee_buffer_add_va (&members_node, "%lu, ", ref);
44 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
45 if (update == 1) {
46 cherokee_buffer_add_va (&sql1, "UPDATE relation_members_node SET to_node = %lu, role = '%s' WHERE relation = %lu AND idx = %lu", ref, role, relationid, idx);
48 if (update == 0 || run_sql(hdl, &sql1, NULL, node_update_or_insert) == ret_error) {
49 cherokee_buffer_mrproper(&sql1);
50 cherokee_buffer_add_va (&sql1, "INSERT INTO relation_members_node (relation, idx, to_node, role) VALUES (%lu, %lu, %lu, '%s')", relationid, idx, ref, role);
51 run_sql(hdl, &sql1, NULL, NULL);
53 cherokee_buffer_mrproper(&sql1);
54 } else if (strcmp(type, "way") == 0) {
55 cherokee_buffer_add_va (&members_way, "%lu, ", ref);
56 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
57 if (update == 1) {
58 cherokee_buffer_add_va (&sql1, "UPDATE relation_members_way SET to_way = %lu, role = '%s' WHERE relation = %lu AND idx = %lu", ref, role, relationid, idx);
60 if (update == 0 || run_sql(hdl, &sql1, NULL, node_update_or_insert) == ret_error) {
61 cherokee_buffer_mrproper(&sql1);
62 cherokee_buffer_add_va (&sql1, "INSERT INTO relation_members_way (relation, idx, to_way, role) VALUES (%lu, %lu, %lu, '%s')", relationid, idx, ref, role);
63 run_sql(hdl, &sql1, NULL, NULL);
65 cherokee_buffer_mrproper(&sql1);
66 } else if (strcmp(type, "relation") == 0) {
67 cherokee_buffer_add_va (&members_relation, "%lu, ", ref);
68 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
69 if (update == 1) {
70 cherokee_buffer_add_va (&sql1, "UPDATE relation_members_relation SET to_relation = %lu, role = '%s' WHERE relation = %lu AND idx = %lu", ref, role, relationid, idx);
72 if (update == 0 || run_sql(hdl, &sql1, NULL, node_update_or_insert) == ret_error) {
73 cherokee_buffer_mrproper(&sql1);
74 cherokee_buffer_add_va (&sql1, "INSERT INTO relation_members_relation (relation, idx, to_relation, role) VALUES (%lu, %lu, %lu, '%s')", relationid, idx, ref, role);
75 run_sql(hdl, &sql1, NULL, NULL);
77 cherokee_buffer_mrproper(&sql1);
78 } else {
79 TRACE("osm", "%s: New type?\n", type);
81 idx++;
84 } while ((member = axl_node_get_next(member)) != NULL);
86 if (members_node.len > 0) {
87 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
88 cherokee_buffer_drop_ending(&members_node, 2);
89 cherokee_buffer_add_va (&sql1, "DELETE FROM relation_members_node WHERE relation = %lu AND to_node NOT IN (%s)", relationid, members_node.buf);
90 run_sql(hdl, &sql1, NULL, NULL);
91 cherokee_buffer_mrproper(&sql1);
93 cherokee_buffer_mrproper(&members_node);
95 if (members_way.len > 0) {
96 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
97 cherokee_buffer_drop_ending(&members_way, 2);
98 cherokee_buffer_add_va (&sql1, "DELETE FROM relation_members_way WHERE relation = %lu AND to_way NOT IN (%s)", relationid, members_way.buf);
99 run_sql(hdl, &sql1, NULL, NULL);
100 cherokee_buffer_mrproper(&sql1);
102 cherokee_buffer_mrproper(&members_way);
104 if (members_relation.len > 0) {
105 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
106 cherokee_buffer_drop_ending(&members_relation, 2);
107 cherokee_buffer_add_va (&sql1, "DELETE FROM relation_members_relation WHERE relation = %lu AND to_relation NOT IN (%s)", relationid, members_relation.buf);
108 run_sql(hdl, &sql1, NULL, NULL);
109 cherokee_buffer_mrproper(&sql1);
111 cherokee_buffer_mrproper(&members_relation);
117 static void do_nds(cherokee_handler_osm_t *hdl, axlNode *node, unsigned long int wayid, unsigned short int update) {
118 axlNode * nd;
119 if ((nd = axl_node_get_first_child(node)) != NULL) {
120 cherokee_buffer_t nds = CHEROKEE_BUF_INIT;
121 unsigned long int idx = 0;
122 do {
123 if (NODE_CMP_NAME (nd, "nd") &&
124 axl_node_has_attribute(nd, "ref")) {
126 unsigned long int ref = strtod(axl_node_get_attribute_value(nd, "ref"), NULL);
127 if (errno != ERANGE && ref > 0) {
128 cherokee_buffer_add_va (&nds, "%lu, ", ref);
130 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
131 if (update == 1) {
132 cherokee_buffer_add_va (&sql1, "UPDATE way_nds SET to_node = %lu WHERE way = %lu AND idx = %lu", ref, wayid, idx);
134 if (update == 0 || run_sql(hdl, &sql1, NULL, node_update_or_insert) == ret_error) {
135 cherokee_buffer_mrproper(&sql1);
136 cherokee_buffer_add_va (&sql1, "INSERT INTO way_nds (way, idx, to_node) VALUES (%lu, %lu, %lu)", wayid, idx, ref);
137 run_sql(hdl, &sql1, NULL, NULL);
139 cherokee_buffer_mrproper(&sql1);
140 idx++;
143 } while ((nd = axl_node_get_next(nd)) != NULL);
145 if (nds.len > 0) {
146 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
147 cherokee_buffer_drop_ending(&nds, 2);
148 cherokee_buffer_add_va (&sql1, "DELETE FROM way_nds WHERE relation = %lu AND to_node NOT IN (%s)", wayid, nds.buf);
149 run_sql(hdl, &sql1, NULL, NULL);
150 cherokee_buffer_mrproper(&sql1);
153 cherokee_buffer_mrproper(&nds);
157 static void do_tags(cherokee_handler_osm_t *hdl, axlNode *node, unsigned long int nodeid, unsigned short int update, char *create_sql, char *update_sql, char *delete_sql) {
158 axlNode * tag;
159 if ((tag = axl_node_get_first_child(node)) != NULL) {
160 cherokee_buffer_t keys = CHEROKEE_BUF_INIT;
161 do {
162 if (NODE_CMP_NAME (tag, "tag") &&
163 axl_node_has_attribute(tag, "k") &&
164 axl_node_has_attribute(tag, "v")) {
165 const char * key = axl_node_get_attribute_value(tag, "k");
166 size_t keylen = strlen(key);
168 if (keylen > 0 && keylen < 256) {
169 const char * value = axl_node_get_attribute_value(tag, "v");
170 size_t valuelen = strlen(value);
171 cherokee_buffer_add_va (&keys, "\'%s\', ", key);
173 if (valuelen > 0 && valuelen < 256) {
174 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
175 if (update == 1) {
176 cherokee_buffer_add_va (&sql1, update_sql,
177 value,
178 nodeid,
182 if (update == 0 || run_sql(hdl, &sql1, NULL, node_update_or_insert) == ret_error) {
183 cherokee_buffer_mrproper(&sql1);
184 cherokee_buffer_add_va (&sql1, create_sql,
185 nodeid,
186 key,
187 value);
188 run_sql(hdl, &sql1, NULL, NULL);
190 cherokee_buffer_mrproper(&sql1);
194 } while ((tag = axl_node_get_next(tag)) != NULL);
196 if (keys.len > 0) {
197 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
198 cherokee_buffer_drop_ending(&keys, 2);
199 cherokee_buffer_add_va (&sql1, delete_sql, nodeid, keys.buf);
200 run_sql(hdl, &sql1, NULL, NULL);
201 cherokee_buffer_mrproper(&sql1);
204 cherokee_buffer_mrproper(&keys);
208 static int
209 node_exists(cherokee_handler_osm_t *hdl, osm_state_delete_t type, unsigned long int nodeid) {
210 int result = 0;
211 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
212 cherokee_buffer_t tmp = CHEROKEE_BUF_INIT;
214 switch (type) {
215 case OSM_DELETE_NODE_COMMAND:
216 cherokee_buffer_add_va (&sql1, SQL_NODE_EXIST, nodeid);
217 break;
219 case OSM_DELETE_WAY_COMMAND:
220 cherokee_buffer_add_va (&sql1, SQL_WAY_EXIST, nodeid);
221 break;
223 case OSM_DELETE_RELATION_COMMAND:
224 cherokee_buffer_add_va (&sql1, SQL_RELATION_EXIST, nodeid);
225 break;
227 default:
228 SHOULDNT_HAPPEN;
229 return result;
232 run_sql(hdl, &sql1, &tmp, NULL);
233 if (tmp.len > 0)
234 result = 1;
236 cherokee_buffer_mrproper(&sql1);
237 cherokee_buffer_mrproper(&tmp);
239 return result;
242 static ret_t
243 create_node(cherokee_handler_osm_t *hdl, axlNode * node, osm_state_delete_t type, unsigned long int nodeid, const char *username, short int timestamp) {
244 cherokee_connection_t *conn = HANDLER_CONN(hdl);
245 cherokee_buffer_t *buf = &hdl->buffer;
247 switch (type) {
248 case OSM_DELETE_NODE_COMMAND: {
249 if (axl_node_has_attribute(node, "lat") &&
250 axl_node_has_attribute(node, "lon")) {
251 double lat, lon;
252 lat = strtod(axl_node_get_attribute_value(node, "lat"), NULL);
253 if (errno == ERANGE) {
254 conn->error_code = http_bad_request;
255 return ret_error;
258 lon = strtod(axl_node_get_attribute_value(node, "lon"), NULL);
259 if (errno == ERANGE) {
260 conn->error_code = http_bad_request;
261 return ret_error;
262 } else {
263 /* TODO: more error checking */
264 long testid = 0;
265 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
267 if (nodeid == 0) {
268 if (timestamp == 1 && axl_node_has_attribute(node, "timestamp")) {
269 cherokee_buffer_add_va (&sql1, SQL_NODE_CREATE, lon, lat, username, "'", axl_node_get_attribute_value(node, "timestamp"), "'");
270 } else {
271 cherokee_buffer_add_va (&sql1, SQL_NODE_CREATE, lon, lat, username, SQL_NOW);
273 } else {
274 if (timestamp == 1 && axl_node_has_attribute(node, "timestamp")) {
275 cherokee_buffer_add_va (&sql1, SQL_NODE_CREATE_BY_ID, lon, lat, username, "'", axl_node_get_attribute_value(node, "timestamp"), "'", nodeid);
276 } else {
277 cherokee_buffer_add_va (&sql1, SQL_NODE_CREATE_BY_ID, lon, lat, username, SQL_NOW, nodeid);
280 run_sql(hdl, &sql1, buf, result_node_last_id);
281 cherokee_buffer_mrproper(&sql1);
283 testid = strtol(buf->buf, (char **) NULL, 10);
284 if (errno != ERANGE && testid > 0) {
285 do_tags(hdl, node, testid, 0, SQL_NODE_CREATE_NODE_TAG, SQL_NODE_UPDATE_NODE_TAG, SQL_NODE_DELETE_NODE_TAG);
286 return ret_ok;
287 } else {
288 return ret_error;
293 break;
294 case OSM_DELETE_WAY_COMMAND: {
295 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
296 cherokee_buffer_add_va (&sql1, SQL_WAY_CREATE, username);
297 run_sql(hdl, &sql1, buf, result_node_last_id);
298 cherokee_buffer_mrproper(&sql1);
300 long testid = 0;
301 testid = strtol(buf->buf, (char **) NULL, 10);
302 if (errno != ERANGE && testid > 0) {
303 do_tags(hdl, node, testid, 0, SQL_WAY_CREATE_NODE_TAG, SQL_WAY_UPDATE_NODE_TAG, SQL_WAY_DELETE_NODE_TAG);
304 do_nds(hdl, node, testid, 0); /* this sequence otherwise we screw up type= */
306 return ret_ok;
307 } else {
308 return ret_error;
311 break;
312 case OSM_DELETE_RELATION_COMMAND: {
313 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
314 cherokee_buffer_add_va (&sql1, SQL_RELATION_CREATE, username);
315 run_sql(hdl, &sql1, buf, result_node_last_id);
316 cherokee_buffer_mrproper(&sql1);
318 long testid = 0;
319 testid = strtol(buf->buf, (char **) NULL, 10);
320 if (errno != ERANGE && testid > 0) {
321 do_members(hdl, node, testid, 0);
322 do_tags(hdl, node, testid, 0, SQL_RELATION_CREATE_NODE_TAG, SQL_RELATION_UPDATE_NODE_TAG, SQL_RELATION_DELETE_NODE_TAG);
324 return ret_ok;
325 } else {
326 return ret_error;
329 break;
330 default:
331 SHOULDNT_HAPPEN;
333 SHOULDNT_HAPPEN;
334 return ret_error;
337 static ret_t
338 update_node(cherokee_handler_osm_t *hdl, axlNode * node, osm_state_delete_t type, unsigned long int nodeid, const char *username, short int timestamp) {
339 cherokee_connection_t *conn = HANDLER_CONN(hdl);
341 if (axl_node_has_attribute_value(node, "visible", "false")) {
342 /* the user wants to delete stuff by updating, that is nice
343 * but we will not update. Instead we do what the user request:
344 * deletion.
346 return delete_object_by_id(hdl, nodeid, type);
347 } else {
348 switch (type) {
349 case OSM_DELETE_NODE_COMMAND: {
350 if (axl_node_has_attribute(node, "lat") &&
351 axl_node_has_attribute(node, "lon")) {
352 double lat, lon;
353 lat = strtod(axl_node_get_attribute_value(node, "lat"), NULL);
354 if (errno == ERANGE) {
355 conn->error_code = http_bad_request;
356 return ret_error;
359 lon = strtod(axl_node_get_attribute_value(node, "lon"), NULL);
360 if (errno == ERANGE) {
361 conn->error_code = http_bad_request;
362 return ret_error;
363 } else {
364 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
365 if (timestamp == 1 && axl_node_has_attribute(node, "timestamp")) {
366 cherokee_buffer_add_va (&sql1, SQL_NODE_UPDATE_BY_ID, lon, lat, username,
367 "'", axl_node_get_attribute_value(node, "timestamp"), "'", nodeid);
368 } else {
369 cherokee_buffer_add_va (&sql1, SQL_NODE_UPDATE_BY_ID, lon, lat, username, SQL_NOW, nodeid);
371 run_sql(hdl, &sql1, NULL, NULL);
372 cherokee_buffer_mrproper(&sql1);
374 do_tags(hdl, node, nodeid, 1, SQL_NODE_CREATE_NODE_TAG, SQL_NODE_UPDATE_NODE_TAG, SQL_NODE_DELETE_NODE_TAG);
376 return ret_ok;
380 break;
381 case OSM_DELETE_WAY_COMMAND: {
382 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
383 if (timestamp == 1 && axl_node_has_attribute(node, "timestamp")) {
384 cherokee_buffer_add_va (&sql1, SQL_WAY_UPDATE, username,
385 "'", axl_node_get_attribute_value(node, "timestamp"), "'", nodeid);
386 } else {
387 cherokee_buffer_add_va (&sql1, SQL_WAY_UPDATE, username, SQL_NOW, nodeid);
389 run_sql(hdl, &sql1, NULL, NULL);
390 cherokee_buffer_mrproper(&sql1);
392 do_tags(hdl, node, nodeid, 1, SQL_WAY_CREATE_NODE_TAG, SQL_WAY_UPDATE_NODE_TAG, SQL_WAY_DELETE_NODE_TAG);
393 do_nds(hdl, node, nodeid, 1); /* this sequence otherwise we screw up type = */
395 return ret_ok;
397 break;
398 case OSM_DELETE_RELATION_COMMAND: {
399 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
400 if (timestamp == 1 && axl_node_has_attribute(node, "timestamp")) {
401 cherokee_buffer_add_va (&sql1, SQL_RELATION_UPDATE, username,
402 "'", axl_node_get_attribute_value(node, "timestamp"), "'", nodeid);
403 } else {
404 cherokee_buffer_add_va (&sql1, SQL_RELATION_UPDATE, username, SQL_NOW, nodeid);
406 run_sql(hdl, &sql1, NULL, NULL);
407 cherokee_buffer_mrproper(&sql1);
409 do_members(hdl, node, nodeid, 1);
410 do_tags(hdl, node, nodeid, 1, SQL_RELATION_CREATE_NODE_TAG, SQL_RELATION_UPDATE_NODE_TAG, SQL_RELATION_DELETE_NODE_TAG);
412 return ret_ok;
414 break;
415 default:
416 SHOULDNT_HAPPEN;
421 SHOULDNT_HAPPEN;
422 return ret_error;
427 ret_t
428 cherokee_handler_osm_init_put (cherokee_handler_osm_t *hdl)
430 off_t postl;
431 ret_t ret = ret_ok;
432 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
433 cherokee_connection_t *conn = HANDLER_CONN(hdl);
434 axlDoc * doc;
435 axlError * error;
437 /* Check for the post info
439 cherokee_post_get_len (&conn->post, &postl);
440 if (postl <= 0 || postl >= (INT_MAX-1)) {
441 conn->error_code = http_bad_request;
442 return ret_error;
446 /* Process line per line
448 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
450 TRACE("post", "%s\n", post.buf);
452 doc = axl_doc_parse (post.buf, post.len, &error);
454 if (doc == NULL) {
455 printf ("Error found: %s\n", axl_error_get (error));
456 axl_error_free (error);
457 ret = ret_error;
458 } else {
459 int isroot = 0;
460 axlNode * node = axl_doc_get_root (doc);
461 node = axl_node_get_first_child (node);
462 ret = ret_ok;
464 /* het mooiste zou zijn om het onderstaande in twee functies te zetten
465 * update vs create.
466 * Als dat gebeurd is kan hier (of in de 'update' code gechecked worden
467 * op 'root' of op normale user en aan de hand daarvan weer switchen op
468 * empty == create of full == update)
470 cherokee_buffer_t sql1 = CHEROKEE_BUF_INIT;
471 cherokee_buffer_add_str (&sql1, SQL_TRANSACTION_START);
472 run_sql(hdl, &sql1, &hdl->buffer, NULL);
473 cherokee_buffer_mrproper(&sql1);
475 isroot = (cherokee_buffer_cmp_str(conn->realm_ref,"root") == 0);
477 while (node != NULL && ret == ret_ok) {
478 const char *username = NULL;
479 unsigned long int nodeid = 0;
480 osm_state_delete_t type;
482 if (axl_node_has_attribute(node, "id")) {
483 const char *id = axl_node_get_attribute_value(node, "id");
484 nodeid = strtoul(id, (char **) NULL, 10);
485 TRACE("osm", "%lu\n", nodeid);
488 if (isroot) {
489 username = axl_node_get_attribute_value(node, "user");
490 } else {
491 username = conn->realm_ref->buf;
494 if (NODE_CMP_NAME (node, "node")) {
495 type = OSM_DELETE_NODE_COMMAND;
496 } else if (NODE_CMP_NAME (node, "way")) {
497 type = OSM_DELETE_WAY_COMMAND;
498 } else if (NODE_CMP_NAME (node, "relation")) {
499 type = OSM_DELETE_RELATION_COMMAND;
500 } else {
501 ret = ret_error;
502 break;
505 if (nodeid > 0 && node_exists(hdl, type, nodeid)) {
506 /* UPDATE */
507 ret = update_node(hdl, node, type, nodeid, username, isroot);
508 } else {
509 /* CREATE */
510 ret = create_node(hdl, node, type, nodeid, username, isroot);
513 node = axl_node_get_next(node);
516 if (ret != ret_ok) {
517 cherokee_buffer_add_str (&sql1, SQL_TRANSACTION_ROLLBACK);
518 run_sql(hdl, &sql1, &hdl->buffer, NULL);
519 cherokee_buffer_mrproper(&sql1);
520 } else {
521 cherokee_buffer_add_str (&sql1, SQL_TRANSACTION_COMMIT);
522 run_sql(hdl, &sql1, &hdl->buffer, NULL);
523 cherokee_buffer_mrproper(&sql1);
526 axl_doc_free (doc);
529 cherokee_buffer_mrproper (&post);
530 return ret;