tinyows 1.2.2
wfs_transaction.c
Go to the documentation of this file.
1/*
2 Copyright (c) <2007-2012> <Barbara Philippot - Olivier Courtin>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 IN THE SOFTWARE.
21*/
22
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <assert.h>
27#include <string.h>
28#include <ctype.h>
29#include <time.h>
30
31#include "../ows/ows.h"
32
33/*
34 * Execute the request sql matching a transaction
35 * Return the result of the request (PGRES_COMMAND_OK or an error message)
36 */
38{
39 buffer *result, *cmd_status;
40 PGresult *res;
41
42 assert(o);
43 assert(sql);
44
45 result = buffer_init();
46 cmd_status = buffer_init();
47
48 res = ows_psql_exec(o, sql->buf);
49 if (PQresultStatus(res) != PGRES_COMMAND_OK)
50 buffer_add_str(result, PQresultErrorMessage(res));
51 else
52 buffer_add_str(result, PQresStatus(PQresultStatus(res)));
53 buffer_add_str(cmd_status, (char *) PQcmdStatus(res));
54
55 if (check_regexp(cmd_status->buf, "^DELETE")) {
56 cmd_status = buffer_replace(cmd_status, "DELETE ", "");
57 wr->delete_results += atoi(cmd_status->buf);
58 }
59
60 if (check_regexp(cmd_status->buf, "^UPDATE")) {
61 cmd_status = buffer_replace(cmd_status, "UPDATE ", "");
62 wr->update_results += atoi(cmd_status->buf);
63 }
64
65 buffer_free(cmd_status);
66 PQclear(res);
67
68 return result;
69}
70
71
72/*
73 * Summarize overall results of transaction request
74 */
75static void wfs_transaction_summary(ows * o, wfs_request * wr, buffer * result)
76{
77 alist_node *an;
78 int nb = 0;
79
80 assert(o);
81 assert(wr);
82 assert(result);
83
84 fprintf(o->output, "<wfs:TransactionSummary>\n");
85
86 if (buffer_cmp(result, "PGRES_COMMAND_OK")) {
87
88 if (wr->insert_results) {
89 for (an = wr->insert_results->first ; an ; an = an->next) nb += an->value->size;
90 fprintf(o->output, " <wfs:totalInserted>%d</wfs:totalInserted>\n", nb);
91 }
92
93 fprintf(o->output, "<wfs:totalUpdated>%d</wfs:totalUpdated>\n", wr->update_results);
94 fprintf(o->output, " <wfs:totalDeleted>%d</wfs:totalDeleted>\n", wr->delete_results);
95 }
96
97 fprintf(o->output, "</wfs:TransactionSummary>\n");
98}
99
100
101/*
102 * Report newly created feature instances
103 */
104static void wfs_transaction_insert_result(ows * o, wfs_request * wr, buffer * result)
105{
106 alist_node *an;
107 list_node *ln;
108
109 assert(o);
110 assert(wr);
111 assert(result);
112
113 ln = NULL;
114
115 /* check if there were Insert operations and if the command succeeded */
116 if ((!cgi_method_get()) && (buffer_cmp(result, "PGRES_COMMAND_OK") && (wr->insert_results->first))) {
117
118 if (ows_version_get(o->request->version) == 110)
119 fprintf(o->output, "<wfs:InsertResults>\n");
120
121 for (an = wr->insert_results->first ; an ; an = an->next) {
122
123 if (ows_version_get(o->request->version) == 100) {
124 fprintf(o->output, "<wfs:InsertResult handle=\"%s\">", an->key->buf);
125 for (ln = an->value->first ; ln ; ln = ln->next)
126 fprintf(o->output, "<ogc:FeatureId fid=\"%s\"/>", ln->value->buf);
127 fprintf(o->output, "</wfs:InsertResult>\n");
128 } else {
129 for (ln = an->value->first ; ln ; ln = ln->next) {
130 fprintf(o->output, "<wfs:Feature handle=\"%s\">\n", an->key->buf);
131 fprintf(o->output, " <ogc:FeatureId fid=\"%s\"/>\n", ln->value->buf);
132 fprintf(o->output, "</wfs:Feature>\n");
133 }
134 }
135 }
136
137 if (ows_version_get(o->request->version) == 110)
138 fprintf(o->output, "</wfs:InsertResults>");
139 }
140}
141
142
143/*
144 * Report the overall result of the transaction request
145 */
146static void wfs_transaction_result(ows * o, wfs_request * wr, buffer * result, buffer * locator)
147{
148 assert(o);
149 assert(wr);
150 assert(result);
151
152 if (!buffer_cmp(result, "PGRES_COMMAND_OK")) assert(locator);
153
154 /* only if version = 1.0.0 or if command failed */
155 if (ows_version_get(o->request->version) == 100
156 || (ows_version_get(o->request->version) == 110
157 && !buffer_cmp(result, "PGRES_COMMAND_OK"))) {
158
159 if (ows_version_get(o->request->version) == 110)
160 fprintf(o->output, "<wfs:TransactionResults>\n");
161 else {
162 fprintf(o->output, "<wfs:TransactionResult>\n");
163 /* display status transaction only for 1.0.0 version */
164 fprintf(o->output, "<wfs:Status>");
165
166 if (buffer_cmp(result, "PGRES_COMMAND_OK"))
167 fprintf(o->output, "<wfs:SUCCESS/>");
168 else fprintf(o->output, "<wfs:FAILED/>");
169
170 fprintf(o->output, "</wfs:Status>\n");
171 }
172
173
174 if (ows_version_get(o->request->version) == 100)
175 fprintf(o->output, "</wfs:TransactionResult>\n");
176 else {
177 fprintf(o->output, "</wfs:Action>\n");
178 fprintf(o->output, "</wfs:TransactionResults>\n");
179 }
180 }
181}
182
183
184/*
185 * Write the transaction response in XML
186 */
187static void wfs_transaction_response(ows * o, wfs_request * wr, buffer * result, buffer * locator)
188{
189 assert(o);
190 assert(wr);
191 assert(result);
192
193 if (!buffer_cmp(result, "PGRES_COMMAND_OK")) {
194 if (buffer_cmp(result, "No FE selector on DELETE statement"))
195 wfs_error(o, wr, WFS_ERROR_MISSING_PARAMETER, result->buf, locator->buf);
196 else
197 wfs_error(o, wr, WFS_ERROR_INVALID_PARAMETER, result->buf, locator->buf);
198 return;
199 }
200
201 fprintf(o->output, "Content-Type: application/xml\n\n");
202 fprintf(o->output, "<?xml version='1.0' encoding='%s'?>\n", o->encoding->buf);
203
204 if (ows_version_get(o->request->version) == 100)
205 fprintf(o->output, "<wfs:WFS_TransactionResponse version=\"1.0.0\"\n");
206 else fprintf(o->output, "<wfs:TransactionResponse version=\"1.1.0\"\n");
207
208 fprintf(o->output, " xmlns:wfs=\"http://www.opengis.net/wfs\"\n");
209 fprintf(o->output, " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
210 fprintf(o->output, " xmlns:ogc=\"http://www.opengis.net/ogc\"\n");
211
212 if (ows_version_get(o->request->version) == 100) {
213 fprintf(o->output, " xsi:schemaLocation='http://www.opengis.net/wfs");
214 fprintf(o->output, " http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd'>\n");
215 } else {
216 fprintf(o->output, " xsi:schemaLocation='http://www.opengis.net/wfs");
217 fprintf(o->output, " http://schemas.opengis.net/wfs/1.1.0/wfs.xsd'>\n");
218 }
219
220 if (ows_version_get(o->request->version) == 100) {
221 wfs_transaction_insert_result(o, wr, result);
222 wfs_transaction_result(o, wr, result, locator);
223 } else {
224 wfs_transaction_summary(o, wr, result);
225 wfs_transaction_result(o, wr, result, locator);
226 wfs_transaction_insert_result(o, wr, result);
227 }
228
229 if (ows_version_get(o->request->version) == 100)
230 fprintf(o->output, "</wfs:WFS_TransactionResponse>\n");
231 else fprintf(o->output, "</wfs:TransactionResponse>\n");
232}
233
234
235/*
236 * Add a content node value to a buffer
237 */
238static buffer *wfs_retrieve_value(ows * o, wfs_request * wr, buffer * value, xmlDocPtr xmldoc, xmlNodePtr n)
239{
240 xmlChar *content;
241 char *content_escaped;
242
243 assert(o);
244 assert(wr);
245 assert(value);
246 assert(n);
247
248 content = xmlNodeGetContent(n);
249 content_escaped = ows_psql_escape_string(o, (char *) content);
250
251 if (!content_escaped) {
252 xmlFree(content);
253 buffer_free(value);
254 xmlFreeDoc(xmldoc);
256 "Some forbidden character are present into the request", "transaction");
257 }
258
259 buffer_add_str(value, "'");
260 buffer_add_str(value, content_escaped);
261 buffer_add_str(value, "'");
262
263 xmlFree(content);
264 free(content_escaped);
265
266 return value;
267}
268
269
270/*
271 * Retrieve the layer's name
272 */
273static buffer *wfs_retrieve_typename(ows * o, wfs_request * wr, xmlNodePtr n)
274{
275 xmlAttr *att;
276 xmlChar *content;
277 buffer *typename;
278 array *o_ns;
279
280 content = NULL;
281 typename = buffer_init();
283
284 for (att = n->properties ; att ; att = att->next) {
285
286 if (!strcmp((char *) att->name, "typeName")) {
287 content = xmlNodeGetContent(att->children);
288 buffer_add_str(typename, (char *) content);
289
290 /* Handle case when ns_prefix don't match but ns_uri does */
291 /* FIXME is this still work with several ns_uri ? */
292 if (n->nsDef && n->nsDef->href && array_is_value(o_ns, (char *) n->nsDef->href)) {
293 buffer_shift(typename, strlen((char *) n->nsDef->prefix));
294 buffer_add_head_str(typename, (array_get_key(o_ns, (char *) n->nsDef->href))->buf);
295 }
296
298 xmlFree(content);
299 return NULL;
300 }
301
302 xmlFree(content);
303 array_free(o_ns);
304 return typename;
305 }
306 }
307
308 array_free(o_ns);
309 return NULL;
310}
311
312
313/*
314 * Insert features into the database
315 * Method POST, XML
316 */
317static buffer *wfs_insert_xml(ows * o, wfs_request * wr, xmlDocPtr xmldoc, xmlNodePtr n)
318{
319 buffer *values, *column, *layer_name, *layer_ns_prefix, *result, *sql, *gml;
320 buffer *handle, *id_column, *fid_full_name, *dup_sql, *id;
321 xmlNodePtr node, elemt;
322 filter_encoding *fe;
323 PGresult *res;
324 array * table;
325 char *escaped;
326 list *l;
327 ows_srs * srs_root = NULL;
328 xmlChar *attr = NULL;
330 enum wfs_insert_idgen handle_idgen = WFS_GENERATE_NEW;
331
332 assert(o);
333 assert(wr);
334 assert(xmldoc);
335 assert(n);
336
337 sql = buffer_init();
338 handle = buffer_init();
339 result = NULL;
340
341 /* retrieve handle attribute to report it in transaction response */
342 if (xmlHasProp(n, (xmlChar *) "handle")) {
343 attr = xmlGetProp(n, (xmlChar *) "handle");
344 buffer_add_str(handle, (char *) attr);
345 xmlFree(attr);
346 attr = NULL;
347 /* handle is optional in WFS Schema */
348 } else buffer_add_str(handle, "TinyOWS-WFS-default-handle");
349
350 /* idgen appears in WFS 1.1.0, default behaviour is GenerateNew id
351 It is safe to not test WFS version, as schema validation
352 already do the job for us.
353 */
354 if (xmlHasProp(n, (xmlChar *) "idgen")) {
355 attr = xmlGetProp(n, (xmlChar *) "idgen");
356 if (!strcmp((char *) attr, "ReplaceDuplicate")) handle_idgen = WFS_REPLACE_DUPLICATE;
357 else if (!strcmp((char *) attr, "UseExisting")) handle_idgen = WFS_USE_EXISTING;
358 xmlFree(attr);
359 attr = NULL;
360 }
361
362 /*
363 * In WFS 1.1.0 default srsName could be define
364 * TODO: what about for WFS 1.0.0 ?
365 */
366 if (xmlHasProp(n, (xmlChar *) "srsName")) {
367 attr = xmlGetProp(n, (xmlChar *) "srsName");
368 srs_root = ows_srs_init();
369
370 if (!ows_srs_set_from_srsname(o, srs_root, (char *) attr)) {
371 buffer_free(sql);
372 buffer_free(handle);
373 ows_srs_free(srs_root);
374 xmlFree(attr);
375 result = buffer_from_str("Unkwnown or wrong CRS used");
376 return result;
377 }
378
379 xmlFree(attr);
380 attr = NULL;
381 }
382
383 n = n->children;
384
385 /* jump to the next element if there are spaces */
386 while (n->type != XML_ELEMENT_NODE) n = n->next;
387
388 /* Create Insert SQL query for each Typename */
389 for ( /* Empty */ ; n ; n = n->next) {
390 if (n->type != XML_ELEMENT_NODE) continue;
391
392 id = buffer_init();
393 values = buffer_init();
394 layer_name = buffer_init();
395
396 /* name of the table in which features must be inserted */
397 buffer_add_str(layer_name, (char *) n->ns->href);
398 buffer_add(layer_name, ':');
399 buffer_add_str(layer_name, (char *) n->name);
400
401 if (!layer_name || !ows_layer_writable(o->layers, layer_name)) {
402 buffer_free(id);
403 buffer_free(sql);
404 buffer_free(values);
405 buffer_free(handle);
406 if (layer_name) buffer_free(layer_name);
407 if (srs_root) ows_srs_free(srs_root);
408 result = buffer_from_str("Error unknown or not writable Layer Name");
409 return result;
410 }
411
412 idgen = handle_idgen;
413
414 /* In GML 3 GML:id is used, in GML 2.1.2 fid is used.
415 * In both cases no other attribute allowed in this element
416 * and in both cases (f)id is optionnal !
417 */
418 if (xmlHasProp(n, (xmlChar *) "id")) attr = xmlGetProp(n, (xmlChar *) "id");
419 else if (xmlHasProp(n, (xmlChar *) "fid")) attr = xmlGetProp(n, (xmlChar *) "fid");
420
421 if (attr) {
422 buffer_empty(id);
423 buffer_add_str(id, (char *) attr);
424 xmlFree(attr);
425 } else idgen = WFS_GENERATE_NEW;
426 /* FIXME should we end on error if UseExisting or Replace without id set ? */
427
428 id_column = ows_psql_id_column(o, layer_name);
429 if (!id_column) {
430 buffer_free(id);
431 buffer_free(sql);
432 buffer_free(values);
433 buffer_free(layer_name);
434 if (srs_root) ows_srs_free(srs_root);
435 result = buffer_from_str("Error unknown Layer Name or not id column available");
436 return result;
437 }
438
439 if (id->use) {
440 l = list_explode('.', id);
441 if (l->last) {
442 buffer_empty(id);
443 buffer_copy(id, l->last->value);
444 }
445 list_free(l);
446 }
447
448 layer_ns_prefix = ows_layer_ns_prefix(o->layers, layer_name);
449 (void)layer_ns_prefix; // FIXME : unused variable ?
450
451 /* ReplaceDuplicate look if an ID is already used
452 *
453 * May not be safe if another transaction occur between
454 * this select and the related insert !!!
455 */
456 if (idgen == WFS_REPLACE_DUPLICATE) {
457 dup_sql = buffer_init();
458
459 buffer_add_str(dup_sql, "SELECT count(*) FROM \"");
460 buffer_copy(dup_sql, ows_psql_schema_name(o, layer_name));
461 buffer_add_str(dup_sql, "\".\"");
462 buffer_copy(dup_sql, ows_psql_table_name(o, layer_name));
463 buffer_add_str(dup_sql, "\" WHERE ");
464 buffer_copy(dup_sql, id_column);
465 buffer_add_str(dup_sql, "='");
466 escaped = ows_psql_escape_string(o, id->buf);
467 if (escaped) {
468 buffer_add_str(dup_sql, escaped);
469 free(escaped);
470 }
471 buffer_add_str(dup_sql, "';");
472
473 res = ows_psql_exec(o, dup_sql->buf);
474 if (PQresultStatus(res) != PGRES_TUPLES_OK || atoi((char *) PQgetvalue(res, 0, 0)) != 0)
475 idgen = WFS_GENERATE_NEW;
476 else
477 idgen = WFS_USE_EXISTING;
478
479 buffer_free(dup_sql);
480 PQclear(res);
481 }
482
483 if (idgen == WFS_GENERATE_NEW) {
484 buffer_free(id);
485 id = ows_psql_generate_id(o, layer_name);
486 }
487
488 /* Retrieve the id of the inserted feature
489 * to report it in transaction respons
490 */
491 fid_full_name = buffer_init();
492 buffer_add_str(fid_full_name, (char *) n->name);
493 buffer_add(fid_full_name, '.');
494 buffer_copy(fid_full_name, id);
495 alist_add(wr->insert_results, handle, fid_full_name);
496
497 buffer_add_str(sql, "INSERT INTO \"");
498 buffer_copy(sql, ows_psql_schema_name(o, layer_name));
499 buffer_add_str(sql, "\".\"");
500 buffer_copy(sql, ows_psql_table_name(o, layer_name));
501 buffer_add_str(sql, "\" (\"");
502 buffer_copy(sql, id_column);
503 buffer_add_str(sql, "\"");
504
505 node = n->children;
506
507 /* Jump to the next element if spaces */
508 while (node != NULL && node->type != XML_ELEMENT_NODE) node = node->next;
509
510 /* Fill SQL fields and values at once */
511 for ( /* empty */ ; node; node = node->next) {
512
513
514 if (node->type == XML_ELEMENT_NODE &&
515 ( buffer_cmp(ows_layer_ns_uri(o->layers, layer_name), (char *) node->ns->href)
516 || !strcmp("http://www.opengis.net/gml", (char *) node->ns->href)
517 || !strcmp("http://www.opengis.net/gml/3.2", (char *) node->ns->href))) {
518
519 /* We have to ignore if not present in database,
520 gml elements (name, description, boundedBy) */
521 if ( !strcmp("http://www.opengis.net/gml", (char *) node->ns->href)
522 || !strcmp("http://www.opengis.net/gml/3.2", (char *) node->ns->href)) {
523 table = ows_psql_describe_table(o, layer_name);
524 if (!array_is_key(table, (char *) node->name)) continue;
525 }
526 buffer_add(sql, ',');
527 buffer_add(values, ',');
528
529 column = buffer_from_str((char *) node->name);
530
531 buffer_add_str(sql, "\"");
532 escaped = ows_psql_escape_string(o, column->buf);
533 if (escaped) {
534 buffer_add_str(sql, escaped);
535 free(escaped);
536 }
537 buffer_add_str(sql, "\"");
538
539 /* If column's type is a geometry, transform the GML into WKT */
540 if (ows_psql_is_geometry_column(o, layer_name, column)) {
541 elemt = node->children;
542
543 /* Jump to the next element if spaces */
544 while (elemt != NULL && elemt->type != XML_ELEMENT_NODE) elemt = elemt->next;
545 if (elemt != NULL) {
546 if (!strcmp((char *) elemt->name, "Box") ||
547 !strcmp((char *) elemt->name, "Envelope")) {
548
550 fe->sql = fe_envelope(o, layer_name, fe, fe->sql, elemt);
551 if (fe->error_code != FE_NO_ERROR) {
552 result = fill_fe_error(o, fe);
553 buffer_free(sql);
554 buffer_free(values);
555 buffer_free(column);
556 buffer_free(id);
558 if (srs_root) ows_srs_free(srs_root);
559 return result;
560 }
561 buffer_copy(values, fe->sql);
563
564 } else if (!strcmp((char *) elemt->name, "Null")) {
565 buffer_add_str(values, "''");
566 } else {
567 gml = ows_psql_gml_to_sql(o, elemt, srs_root);
568 if (gml) {
569 buffer_add_str(values, "'");
570 buffer_copy(values, gml);
571 buffer_add_str(values, "'");
572 buffer_free(gml);
573 } else {
574 buffer_free(sql);
575 buffer_free(values);
576 buffer_free(column);
577 buffer_free(id);
578 buffer_free(layer_name);
579 if (srs_root) ows_srs_free(srs_root);
580
581 result = buffer_from_str("Error invalid Geometry");
582 return result;
583 }
584 }
585 }
586 else
587 buffer_add_str(values, "NULL");
588
589 } else values = wfs_retrieve_value(o, wr, values, xmldoc, node);
590
591 buffer_free(column);
592 }
593 }
594
595 /* As 'id' could be NULL in GML */
596 if (id->use) {
597 buffer_add_str(sql, ") VALUES ('");
598 escaped = ows_psql_escape_string(o, id->buf);
599 if (escaped) {
600 buffer_add_str(sql, escaped);
601 free(escaped);
602 }
603 buffer_add_str(sql, "'");
604 } else buffer_add_str(sql, ") VALUES (null");
605
606 buffer_copy(sql, values);
607 buffer_add_str(sql, ") ");
608
609 buffer_free(values);
610 buffer_free(id);
611
612 /* Run the request to insert each feature */
613 if(result) buffer_free(result);
614 result = wfs_execute_transaction_request(o, wr, sql);
615 if (!buffer_cmp(result, "PGRES_COMMAND_OK")) {
616 buffer_free(sql);
617 if (srs_root) ows_srs_free(srs_root);
618 return result;
619 }
620 buffer_empty(sql);
621 buffer_free(layer_name);
622 }
623
624 buffer_free(sql);
625 if (srs_root) ows_srs_free(srs_root);
626
627 return result;
628}
629
630
631/*
632 * Delete features in database
633 * Method GET / KVP
634 */
636{
637 buffer *sql, *result, *where, *layer_name, *locator;
638 int cpt, size;
639 mlist_node *mln_fid;
640 list_node *ln_typename, *ln_filter;
641 list *fe;
642 filter_encoding *filter;
643
644 assert(o);
645 assert(wr);
646
647 sql = buffer_init();
648 ln_typename = NULL;
649 ln_filter = NULL;
650 mln_fid = NULL;
651 where = NULL;
652 size = 0;
653
654 if (wr->typename) {
655 size = wr->typename->size;
656 ln_typename = wr->typename->first;
657 }
658
659 if (wr->filter) ln_filter = wr->filter->first;
660 if (wr->featureid) {
661 size = wr->featureid->size;
662 mln_fid = wr->featureid->first;
663 }
664
665 /* delete elements layer by layer */
666 for (cpt = 0; cpt < size; cpt++) {
667 /* define a layer_name which match typename or featureid */
668 layer_name = buffer_init();
669
670 if (wr->typename) buffer_copy(layer_name, ln_typename->value);
671 else {
672 fe = list_explode('.', mln_fid->value->first->value);
673 buffer_copy(layer_name, fe->first->value);
674 list_free(fe);
675 }
676
677 /* FROM */
678 buffer_add_str(sql, "DELETE FROM \"");
679 buffer_copy(sql, ows_psql_schema_name(o, layer_name));
680 buffer_add_str(sql, "\".\"");
681 buffer_copy(sql, ows_psql_table_name(o, layer_name));
682 buffer_add_str(sql, "\" ");
683
684 /* WHERE : match featureid, bbox or filter */
685
686 /* FeatureId */
687 if (wr->featureid) {
688 where = fe_kvp_featureid(o, wr, layer_name, mln_fid->value);
689
690 if (!where->use) {
691 buffer_free(where);
692 buffer_free(sql);
693 wfs_error(o, wr, WFS_ERROR_NO_MATCHING, "error : an id_column is required to use featureid", "Delete");
694 return;
695 }
696 }
697 /* BBOX */
698 else if (wr->bbox) where = fe_kvp_bbox(o, wr, layer_name, wr->bbox);
699
700 /* Filter */
701 else {
702 if (ln_filter->value->use) {
703 where = buffer_init();
704 buffer_add_str(where, " WHERE ");
705 filter = filter_encoding_init();
706 filter = fe_filter(o, filter, layer_name, ln_filter->value);
707
708 if (filter->error_code != FE_NO_ERROR) {
709 buffer_free(where);
710 buffer_free(sql);
711 fe_error(o, filter);
712 return;
713 }
714
715 buffer_copy(where, filter->sql);
716 filter_encoding_free(filter);
717 }
718 }
719
720 buffer_copy(sql, where);
721 buffer_add_str(sql, "; ");
722 buffer_free(where);
723
724 /*incrementation of the nodes */
725 if (wr->featureid) mln_fid = mln_fid->next;
726 if (wr->typename) ln_typename = ln_typename->next;
727 if (wr->filter) ln_filter = ln_filter->next;
728 }
729
730 result = wfs_execute_transaction_request(o, wr, sql);
731
732 locator = buffer_init();
733 buffer_add_str(locator, "Delete");
734
735 /* display the transaction response directly since
736 there is only one operation using GET method */
737 wfs_transaction_response(o, wr, result, locator);
738
739 buffer_free(locator);
740 buffer_free(result);
741 buffer_free(sql);
742}
743
744
745/*
746 * Delete features in database
747 * Method POST / XML
748 */
749static buffer *wfs_delete_xml(ows * o, wfs_request * wr, xmlNodePtr n)
750{
751 buffer *typename, *layer_name, *xmlstring, *result, *sql, *s, *t;
752 filter_encoding *filter;
753
754 assert(o);
755 assert(wr);
756 assert(n);
757
758 sql = buffer_init();
759 s = t = NULL;
760
761 buffer_add_str(sql, "DELETE FROM ");
762
763 /*retrieve the name of the table in which features must be deleted */
764 typename = wfs_retrieve_typename(o, wr, n);
765 layer_name = ows_layer_prefix_to_uri(o->layers, typename);
766 if (layer_name) s = ows_psql_schema_name(o, layer_name);
767 if (layer_name) t = ows_psql_table_name(o, layer_name);
768
769 if (!layer_name || !s || !t) {
770 if (typename) buffer_free(typename);
771 buffer_free(sql);
772 result = buffer_from_str("Typename provided is unknown or not writable");
773
774 return result;
775 }
776
777 buffer_add_str(sql, "\"");
778 buffer_copy(sql, s);
779 buffer_add_str(sql, "\".\"");
780 buffer_copy(sql, t);
781 buffer_add_str(sql, "\"");
782
783 n = n->children;
784 if (!n) {
785 buffer_free(typename);
786 buffer_free(sql);
787 result = buffer_init();
788 buffer_add_str(result, "No FE selector on DELETE statement");
789 return result;
790 }
791
792 /* jump to the next element if there are spaces */
793 while (n->type != XML_ELEMENT_NODE) n = n->next;
794 buffer_add_str(sql, " WHERE ");
795
796 /* put xml filter into a buffer */
797 xmlstring = buffer_init();
798 xmlstring = cgi_add_xml_into_buffer(xmlstring, n);
799
800 filter = filter_encoding_init();
801 filter = fe_filter(o, filter, typename, xmlstring);
802
803 /* check if filter returned an error */
804 if (filter->error_code != FE_NO_ERROR)
805 result = fill_fe_error(o, filter);
806 else {
807 buffer_copy(sql, filter->sql);
808 buffer_add_str(sql, ";");
809 /* run the SQL request to delete all specified features */
810 result = wfs_execute_transaction_request(o, wr, sql);
811 }
812
813 filter_encoding_free(filter);
814 buffer_free(xmlstring);
815 buffer_free(typename);
816 buffer_free(sql);
817
818 return result;
819}
820
821
822/*
823 * Update features in database
824 * Method POST / XML
825 */
826static buffer *wfs_update_xml(ows * o, wfs_request * wr, xmlDocPtr xmldoc, xmlNodePtr n)
827{
828 buffer *typename, *layer_name, *xmlstring, *result, *sql, *property_name, *values, *gml, *s, *t;
829 filter_encoding *filter, *fe;
830 xmlNodePtr node, elemt;
831 xmlChar *content;
832 char *escaped;
833 array *table;
834 ows_srs *srs_root = NULL;
835 xmlChar *attr = NULL;
836 list *l;
837
838 assert(o);
839 assert(wr);
840 assert(xmldoc);
841 assert(n);
842
843 sql = buffer_init();
844 content = NULL;
845 s = t = result = layer_name = NULL;
846
847 /*
848 * In WFS 1.1.0 default srsName could be define
849 * FIXME: what about for WFS 1.0.0 ?
850 */
851 if (xmlHasProp(n, (xmlChar *) "srsName")) {
852 attr = xmlGetProp(n, (xmlChar *) "srsName");
853 srs_root = ows_srs_init();
854
855 if (!ows_srs_set_from_srsname(o, srs_root, (char *) attr)) {
856 ows_srs_free(srs_root);
857 xmlFree(attr);
858 buffer_add_str(result, "Unkwnown or wrong CRS used");
859 return result;
860 }
861
862 xmlFree(attr);
863 attr = NULL;
864 }
865
866 buffer_add_str(sql, "UPDATE ");
867
868 /*retrieve the name of the table in which features must be updated */
869 typename = wfs_retrieve_typename(o, wr, n);
870 if (typename) layer_name = ows_layer_prefix_to_uri(o->layers, typename);
871 if (layer_name) s = ows_psql_schema_name(o, layer_name);
872 if (layer_name) t = ows_psql_table_name(o, layer_name);
873
874 if (!layer_name || !s || !t) {
875 if (typename) buffer_free(typename);
876 buffer_free(sql);
877 if (srs_root) ows_srs_free(srs_root);
878 result = buffer_from_str("Typename provided is unknown or not writable");
879 return result;
880 }
881
882 buffer_add_str(sql, "\"");
883 buffer_copy(sql, s);
884 buffer_add_str(sql, "\".\"");
885 buffer_copy(sql, t);
886 buffer_add_str(sql, "\"");
887
888 n = n->children;
889
890 /* jump to the next element if there are spaces */
891 while (n->type != XML_ELEMENT_NODE) n = n->next;
892
893 buffer_add_str(sql, " SET ");
894
895 /* write the fields and the new values of the features to update */
896 for (; n; n = n->next) {
897 values = buffer_init();
898
899 if (n->type == XML_ELEMENT_NODE) {
900 if (!strcmp((char *) n->name, "Property")) {
901 node = n->children;
902
903 while (node->type != XML_ELEMENT_NODE) node = node->next;
904
905 /* We have to ignore if not present in database,
906 gml elements (name, description, boundedBy) */
907 if ( !strcmp("http://www.opengis.net/gml", (char *) node->ns->href)
908 || !strcmp("http://www.opengis.net/gml/3.2", (char *) node->ns->href)) {
909 table = ows_psql_describe_table(o, layer_name);
910 if (!array_is_key(table, (char *) node->name)) continue;
911 }
912
913 property_name = buffer_init();
914
915 /* property name to update */
916 if (!strcmp((char *) node->name, "Name")) {
917 content = xmlNodeGetContent(node);
918 buffer_add_str(property_name, (char *) content);
919 xmlFree(content);
920 buffer_add_str(sql, "\"");
921 l = list_init();
922 list_add_by_copy(l, layer_name);
923 property_name = wfs_request_remove_prop_ns_prefix(o, property_name, l);
924 list_free(l);
925 escaped = ows_psql_escape_string(o, property_name->buf);
926 if (escaped) {
927 buffer_add_str(sql, escaped);
928 free(escaped);
929 }
930 buffer_add_str(sql, "\"");
931 }
932
933 buffer_add_str(sql, " = ");
934 node = node->next;
935
936 /* jump to the next element if there are spaces */
937 if (node && node->type != XML_ELEMENT_NODE) node = node->next;
938
939 /* replacement value is optional, set to NULL if not defined */
940 if (!node) buffer_add_str(sql, "NULL");
941 else if (!strcmp((char *) node->name, "Value")) {
942 if (ows_psql_is_geometry_column(o, layer_name, property_name)) {
943 elemt = node->children;
944
945 /* jump to the next element if there are spaces */
946 while (elemt->type != XML_ELEMENT_NODE) elemt = elemt->next;
947
948 if (!strcmp((char *) elemt->name, "Box") ||
949 !strcmp((char *) elemt->name, "Envelope")) {
950
952 fe->sql = buffer_init();
953 fe->sql = fe_envelope(o, typename, fe, fe->sql, elemt);
954
955 if (fe->error_code != FE_NO_ERROR) {
956 result = fill_fe_error(o, fe);
957 buffer_free(values);
958 buffer_free(sql);
959 buffer_free(typename);
960 buffer_free(property_name);
962 if (srs_root) ows_srs_free(srs_root);
963 return result;
964 }
965
967 buffer_copy(values, fe->sql);
968
969 } else if (!strcmp((char *) elemt->name, "Null")) {
970 buffer_add_str(values, "''");
971 } else {
972 gml = ows_psql_gml_to_sql(o, elemt, srs_root);
973 if (gml) {
974 buffer_add_str(values, "'");
975 buffer_copy(values, gml);
976 buffer_add_str(values, "'");
977 buffer_free(gml);
978 } else {
979 buffer_free(values);
980 buffer_free(typename);
981 buffer_free(property_name);
982 buffer_free(sql);
983 if (srs_root) ows_srs_free(srs_root);
984 result = buffer_from_str("Invalid GML Geometry");
985 return result;
986 }
987 }
988 } else values = wfs_retrieve_value(o, wr, values, xmldoc, node);
989
990 buffer_copy(sql, values);
991 }
992 buffer_free(property_name);
993 }
994
995 if (!strcmp((char *) n->name, "Filter")) {
996 buffer_add_str(sql, " WHERE ");
997 xmlstring = buffer_init();
998 xmlstring = cgi_add_xml_into_buffer(xmlstring, n);
999
1000 filter = filter_encoding_init();
1001 filter = fe_filter(o, filter, typename, xmlstring);
1002
1003 /* check if filter returned an error */
1004 if (filter->error_code != FE_NO_ERROR) {
1005 result = fill_fe_error(o, filter);
1006 buffer_free(xmlstring);
1007 filter_encoding_free(filter);
1008 buffer_free(values);
1009 buffer_free(sql);
1010 buffer_free(typename);
1011 if (srs_root) ows_srs_free(srs_root);
1012 return result;
1013
1014 } else {
1015 buffer_copy(sql, filter->sql);
1016 buffer_free(xmlstring);
1017 filter_encoding_free(filter);
1018 }
1019 }
1020 }
1021
1022 if (n->next && !strcmp((char *) n->next->name, "Property")) buffer_add_str(sql, ",");
1023
1024 buffer_free(values);
1025 }
1026
1027 buffer_add_str(sql, "; ");
1028 /* run the request to update the specified features */
1029 result = wfs_execute_transaction_request(o, wr, sql);
1030
1031 buffer_free(typename);
1032 buffer_free(sql);
1033 if (srs_root) ows_srs_free(srs_root);
1034
1035 return result;
1036}
1037
1038
1039/*
1040 * Parse XML operations to execute each transaction operation
1041 */
1043{
1044 xmlDocPtr xmldoc;
1045 xmlNodePtr n;
1046 xmlAttr *att;
1047 xmlChar *content;
1048
1049 buffer *sql, *result, *end_transaction, *locator;
1050
1051 assert(o);
1052 assert(wr);
1053 assert(op);
1054
1055 sql = buffer_init();
1056 locator = buffer_init();
1057 wr->insert_results = alist_init();
1058 content = NULL;
1059
1060 xmldoc = xmlParseMemory(op->buf, op->use);
1061
1062 if (!xmldoc) {
1063 xmlFreeDoc(xmldoc);
1064 wfs_error(o, wr, WFS_ERROR_NO_MATCHING, "xml isn't valid", "transaction");
1065 return;
1066 }
1067
1068 /* jump to the next element if there are spaces */
1069 n = xmldoc->children;
1070 while (n->type != XML_ELEMENT_NODE) n = n->next;
1071 n = n->children;
1072 while (n->type != XML_ELEMENT_NODE) n = n->next; /* FIXME really ? */
1073
1074 /* initialize the transaction inside postgresql */
1075 buffer_add_str(sql, "BEGIN;");
1076 result = wfs_execute_transaction_request(o, wr, sql);
1077
1078 buffer_empty(result);
1079 buffer_add_str(result, "PGRES_COMMAND_OK");
1080 buffer_empty(sql);
1081
1082 /* go through the operations while transaction is successful */
1083 for ( /* empty */ ; n && (buffer_cmp(result, "PGRES_COMMAND_OK")) ; n = n->next) {
1084 if (n->type != XML_ELEMENT_NODE) continue;
1085
1086 if (!strcmp((char *) n->name, "Insert")) {
1087 buffer_free(result);
1088 result = wfs_insert_xml(o, wr, xmldoc, n);
1089 } else if (!strcmp((char *) n->name, "Delete")) {
1090 buffer_free(result);
1091 result = wfs_delete_xml(o, wr, n);
1092 } else if (!strcmp((char *) n->name, "Update")) {
1093 buffer_free(result);
1094 result = wfs_update_xml(o, wr, xmldoc, n);
1095 }
1096
1097 /* fill locator only if transaction failed */
1098 if (!buffer_cmp(result, "PGRES_COMMAND_OK")) {
1099 /* fill locator with handle attribute if specified
1100 else with transaction name */
1101 if (n->properties) {
1102 att = n->properties;
1103
1104 if (!strcmp((char *) att->name, "handle")) {
1105 content = xmlNodeGetContent(att->children);
1106 buffer_add_str(locator, (char *) content);
1107 xmlFree(content);
1108 } else buffer_add_str(locator, (char *) n->name);
1109 } else buffer_add_str(locator, (char *) n->name);
1110 }
1111 }
1112
1113 /* end the transaction according to the result */
1114 if (buffer_cmp(result, "PGRES_COMMAND_OK")) buffer_add_str(sql, "COMMIT;");
1115 else buffer_add_str(sql, "ROLLBACK;");
1116
1117 end_transaction = wfs_execute_transaction_request(o, wr, sql);
1118 buffer_free(end_transaction);
1119
1120 /* display the xml transaction response */
1121 wfs_transaction_response(o, wr, result, locator);
1122
1123 buffer_free(sql);
1124 buffer_free(result);
1125 buffer_free(locator);
1126
1127 xmlFreeDoc(xmldoc);
1128}
void buffer_add(buffer *buf, char c)
Definition buffer.c:123
int ows_version_get(ows_version *v)
void list_add_by_copy(list *l, buffer *value)
Definition list.c:187
void buffer_empty(buffer *buf)
Definition buffer.c:100
filter_encoding * fe_filter(ows *o, filter_encoding *fe, buffer *typename, buffer *xmlchar)
Definition fe_filter.c:353
buffer * wfs_request_remove_prop_ns_prefix(ows *o, buffer *prop, list *layer_name)
buffer * fill_fe_error(ows *o, filter_encoding *fe)
Definition fe_error.c:79
PGresult * ows_psql_exec(ows *o, const char *sql)
Definition ows_psql.c:56
buffer * ows_psql_gml_to_sql(ows *o, xmlNodePtr n, const ows_srs *parent_srs)
Definition ows_psql.c:734
void buffer_copy(buffer *dest, const buffer *src)
Definition buffer.c:350
bool array_is_value(const array *a, const char *value)
Definition array.c:125
void fe_error(ows *o, filter_encoding *fe)
Definition fe_error.c:34
filter_encoding * filter_encoding_init()
Definition fe_filter.c:35
ows_srs * ows_srs_init()
Definition ows_srs.c:37
bool buffer_cmp(const buffer *buf, const char *str)
Definition buffer.c:290
buffer * array_get_key(const array *a, const char *value)
Definition array.c:170
buffer * fe_envelope(ows *o, buffer *typename, filter_encoding *fe, buffer *envelope, xmlNodePtr n)
bool cgi_method_get()
Definition cgi_request.c:42
void list_free(list *l)
Definition list.c:54
void buffer_add_str(buffer *buf, const char *str)
Definition buffer.c:254
list * list_init()
Definition list.c:36
bool ows_srs_set_from_srsname(ows *o, ows_srs *s, const char *srsname)
Definition ows_srs.c:303
buffer * cgi_add_xml_into_buffer(buffer *element, xmlNodePtr n)
char * ows_psql_escape_string(ows *o, const char *content)
Definition ows_psql.c:840
array * ows_layer_list_namespaces(ows_layer_list *ll)
Definition ows_layer.c:228
buffer * ows_psql_id_column(ows *o, buffer *layer_name)
Definition ows_psql.c:36
void wfs_error(ows *o, wfs_request *wf, enum wfs_error_code code, char *message, char *locator)
Definition wfs_error.c:124
void ows_error(ows *o, enum ows_error_code code, char *message, char *locator)
Definition ows_error.c:71
void array_free(array *a)
Definition array.c:53
void filter_encoding_free(filter_encoding *fe)
Definition fe_filter.c:54
void buffer_add_head_str(buffer *buf, char *str)
Definition buffer.c:239
buffer * buffer_replace(buffer *buf, char *before, char *after)
Definition buffer.c:412
bool array_is_key(const array *a, const char *key)
Definition array.c:105
array * ows_psql_describe_table(ows *o, buffer *layer_name)
Definition ows_psql.c:373
buffer * buffer_from_str(const char *str)
Definition buffer.c:202
void buffer_free(buffer *buf)
Definition buffer.c:83
void buffer_shift(buffer *buf, size_t len)
Definition buffer.c:392
buffer * ows_layer_ns_prefix(ows_layer_list *ll, buffer *layer_name_prefix)
Definition ows_layer.c:408
void alist_add(alist *al, buffer *key, buffer *value)
Definition alist.c:83
bool ows_psql_is_geometry_column(ows *o, buffer *layer_name, buffer *column)
Definition ows_psql.c:164
buffer * ows_layer_ns_uri(ows_layer_list *ll, buffer *ns_prefix)
Definition ows_layer.c:424
buffer * ows_psql_generate_id(ows *o, buffer *layer_name)
Definition ows_psql.c:535
void ows_srs_free(ows_srs *c)
Definition ows_srs.c:76
alist * alist_init()
Definition alist.c:39
buffer * buffer_init()
Definition buffer.c:61
buffer * ows_psql_table_name(ows *o, buffer *layer_name)
Definition ows_psql.c:116
bool ows_layer_writable(const ows_layer_list *ll, const buffer *name)
Definition ows_layer.c:175
list * list_explode(char separator, const buffer *value)
Definition list.c:296
buffer * fe_kvp_featureid(ows *o, wfs_request *wr, buffer *layer_name, list *fid)
Definition fe_filter.c:494
bool check_regexp(const char *str_request, const char *str_regex)
Definition regexp.c:36
buffer * fe_kvp_bbox(ows *o, wfs_request *wr, buffer *layer_name, ows_bbox *bbox)
Definition fe_filter.c:420
buffer * ows_layer_prefix_to_uri(ows_layer_list *ll, buffer *layer_name_prefix)
Definition ows_layer.c:343
buffer * ows_psql_schema_name(ows *o, buffer *layer_name)
Definition ows_psql.c:96
@ FE_NO_ERROR
Definition ows_struct.h:328
@ WFS_ERROR_INVALID_PARAMETER
Definition ows_struct.h:265
@ WFS_ERROR_NO_MATCHING
Definition ows_struct.h:264
@ WFS_ERROR_MISSING_PARAMETER
Definition ows_struct.h:266
wfs_insert_idgen
Definition ows_struct.h:289
@ WFS_GENERATE_NEW
Definition ows_struct.h:290
@ WFS_REPLACE_DUPLICATE
Definition ows_struct.h:292
@ WFS_USE_EXISTING
Definition ows_struct.h:291
@ OWS_ERROR_FORBIDDEN_CHARACTER
Definition ows_struct.h:168
wfs_request
Definition ows_struct.h:269
buffer * key
Definition ows_struct.h:70
list * value
Definition ows_struct.h:71
struct Alist_node * next
Definition ows_struct.h:72
size_t size
size used for data
Definition ows_struct.h:37
char * buf
size to next realloc
Definition ows_struct.h:39
size_t use
Definition ows_struct.h:36
enum fe_error_code error_code
Definition ows_struct.h:346
struct List_node * next
Definition ows_struct.h:45
buffer * value
Definition ows_struct.h:44
unsigned int size
Definition ows_struct.h:52
list_node * last
Definition ows_struct.h:51
list_node * first
Definition ows_struct.h:50
struct Mlist_node * next
Definition ows_struct.h:58
list * value
Definition ows_struct.h:57
ows_version * version
Definition ows_struct.h:353
ows_request * request
Definition ows_struct.h:403
buffer * encoding
Definition ows_struct.h:375
ows_layer_list * layers
Definition ows_struct.h:402
FILE * output
Definition ows_struct.h:382
static buffer * wfs_execute_transaction_request(ows *o, wfs_request *wr, buffer *sql)
static void wfs_transaction_insert_result(ows *o, wfs_request *wr, buffer *result)
static buffer * wfs_retrieve_value(ows *o, wfs_request *wr, buffer *value, xmlDocPtr xmldoc, xmlNodePtr n)
void wfs_delete(ows *o, wfs_request *wr)
static void wfs_transaction_result(ows *o, wfs_request *wr, buffer *result, buffer *locator)
void wfs_parse_operation(ows *o, wfs_request *wr, buffer *op)
static buffer * wfs_delete_xml(ows *o, wfs_request *wr, xmlNodePtr n)
static buffer * wfs_update_xml(ows *o, wfs_request *wr, xmlDocPtr xmldoc, xmlNodePtr n)
static buffer * wfs_retrieve_typename(ows *o, wfs_request *wr, xmlNodePtr n)
static void wfs_transaction_response(ows *o, wfs_request *wr, buffer *result, buffer *locator)
static buffer * wfs_insert_xml(ows *o, wfs_request *wr, xmlDocPtr xmldoc, xmlNodePtr n)
static void wfs_transaction_summary(ows *o, wfs_request *wr, buffer *result)

Generated for tinyows by doxygen 1.9.7