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 <time.h>
29
30 #include "ows.h"
31
32
33 /*
34 * Return the name of the id column from table matching layer name
35 */
ows_psql_id_column(ows * o,buffer * layer_name)36 buffer *ows_psql_id_column(ows * o, buffer * layer_name)
37 {
38 ows_layer_node *ln = NULL;
39
40 assert(o);
41 assert(o->layers);
42 assert(layer_name);
43
44 for (ln = o->layers->first ; ln ; ln = ln->next)
45 if (ln->layer->name && ln->layer->storage
46 && !strcmp(ln->layer->name->buf, layer_name->buf))
47 return ln->layer->storage->pkey;
48
49 return NULL;
50 }
51
52
53 /*
54 * Execute an SQL request
55 */
ows_psql_exec(ows * o,const char * sql)56 PGresult * ows_psql_exec(ows *o, const char *sql)
57 {
58 PGresult* res;
59
60 assert(o);
61 assert(sql);
62 assert(o->pg);
63
64 ows_log(o, 8, sql);
65 res = PQexecParams(o->pg, sql, 0, NULL, NULL, NULL, NULL, 0);
66 if (strlen(PQresultErrorMessage(res)))
67 ows_log(o, 1, PQresultErrorMessage(res));
68
69 return res;
70 }
71
72
73 /*
74 * Return the column number of the id column from table matching layer name
75 * (needed in wfs_get_feature only)
76 */
ows_psql_column_number_id_column(ows * o,buffer * layer_name)77 int ows_psql_column_number_id_column(ows * o, buffer * layer_name)
78 {
79 ows_layer_node *ln = NULL;
80
81 assert(o);
82 assert(o->layers);
83 assert(layer_name);
84
85 for (ln = o->layers->first ; ln ; ln = ln->next)
86 if (ln->layer->name && ln->layer->storage
87 && !strcmp(ln->layer->name->buf, layer_name->buf))
88 return ln->layer->storage->pkey_column_number;
89
90 return -1;
91 }
92
93
94 /*
95 * Return geometry columns from the table matching layer name
96 */
ows_psql_geometry_column(ows * o,buffer * layer_name)97 list *ows_psql_geometry_column(ows * o, buffer * layer_name)
98 {
99 ows_layer_node *ln = NULL;
100
101 assert(o);
102 assert(o->layers);
103 assert(layer_name);
104
105 for (ln = o->layers->first ; ln ; ln = ln->next)
106 if (ln->layer->name && ln->layer->storage
107 && !strcmp(ln->layer->name->buf, layer_name->buf))
108 return ln->layer->storage->geom_columns;
109
110 return NULL;
111 }
112
113
114 /*
115 * Return schema name from a given layer
116 */
ows_psql_schema_name(ows * o,buffer * layer_name)117 buffer *ows_psql_schema_name(ows * o, buffer * layer_name)
118 {
119 ows_layer_node *ln = NULL;
120
121 assert(o);
122 assert(o->layers);
123 assert(layer_name);
124
125 for (ln = o->layers->first ; ln ; ln = ln->next)
126 if (ln->layer->name && ln->layer->storage
127 && !strcmp(ln->layer->name->buf, layer_name->buf))
128 return ln->layer->storage->schema;
129
130 return NULL;
131 }
132
133
134 /*
135 * Return table name from a given layer
136 */
ows_psql_table_name(ows * o,buffer * layer_name)137 buffer *ows_psql_table_name(ows * o, buffer * layer_name)
138 {
139 ows_layer_node *ln = NULL;
140
141 assert(o);
142 assert(o->layers);
143 assert(layer_name);
144
145 for (ln = o->layers->first ; ln ; ln = ln->next)
146 if (ln->layer->name && ln->layer->storage
147 && !strcmp(ln->layer->name->buf, layer_name->buf))
148 return ln->layer->storage->table;
149
150 return NULL;
151 }
152
153
154 /*
155 * Check if a given WKT geometry is or not valid
156 */
ows_psql_is_geometry_valid(ows * o,buffer * geom)157 bool ows_psql_is_geometry_valid(ows * o, buffer * geom)
158 {
159 buffer *sql;
160 PGresult *res;
161 bool ret = false;
162
163 assert(o);
164 assert(geom);
165
166 sql = buffer_init();
167 buffer_add_str(sql, "SELECT ST_isvalid(ST_geometryfromtext('");
168 buffer_copy(sql, geom);
169 buffer_add_str(sql, "', -1));");
170
171 res = ows_psql_exec(o, sql->buf);
172 buffer_free(sql);
173
174 if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1
175 && (char) PQgetvalue(res, 0, 0)[0] == 't') ret = true;
176
177 PQclear(res);
178 return ret;
179 }
180
181
182 /*
183 * Check if the specified column from a layer_name is (or not) a geometry column
184 */
ows_psql_is_geometry_column(ows * o,buffer * layer_name,buffer * column)185 bool ows_psql_is_geometry_column(ows * o, buffer * layer_name, buffer * column)
186 {
187 ows_layer_node *ln;
188
189 assert(o);
190 assert(o->layers);
191 assert(layer_name);
192 assert(column);
193
194 for (ln = o->layers->first ; ln ; ln = ln->next)
195 if (ln->layer->name && ln->layer->storage
196 && !strcmp(ln->layer->name->buf, layer_name->buf))
197 return in_list(ln->layer->storage->geom_columns, column);
198
199 return false;
200 }
201
202
203 /*
204 * Return a list of not null properties from the table matching layer name
205 */
ows_psql_not_null_properties(ows * o,buffer * layer_name)206 list *ows_psql_not_null_properties(ows * o, buffer * layer_name)
207 {
208 ows_layer_node *ln;
209
210 assert(o);
211 assert(o->layers);
212 assert(layer_name);
213
214 for (ln = o->layers->first ; ln ; ln = ln->next)
215 if (ln->layer->name && ln->layer->storage
216 && !strcmp(ln->layer->name->buf, layer_name->buf))
217 return ln->layer->storage->not_null_columns;
218
219 return NULL;
220 }
221
222
223 /*
224 * Returns the constraint name for a table column.
225 * Used to return enumeration constraints in describe feature type request.
226 */
ows_psql_column_constraint_name(ows * o,buffer * column_name,buffer * table_name)227 buffer *ows_psql_column_constraint_name(ows * o, buffer * column_name, buffer * table_name)
228 {
229 buffer *sql;
230 PGresult *res;
231 buffer *constraint_name;
232
233 constraint_name = buffer_init();
234
235 assert(o);
236 assert(column_name);
237 assert(table_name);
238
239 sql = buffer_init();
240
241 buffer_add_str(sql, "SELECT constraint_name FROM information_schema.constraint_column_usage WHERE table_name = '");
242 buffer_add_str(sql, table_name->buf);
243 buffer_add_str(sql, "' AND column_name='");
244 buffer_add_str(sql, column_name->buf);
245 buffer_add_str(sql, "'");
246
247 res = ows_psql_exec(o, sql->buf);
248 buffer_free(sql);
249
250 if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) {
251 PQclear(res);
252 return constraint_name;
253 }
254
255 buffer_add_str(constraint_name, PQgetvalue(res, 0, 0));
256 PQclear(res);
257
258 return constraint_name;
259 }
260
261 /*
262 * Returns the list of possible values for a column according to the constraint value.
263 * Used to return enumeration constraints in describe feature type request.
264 */
ows_psql_column_check_constraint(ows * o,buffer * constraint_name)265 list *ows_psql_column_check_constraint(ows * o, buffer * constraint_name)
266 {
267 buffer *sql;
268 PGresult *res;
269 list *constraints;
270 buffer *constraint_value;
271 buffer *buf;
272 size_t i;
273 size_t j;
274
275 constraints = list_init();
276 constraint_value = buffer_init();
277
278 assert(o);
279 assert(constraint_name);
280
281 sql = buffer_init();
282
283 buffer_add_str(sql, "SELECT check_clause FROM information_schema.check_constraints WHERE constraint_name = '");
284 buffer_add_str(sql, constraint_name->buf);
285 buffer_add_str(sql, "'");
286
287 res = ows_psql_exec(o, sql->buf);
288
289 if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) {
290 PQclear(res);
291 return constraints;
292 }
293
294 buffer_add_str(constraint_value, PQgetvalue(res, 0, 0));
295 PQclear(res);
296
297 j=0;
298 buf = buffer_init();
299 for (i = 0; constraint_value->buf[i] != '\0'; i++) {
300 if(constraint_value->buf[i] == '\'') {
301 j++;
302 if(j%2==1) {
303 buf = buffer_init();
304 } else {
305 list_add(constraints, buf);
306 }
307 } else if(j%2==1)
308 buffer_add(buf, constraint_value->buf[i]);
309 }
310
311 return constraints;
312 }
313
314
315 /*
316 * Return the column's name matching the specified number from table
317 * (Only use in specific FE position function, so not directly inside
318 * storage handle mechanism)
319 */
ows_psql_column_name(ows * o,buffer * layer_name,int number)320 buffer *ows_psql_column_name(ows * o, buffer * layer_name, int number)
321 {
322 buffer *sql;
323 PGresult *res;
324 buffer *column;
325
326 assert(o);
327 assert(layer_name);
328
329 sql = buffer_init();
330 column = buffer_init();
331
332 buffer_add_str(sql, "SELECT a.attname FROM pg_class c, pg_attribute a, pg_type t WHERE c.relname ='");
333 buffer_copy(sql, layer_name);
334 buffer_add_str(sql, "' AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid AND a.attnum = ");
335 buffer_add_int(sql, number);
336
337 res = ows_psql_exec(o, sql->buf);
338 buffer_free(sql);
339
340 if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) {
341 PQclear(res);
342 return column;
343 }
344
345 buffer_add_str(column, PQgetvalue(res, 0, 0));
346 PQclear(res);
347
348 return column;
349 }
350
351 /*
352 * Returns the column character_maximum_length value from the database
353 * information schema.
354 * Used to return maxLength constraint in describe feature type request.
355 */
ows_psql_column_character_maximum_length(ows * o,buffer * column_name,buffer * table_name)356 buffer *ows_psql_column_character_maximum_length(ows * o, buffer * column_name, buffer * table_name)
357 {
358 buffer *sql;
359 PGresult *res;
360 buffer *character_maximum_length;
361
362 character_maximum_length = buffer_init();
363
364 assert(o);
365 assert(column_name);
366 assert(table_name);
367
368 sql = buffer_init();
369
370 buffer_add_str(sql, "SELECT character_maximum_length FROM information_schema.columns WHERE table_name = '");
371 buffer_add_str(sql, table_name->buf);
372 buffer_add_str(sql, "' and column_name = '");
373 buffer_add_str(sql, column_name->buf);
374 buffer_add_str(sql, "'");
375
376 res = ows_psql_exec(o, sql->buf);
377 buffer_free(sql);
378
379 if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) {
380 PQclear(res);
381 return character_maximum_length;
382 }
383
384 buffer_add_str(character_maximum_length, PQgetvalue(res, 0, 0));
385 PQclear(res);
386
387 return character_maximum_length;
388 }
389
390
391 /*
392 * Retrieve description of a table matching a given layer name
393 */
ows_psql_describe_table(ows * o,buffer * layer_name)394 array *ows_psql_describe_table(ows * o, buffer * layer_name)
395 {
396 ows_layer_node *ln = NULL;
397
398 assert(o);
399 assert(o->layers);
400 assert(layer_name);
401
402 for (ln = o->layers->first ; ln ; ln = ln->next)
403 if (ln->layer->name && ln->layer->storage
404 && !strcmp(ln->layer->name->buf, layer_name->buf))
405 return ln->layer->storage->attributes;
406
407 return NULL;
408 }
409
410
411 /*
412 * Retrieve an ows_version, related to current PostGIS version.
413 */
ows_psql_postgis_version(ows * o)414 ows_version * ows_psql_postgis_version(ows *o)
415 {
416 list *l;
417 PGresult * res;
418 ows_version * v = NULL;
419
420 res = ows_psql_exec(o, "SELECT substr(postgis_full_version(), 10, 5)");
421 if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) {
422 PQclear(res);
423 return NULL;
424 }
425
426 l = list_explode_str('.', (char *) PQgetvalue(res, 0, 0));
427
428 if ( l->size == 3
429 && check_regexp(l->first->value->buf, "^[0-9]+$")
430 && check_regexp(l->first->next->value->buf, "^[0-9]+$")
431 && check_regexp(l->last->value->buf, "^[0-9]+$") ) {
432 v = ows_version_init();
433 v->major = atoi(l->first->value->buf);
434 v->minor = atoi(l->first->next->value->buf);
435 v->release = atoi(l->last->value->buf);
436 }
437
438 list_free(l);
439 PQclear(res);
440 return v;
441 }
442
443
444 /*
445 * TODO
446 */
ows_psql_is_numeric(buffer * type)447 bool ows_psql_is_numeric(buffer * type)
448 {
449 assert(type);
450
451 if (buffer_cmp(type, "int2")) return true;
452 if (buffer_cmp(type, "int4")) return true;
453 if (buffer_cmp(type, "int8")) return true;
454 if (buffer_cmp(type, "float4")) return true;
455 if (buffer_cmp(type, "float8")) return true;
456 if (buffer_ncmp(type, "numeric", 7)) return true;
457
458 return false;
459 }
460
461
462 /*
463 * Convert a PostgreSql type to a valid
464 * OGC XMLSchema's type
465 */
ows_psql_to_xsd(buffer * type,enum wfs_format format)466 char *ows_psql_to_xsd(buffer * type, enum wfs_format format)
467 {
468 int gml_version = 311;
469
470 assert(type);
471 assert(format);
472
473 if (format == WFS_GML212) gml_version = 212;
474
475 if (buffer_case_cmp(type, "geometry")) return "gml:GeometryPropertyType";
476 if (buffer_cmp(type, "geography")) return "gml:GeometryPropertyType";
477 if (buffer_cmp(type, "int2")) return "short";
478 if (buffer_cmp(type, "int4")) return "int";
479 if (buffer_cmp(type, "int8")) return "long";
480 if (buffer_cmp(type, "float4")) return "float";
481 if (buffer_cmp(type, "float8")) return "double";
482 if (buffer_cmp(type, "bool")) return "boolean";
483 if (buffer_cmp(type, "bytea")) return "byte";
484 if (buffer_cmp(type, "date")) return "date";
485 if (buffer_cmp(type, "time")) return "time";
486 if (buffer_ncmp(type, "numeric", 7)) return "decimal";
487 if (buffer_ncmp(type, "timestamp", 9)) return "dateTime"; /* Could be also timestamptz */
488 if (buffer_cmp(type, "POINT")) return "gml:PointPropertyType";
489 if (buffer_cmp(type, "LINESTRING") && gml_version == 212) return "gml:LineStringPropertyType";
490 if (buffer_cmp(type, "LINESTRING") && gml_version >= 311) return "gml:CurvePropertyType";
491 if (buffer_cmp(type, "POLYGON") && gml_version == 212) return "gml:PolygonPropertyType";
492 if (buffer_cmp(type, "POLYGON") && gml_version >= 311) return "gml:SurfacePropertyType";
493 if (buffer_cmp(type, "TRIANGLE")) return "gml:TrianglePropertyType";
494 if (buffer_cmp(type, "MULTIPOINT")) return "gml:MultiPointPropertyType";
495 if (buffer_cmp(type, "MULTILINESTRING") && gml_version == 212) return "gml:MultiLineStringPropertyType";
496 if (buffer_cmp(type, "MULTILINESTRING") && gml_version >= 311) return "gml:MultiCurvePropertyType";
497 if (buffer_cmp(type, "MULTIPOLYGON") && gml_version == 212) return "gml:MultiPolygonPropertyType";
498 if (buffer_cmp(type, "MULTIPOLYGON") && gml_version >= 311) return "gml:MultiSurfacePropertyType";
499 if (buffer_cmp(type, "TIN")) return "gml:TriangulatedSurfacePropertyType";
500 if (buffer_cmp(type, "POLYHEDRALSURFACE")) return "gml:PolyhedralSurfacePropertyType";
501 if (buffer_cmp(type, "GEOMETRYCOLLECTION")) return "gml:MultiGeometryPropertyType";
502
503 return "string";
504 }
505
506
507 /*
508 * Convert a date from PostgreSQL to XML
509 */
ows_psql_timestamp_to_xml_time(char * timestamp)510 buffer *ows_psql_timestamp_to_xml_time(char *timestamp)
511 {
512 buffer *time;
513
514 assert(timestamp);
515
516 time = buffer_init();
517 buffer_add_str(time, timestamp);
518 if (!time->use) return time;
519
520 buffer_replace(time, " ", "T");
521
522 if (check_regexp(time->buf, "\\+"))
523 buffer_add_str(time, ":00");
524 else
525 buffer_add_str(time, "Z");
526
527 return time;
528 }
529
530
531 /*
532 * Return the type of the property passed in parameter
533 */
ows_psql_type(ows * o,buffer * layer_name,buffer * property)534 buffer *ows_psql_type(ows * o, buffer * layer_name, buffer * property)
535 {
536 ows_layer_node *ln;
537
538 assert(o);
539 assert(o->layers);
540 assert(layer_name);
541 assert(property);
542
543 for (ln = o->layers->first ; ln ; ln = ln->next) {
544 if (ln->layer->name && ln->layer->storage
545 && !strcmp(ln->layer->name->buf, layer_name->buf))
546 return array_get(ln->layer->storage->attributes, property->buf);
547 }
548
549 return NULL;
550 }
551
552
553 /*
554 * Generate a new buffer id supposed to be unique for a given layer name
555 */
ows_psql_generate_id(ows * o,buffer * layer_name)556 buffer *ows_psql_generate_id(ows * o, buffer * layer_name)
557 {
558 ows_layer_node *ln;
559 buffer * id, *sql_id;
560 FILE *fp;
561 PGresult * res;
562 int i, seed_len;
563 char * seed = NULL;
564
565 assert(o);
566 assert(o->layers);
567 assert(layer_name);
568
569 /* Retrieve layer node pointer */
570 for (ln = o->layers->first ; ln ; ln = ln->next) {
571 if (ln->layer->name && ln->layer->storage
572 && !strcmp(ln->layer->name->buf, layer_name->buf)) break;
573 }
574 assert(ln);
575
576 id = buffer_init();
577
578 /* If PK have a sequence in PostgreSQL database,
579 * retrieve next available sequence value
580 */
581 if (ln->layer->storage->pkey_sequence) {
582 sql_id = buffer_init();
583 buffer_add_str(sql_id, "SELECT nextval('");
584 buffer_copy(sql_id, ln->layer->storage->pkey_sequence);
585 buffer_add_str(sql_id, "');");
586 res = ows_psql_exec(o, sql_id->buf);
587 buffer_free(sql_id);
588
589 if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1) {
590 buffer_add_str(id, (char *) PQgetvalue(res, 0, 0));
591 PQclear(res);
592 return id;
593 }
594
595 /* FIXME: Shouldn't we return an error there instead ? */
596 PQclear(res);
597 }
598
599 /* If PK have a DEFAULT in PostgreSQL database,
600 * retrieve next available DEFAULT value
601 */
602 if (ln->layer->storage->pkey_default) {
603 sql_id = buffer_init();
604 buffer_add_str(sql_id, "SELECT ");
605 buffer_copy(sql_id, ln->layer->storage->pkey_default);
606 buffer_add_str(sql_id, ";");
607 res = ows_psql_exec(o, sql_id->buf);
608 buffer_free(sql_id);
609
610 if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1) {
611 buffer_add_str(id, (char *) PQgetvalue(res, 0, 0));
612 PQclear(res);
613 return id;
614 }
615
616 /* FIXME: Shouldn't we return an error there instead ? */
617 PQclear(res);
618 }
619
620 /*
621 * If we don't have a PostgreSQL Sequence, we will try to
622 * generate a pseudo random keystring using /dev/urandom
623 * Will so work only on somes/commons Unix system
624 */
625 seed_len = 6;
626 seed = malloc(sizeof(char) * (seed_len * 3 + 1)); /* multiply by 3 to be able to deal
627 with hex2dec conversion */
628 assert(seed);
629 seed[0] = '\0';
630
631 fp = fopen("/dev/urandom","r");
632 if (fp) {
633 for (i=0 ; i<seed_len ; i++)
634 sprintf(seed,"%s%03d", seed, fgetc(fp));
635 fclose(fp);
636 buffer_add_str(id, seed);
637 free(seed);
638
639 return id;
640 }
641 free(seed);
642
643 /* Case where we not using PostgreSQL sequence,
644 * and OS don't have a /dev/urandom support
645 * This case don't prevent to produce ID collision
646 * Don't use it unless really no others choices !!!
647 */
648 srand((int) (time(NULL) ^ rand() % 1000) + 42);
649 srand((rand() % 1000 ^ rand() % 1000) + 42);
650 buffer_add_int(id, rand());
651
652 return id;
653 }
654
655
656 /*
657 * Return the number of rows returned by the specified requests
658 */
ows_psql_number_features(ows * o,list * from,list * where)659 int ows_psql_number_features(ows * o, list * from, list * where)
660 {
661 buffer *sql;
662 PGresult *res;
663 list_node *ln_from, *ln_where;
664 int nb;
665
666 assert(o);
667 assert(from);
668 assert(where);
669
670 nb = 0;
671
672 /* checks if from list and where list have the same size */
673 if (from->size != where->size) return nb;
674
675
676 for (ln_from = from->first, ln_where = where->first;
677 ln_from;
678 ln_from = ln_from->next, ln_where = ln_where->next) {
679 sql = buffer_init();
680
681 /* execute the request */
682 buffer_add_str(sql, "SELECT count(*) FROM \"");
683 buffer_copy(sql, ln_from->value);
684 buffer_add_str(sql, "\" ");
685 buffer_copy(sql, ln_where->value);
686 res = ows_psql_exec(o, sql->buf);
687 buffer_free(sql);
688
689 if (PQresultStatus(res) != PGRES_TUPLES_OK) {
690 PQclear(res);
691 return -1;
692 }
693 nb = nb + atoi(PQgetvalue(res, 0, 0));
694 PQclear(res);
695 }
696
697 return nb;
698 }
699
700
ows_psql_recursive_parse_gml(ows * o,xmlNodePtr n,xmlNodePtr result)701 static xmlNodePtr ows_psql_recursive_parse_gml(ows * o, xmlNodePtr n, xmlNodePtr result)
702 {
703 xmlNodePtr c;
704
705 assert(o);
706 assert(n);
707
708 if (result) return result; /* avoid recursive loop */
709
710 /* We are looking for the geometry part inside GML doc */
711 for (; n ; n = n->next) {
712
713 if (n->type != XML_ELEMENT_NODE) continue;
714
715 /* Check on namespace GML 3 and GML 3.2 */
716 if ( strcmp("http://www.opengis.net/gml", (char *) n->ns->href)
717 && strcmp("http://www.opengis.net/gml/3.2", (char *) n->ns->href)) continue;
718
719 /* GML SF Geometries Types */
720 if ( !strcmp((char *) n->name, "Point")
721 || !strcmp((char *) n->name, "LineString")
722 || !strcmp((char *) n->name, "LinearRing")
723 || !strcmp((char *) n->name, "Curve")
724 || !strcmp((char *) n->name, "Polygon")
725 || !strcmp((char *) n->name, "Triangle")
726 || !strcmp((char *) n->name, "Surface")
727 || !strcmp((char *) n->name, "MultiPoint")
728 || !strcmp((char *) n->name, "MultiLineString")
729 || !strcmp((char *) n->name, "MultiCurve")
730 || !strcmp((char *) n->name, "MultiPolygon")
731 || !strcmp((char *) n->name, "MultiSurface")
732 || !strcmp((char *) n->name, "PolyhedralSurface")
733 || !strcmp((char *) n->name, "Tin")
734 || !strcmp((char *) n->name, "TriangulatedSurface")
735 || !strcmp((char *) n->name, "MultiGeometry")) return n;
736
737 /* Recursive exploration */
738 if (n->children)
739 for (c = n->children ; c ; c = c->next)
740 if ((result = ows_psql_recursive_parse_gml(o, c, NULL)))
741 return result;
742 }
743
744 return NULL;
745 }
746
747
748 /*
749 * Transform a GML geometry to PostGIS EWKT
750 * Return NULL on error
751 */
ows_psql_gml_to_sql(ows * o,xmlNodePtr n,int srid)752 buffer * ows_psql_gml_to_sql(ows * o, xmlNodePtr n, int srid)
753 {
754 PGresult *res;
755 xmlNodePtr g;
756 buffer *result, *sql, *gml;
757
758 assert(o);
759 assert(n);
760
761 g = ows_psql_recursive_parse_gml(o, n, NULL);
762 if (!g) return NULL; /* No Geometry founded in GML doc */
763
764 /* Retrieve the sub doc and launch GML parse via PostGIS */
765 gml = buffer_init();
766 cgi_add_xml_into_buffer(gml, g);
767
768 sql = buffer_init();
769 buffer_add_str(sql, "SELECT ST_GeomFromGML('");
770 buffer_add_str(sql, gml->buf);
771
772 if (ows_version_get(o->postgis_version) >= 200) {
773 buffer_add_str(sql, "',");
774 buffer_add_int(sql, srid);
775 buffer_add_str(sql, ")");
776 } else {
777 /* Means PostGIS 1.5 */
778 buffer_add_str(sql, "')");
779 }
780
781 res = ows_psql_exec(o, sql->buf);
782 buffer_free(gml);
783
784 /* GML Parse errors cases */
785 if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) {
786 buffer_free(sql);
787 PQclear(res);
788 return NULL;
789 }
790
791 result = buffer_init();
792 buffer_add_str(result, PQgetvalue(res, 0, 0));
793 PQclear(res);
794
795 /* Check if geometry is valid */
796 if (o->check_valid_geom) {
797
798 buffer_empty(sql);
799 buffer_add_str(sql, "SELECT ST_IsValid('");
800 buffer_add_str(sql, result->buf);
801 buffer_add_str(sql, "')");
802
803 res = ows_psql_exec(o, sql->buf);
804
805 if ( PQresultStatus(res) != PGRES_TUPLES_OK
806 || PQntuples(res) != 1
807 || (char) PQgetvalue(res, 0, 0)[0] != 't') {
808 buffer_free(sql);
809 buffer_free(result);
810 PQclear(res);
811 return NULL;
812 }
813 PQclear(res);
814 }
815
816 buffer_free(sql);
817
818 return result;
819 }
820
821
822 /*
823 * Use PostgreSQL native handling to escape string
824 * string returned must be freed by the caller
825 * return NULL on error
826 */
ows_psql_escape_string(ows * o,const char * content)827 char *ows_psql_escape_string(ows *o, const char *content)
828 {
829 char *content_escaped;
830 int error = 0;
831
832 assert(o);
833 assert(o->pg);
834 assert(content);
835
836 content_escaped = malloc(strlen(content) * 2 + 1);
837 PQescapeStringConn(o->pg, content_escaped, content, strlen(content), &error);
838
839 if (error != 0) return NULL;
840
841 return content_escaped;
842 }
843
844
845 /*
846 * Return SRID from a given geometry
847 */
ows_psql_geometry_srid(ows * o,const char * geom)848 int ows_psql_geometry_srid(ows *o, const char *geom)
849 {
850 int srid;
851 buffer *sql;
852 PGresult *res;
853
854 assert(o);
855 assert(o->pg);
856 assert(geom);
857
858 sql = buffer_from_str("SELECT ST_SRID('");
859 buffer_add_str(sql, geom);
860 buffer_add_str(sql, "'::geometry)");
861
862 res = ows_psql_exec(o, sql->buf);
863
864 if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) srid = -1;
865 else srid = atoi((char *) PQgetvalue(res, 0, 0));
866
867 buffer_free(sql);
868 PQclear(res);
869
870 return srid;
871 }
872
873
874 /*
875 * vim: expandtab sw=4 ts=4
876 */
877