PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwgeom_inout.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * ^copyright^
22 *
23 **********************************************************************/
24
25#include "postgres.h"
26
27#include "../postgis_config.h"
28
29#include <math.h>
30#include <float.h>
31#include <string.h>
32#include <stdio.h>
33#include <assert.h>
34
35#include "access/gist.h"
36#include "access/itup.h"
37
38#include "fmgr.h"
39#include "utils/elog.h"
40#include "mb/pg_wchar.h"
41#include "lib/stringinfo.h" /* for binary input */
42#include "utils/array.h"
43#include "utils/builtins.h"
44#include "utils/lsyscache.h"
45#include "funcapi.h"
46
47#include "liblwgeom.h"
48#include "lwgeom_cache.h"
49#include "lwgeom_pg.h"
50#include "geography.h" /* for lwgeom_valid_typmod */
51#include "lwgeom_transform.h"
52
53
54#include "access/htup_details.h"
55
56
57void elog_ERROR(const char* string);
58
59Datum LWGEOM_in(PG_FUNCTION_ARGS);
60Datum LWGEOM_out(PG_FUNCTION_ARGS);
61Datum LWGEOM_to_text(PG_FUNCTION_ARGS);
62Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS);
63Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS);
64Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS);
65Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS);
66Datum LWGEOM_recv(PG_FUNCTION_ARGS);
67Datum LWGEOM_send(PG_FUNCTION_ARGS);
68Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS);
69Datum WKBFromLWGEOM(PG_FUNCTION_ARGS);
70Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS);
71Datum TWKBFromLWGEOMArray(PG_FUNCTION_ARGS);
72Datum LWGEOMFromTWKB(PG_FUNCTION_ARGS);
73
74/*
75 * LWGEOM_in(cstring)
76 * format is '[SRID=#;]wkt|wkb'
77 * LWGEOM_in( 'SRID=99;POINT(0 0)')
78 * LWGEOM_in( 'POINT(0 0)') --> assumes SRID=SRID_UNKNOWN
79 * LWGEOM_in( 'SRID=99;0101000000000000000000F03F000000000000004')
80 * LWGEOM_in( '0101000000000000000000F03F000000000000004')
81 * LWGEOM_in( '{"type":"Point","coordinates":[1,1]}')
82 * returns a GSERIALIZED object
83 */
85Datum LWGEOM_in(PG_FUNCTION_ARGS)
86{
87 char *input = PG_GETARG_CSTRING(0);
88 int32 geom_typmod = -1;
89 char *str = input;
90 LWGEOM_PARSER_RESULT lwg_parser_result;
91 LWGEOM *lwgeom;
92 GSERIALIZED *ret;
93 int32_t srid = 0;
94
95 if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) {
96 geom_typmod = PG_GETARG_INT32(2);
97 }
98
99 lwgeom_parser_result_init(&lwg_parser_result);
100
101 /* Empty string. */
102 if ( str[0] == '\0' ) {
103 ereport(ERROR,(errmsg("parse error - invalid geometry")));
104 PG_RETURN_NULL();
105 }
106
107 /* Starts with "SRID=" */
108 if( strncasecmp(str,"SRID=",5) == 0 )
109 {
110 /* Roll forward to semi-colon */
111 char *tmp = str;
112 while ( tmp && *tmp != ';' )
113 tmp++;
114
115 /* Check next character to see if we have WKB */
116 if ( tmp && *(tmp+1) == '0' )
117 {
118 /* Null terminate the SRID= string */
119 *tmp = '\0';
120 /* Set str to the start of the real WKB */
121 str = tmp + 1;
122 /* Move tmp to the start of the numeric part */
123 tmp = input + 5;
124 /* Parse out the SRID number */
125 srid = atoi(tmp);
126 }
127 }
128
129 /* WKB? Let's find out. */
130 if ( str[0] == '0' )
131 {
132 size_t hexsize = strlen(str);
133 unsigned char *wkb = bytes_from_hexbytes(str, hexsize);
134 /* TODO: 20101206: No parser checks! This is inline with current 1.5 behavior, but needs discussion */
135 lwgeom = lwgeom_from_wkb(wkb, hexsize/2, LW_PARSER_CHECK_NONE);
136 /* Parser should throw error, but if not, catch here. */
137 if ( !lwgeom ) PG_RETURN_NULL();
138 /* If we picked up an SRID at the head of the WKB set it manually */
139 if ( srid ) lwgeom_set_srid(lwgeom, srid);
140 /* Add a bbox if necessary */
141 if ( lwgeom_needs_bbox(lwgeom) ) lwgeom_add_bbox(lwgeom);
142 lwfree(wkb);
143 ret = geometry_serialize(lwgeom);
144 lwgeom_free(lwgeom);
145 }
146 else if (str[0] == '{')
147 {
148 char *srs = NULL;
149 lwgeom = lwgeom_from_geojson(str, &srs);
150 if (srs)
151 {
152 srid = GetSRIDCacheBySRS(fcinfo, srs);
153 lwfree(srs);
154 lwgeom_set_srid(lwgeom, srid);
155 }
156 ret = geometry_serialize(lwgeom);
157 lwgeom_free(lwgeom);
158 }
159 /* WKT then. */
160 else
161 {
162 if ( lwgeom_parse_wkt(&lwg_parser_result, str, LW_PARSER_CHECK_ALL) == LW_FAILURE )
163 {
164 PG_PARSER_ERROR(lwg_parser_result);
165 PG_RETURN_NULL();
166 }
167 lwgeom = lwg_parser_result.geom;
168 if ( lwgeom_needs_bbox(lwgeom) )
169 lwgeom_add_bbox(lwgeom);
170 ret = geometry_serialize(lwgeom);
171 lwgeom_parser_result_free(&lwg_parser_result);
172 }
173
174 if ( geom_typmod >= 0 )
175 {
176 ret = postgis_valid_typmod(ret, geom_typmod);
177 POSTGIS_DEBUG(3, "typmod and geometry were consistent");
178 }
179 else
180 {
181 POSTGIS_DEBUG(3, "typmod was -1");
182 }
183
184 /* Don't free the parser result (and hence lwgeom) until we have done */
185 /* the typemod check with lwgeom */
186
187 PG_RETURN_POINTER(ret);
188
189}
190
191/*
192 * LWGEOM_to_latlon(GEOMETRY, text)
193 * NOTE: Geometry must be a point. It is assumed that the coordinates
194 * of the point are in a lat/lon projection, and they will be
195 * normalized in the output to -90-90 and -180-180.
196 *
197 * The text parameter is a format string containing the format for the
198 * resulting text, similar to a date format string. Valid tokens
199 * are "D" for degrees, "M" for minutes, "S" for seconds, and "C" for
200 * cardinal direction (NSEW). DMS tokens may be repeated to indicate
201 * desired width and precision ("SSS.SSSS" means " 1.0023").
202 * "M", "S", and "C" are optional. If "C" is omitted, degrees are
203 * shown with a "-" sign if south or west. If "S" is omitted,
204 * minutes will be shown as decimal with as many digits of precision
205 * as you specify. If "M" is omitted, degrees are shown as decimal
206 * with as many digits precision as you specify.
207 *
208 * If the format string is omitted (null or 0-length) a default
209 * format will be used.
210 *
211 * returns text
212 */
214Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS)
215{
216 /* Get the parameters */
217 GSERIALIZED *pg_lwgeom = PG_GETARG_GSERIALIZED_P(0);
218 text *format_text = PG_GETARG_TEXT_P(1);
219
220 LWGEOM *lwgeom;
221 char *format_str = NULL;
222
223 char * formatted_str;
224 text * formatted_text;
225 char * tmp;
226
227 /* Only supports points. */
228 uint8_t geom_type = gserialized_get_type(pg_lwgeom);
229 if (POINTTYPE != geom_type)
230 {
231 lwpgerror("Only points are supported, you tried type %s.", lwtype_name(geom_type));
232 }
233 /* Convert to LWGEOM type */
234 lwgeom = lwgeom_from_gserialized(pg_lwgeom);
235
236 if (format_text == NULL) {
237 lwpgerror("ST_AsLatLonText: invalid format string (null");
238 PG_RETURN_NULL();
239 }
240
241 if (!lwgeom_isfinite(lwgeom)) {
242 lwpgerror("ST_AsLatLonText: invalid coordinate");
243 PG_RETURN_NULL();
244 }
245
246 format_str = text_to_cstring(format_text);
247 assert(format_str != NULL);
248
249 /* The input string supposedly will be in the database encoding,
250 so convert to UTF-8. */
251 tmp = (char *)pg_do_encoding_conversion(
252 (uint8_t *)format_str, strlen(format_str), GetDatabaseEncoding(), PG_UTF8);
253 assert(tmp != NULL);
254 if ( tmp != format_str ) {
255 pfree(format_str);
256 format_str = tmp;
257 }
258
259 /* Produce the formatted string. */
260 formatted_str = lwpoint_to_latlon((LWPOINT *)lwgeom, format_str);
261 assert(formatted_str != NULL);
262 pfree(format_str);
263
264 /* Convert the formatted string from UTF-8 back to database encoding. */
265 tmp = (char *)pg_do_encoding_conversion(
266 (uint8_t *)formatted_str, strlen(formatted_str),
267 PG_UTF8, GetDatabaseEncoding());
268 assert(tmp != NULL);
269 if ( tmp != formatted_str) {
270 pfree(formatted_str);
271 formatted_str = tmp;
272 }
273
274 /* Convert to the postgres output string type. */
275 formatted_text = cstring_to_text(formatted_str);
276 pfree(formatted_str);
277
278 PG_RETURN_POINTER(formatted_text);
279}
280
281/*
282 * LWGEOM_out(lwgeom) --> cstring
283 * output is 'SRID=#;<wkb in hex form>'
284 * ie. 'SRID=-99;0101000000000000000000F03F0000000000000040'
285 * WKB is machine endian
286 * if SRID=-1, the 'SRID=-1;' will probably not be present.
287 */
289Datum LWGEOM_out(PG_FUNCTION_ARGS)
290{
291 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
292 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
293 PG_RETURN_CSTRING(lwgeom_to_hexwkb_buffer(lwgeom, WKB_EXTENDED));
294}
295
296/*
297 * AsHEXEWKB(geom, string)
298 */
300Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS)
301{
302 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
303 LWGEOM *lwgeom;
304 uint8_t variant = 0;
305
306 /* If user specified endianness, respect it */
307 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
308 {
309 text *type = PG_GETARG_TEXT_P(1);
310
311 if ( ! strncmp(VARDATA(type), "xdr", 3) ||
312 ! strncmp(VARDATA(type), "XDR", 3) )
313 {
315 }
316 else
317 {
319 }
320 }
321
322 /* Create WKB hex string */
323 lwgeom = lwgeom_from_gserialized(geom);
324 PG_RETURN_TEXT_P(lwgeom_to_hexwkb_varlena(lwgeom, variant | WKB_EXTENDED));
325}
326
327
328/*
329 * LWGEOM_to_text(lwgeom) --> text
330 * output is 'SRID=#;<wkb in hex form>'
331 * ie. 'SRID=-99;0101000000000000000000F03F0000000000000040'
332 * WKB is machine endian
333 * if SRID=-1, the 'SRID=-1;' will probably not be present.
334 */
336Datum LWGEOM_to_text(PG_FUNCTION_ARGS)
337{
338 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
339 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
340 PG_RETURN_TEXT_P(lwgeom_to_hexwkb_varlena(lwgeom, WKB_EXTENDED));
341}
342
343/*
344 * LWGEOMFromEWKB(wkb, [SRID] )
345 * NOTE: wkb is in *binary* not hex form.
346 *
347 * NOTE: this function parses EWKB (extended form)
348 * which also contains SRID info.
349 */
351Datum LWGEOMFromEWKB(PG_FUNCTION_ARGS)
352{
353 bytea *bytea_wkb = PG_GETARG_BYTEA_P(0);
354 GSERIALIZED *geom;
355 LWGEOM *lwgeom;
356 uint8_t *wkb = (uint8_t*)VARDATA(bytea_wkb);
357
358 lwgeom = lwgeom_from_wkb(wkb, VARSIZE_ANY_EXHDR(bytea_wkb), LW_PARSER_CHECK_ALL);
359 if (!lwgeom)
360 lwpgerror("Unable to parse WKB");
361
362 if ((PG_NARGS() > 1) && (!PG_ARGISNULL(1)))
363 {
364 int32 srid = PG_GETARG_INT32(1);
365 lwgeom_set_srid(lwgeom, srid);
366 }
367
368 if ( lwgeom_needs_bbox(lwgeom) )
369 lwgeom_add_bbox(lwgeom);
370
371 geom = geometry_serialize(lwgeom);
372 lwgeom_free(lwgeom);
373 PG_FREE_IF_COPY(bytea_wkb, 0);
374 PG_RETURN_POINTER(geom);
375}
376/*
377 * LWGEOMFromTWKB(wkb)
378 * NOTE: twkb is in *binary* not hex form.
379 *
380 */
382Datum LWGEOMFromTWKB(PG_FUNCTION_ARGS)
383{
384 bytea *bytea_twkb = PG_GETARG_BYTEA_P(0);
385 GSERIALIZED *geom;
386 LWGEOM *lwgeom;
387 uint8_t *twkb = (uint8_t*)VARDATA(bytea_twkb);
388
389 lwgeom = lwgeom_from_twkb(twkb, VARSIZE_ANY_EXHDR(bytea_twkb), LW_PARSER_CHECK_ALL);
390
391 if (lwgeom_needs_bbox(lwgeom))
392 lwgeom_add_bbox(lwgeom);
393
394 geom = geometry_serialize(lwgeom);
395 lwgeom_free(lwgeom);
396 PG_FREE_IF_COPY(bytea_twkb, 0);
397 PG_RETURN_POINTER(geom);
398}
399
400/*
401 * WKBFromLWGEOM(lwgeom) --> wkb
402 * this will have no 'SRID=#;'
403 */
405Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
406{
407 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
408 LWGEOM *lwgeom;
409 uint8_t variant = 0;
410
411 /* If user specified endianness, respect it */
412 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
413 {
414 text *type = PG_GETARG_TEXT_P(1);
415
416 if ( ! strncmp(VARDATA(type), "xdr", 3) ||
417 ! strncmp(VARDATA(type), "XDR", 3) )
418 {
420 }
421 else
422 {
424 }
425 }
426
427 /* Create WKB hex string */
428 lwgeom = lwgeom_from_gserialized(geom);
429 PG_RETURN_BYTEA_P(lwgeom_to_wkb_varlena(lwgeom, variant | WKB_EXTENDED));
430}
431
433Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS)
434{
435 GSERIALIZED *geom;
436 LWGEOM *lwgeom;
437 uint8_t variant = 0;
438 srs_precision sp;
439
440 /*check for null input since we cannot have the sql-function as strict.
441 That is because we use null as default for optional ID*/
442 if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
443
444 geom = PG_GETARG_GSERIALIZED_P(0);
445
446 /* Read sensible precision defaults (about one meter) given the srs */
447 sp = srid_axis_precision(gserialized_get_srid(geom), TWKB_DEFAULT_PRECISION);
448
449 /* If user specified XY precision, use it */
450 if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
451 sp.precision_xy = PG_GETARG_INT32(1);
452
453 /* If user specified Z precision, use it */
454 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
455 sp.precision_z = PG_GETARG_INT32(2);
456
457 /* If user specified M precision, use it */
458 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
459 sp.precision_m = PG_GETARG_INT32(3);
460
461 /* We don't permit ids for single geometries */
462 variant = variant & ~TWKB_ID;
463
464 /* If user wants registered twkb sizes */
465 if ( PG_NARGS() > 4 && ! PG_ARGISNULL(4) && PG_GETARG_BOOL(4) )
467
468 /* If user wants bounding boxes */
469 if ( PG_NARGS() > 5 && ! PG_ARGISNULL(5) && PG_GETARG_BOOL(5) )
471
472 /* Create TWKB binary string */
473 lwgeom = lwgeom_from_gserialized(geom);
474 PG_RETURN_BYTEA_P(lwgeom_to_twkb(lwgeom, variant, sp.precision_xy, sp.precision_z, sp.precision_m));
475}
476
477
479Datum TWKBFromLWGEOMArray(PG_FUNCTION_ARGS)
480{
481 ArrayType *arr_geoms = NULL;
482 ArrayType *arr_ids = NULL;
483 int num_geoms, num_ids, i = 0;
484
485 ArrayIterator iter_geoms, iter_ids;
486 bool null_geom, null_id;
487 Datum val_geom, val_id;
488
489 int is_homogeneous = true;
490 uint32_t subtype = 0;
491 int has_z = 0;
492 int has_m = 0;
493 LWCOLLECTION *col = NULL;
494 int64_t *idlist = NULL;
495 uint8_t variant = 0;
496
497 srs_precision sp;
498
499 /* The first two arguments are required */
500 if ( PG_NARGS() < 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1) )
501 PG_RETURN_NULL();
502
503 arr_geoms = PG_GETARG_ARRAYTYPE_P(0);
504 arr_ids = PG_GETARG_ARRAYTYPE_P(1);
505
506 num_geoms = ArrayGetNItems(ARR_NDIM(arr_geoms), ARR_DIMS(arr_geoms));
507 num_ids = ArrayGetNItems(ARR_NDIM(arr_ids), ARR_DIMS(arr_ids));
508
509 if ( num_geoms != num_ids )
510 {
511 elog(ERROR, "size of geometry[] and integer[] arrays must match");
512 PG_RETURN_NULL();
513 }
514
515 /* Loop through array and build a collection of geometry and */
516 /* a simple array of ids. If either side is NULL, skip it */
517
518 iter_geoms = array_create_iterator(arr_geoms, 0, NULL);
519 iter_ids = array_create_iterator(arr_ids, 0, NULL);
520
521 while( array_iterate(iter_geoms, &val_geom, &null_geom) &&
522 array_iterate(iter_ids, &val_id, &null_id) )
523 {
524 LWGEOM *geom;
525 int32_t uid;
526
527 if ( null_geom || null_id )
528 {
529 elog(NOTICE, "ST_AsTWKB skipping NULL entry at position %d", i);
530 continue;
531 }
532
533 geom = lwgeom_from_gserialized((GSERIALIZED*)DatumGetPointer(val_geom));
534 uid = DatumGetInt64(val_id);
535
536 /* Construct collection/idlist first time through */
537 if ( ! col )
538 {
539 has_z = lwgeom_has_z(geom);
540 has_m = lwgeom_has_m(geom);
542 }
543 if ( ! idlist )
544 idlist = palloc0(num_geoms * sizeof(int64_t));
545
546
547 /* Check if there is differences in dimensionality*/
548 if( lwgeom_has_z(geom)!=has_z || lwgeom_has_m(geom)!=has_m)
549 {
550 elog(ERROR, "Geometries have different dimensionality");
551 PG_FREE_IF_COPY(arr_geoms, 0);
552 PG_FREE_IF_COPY(arr_ids, 1);
553 PG_RETURN_NULL();
554 }
555 /* Store the values */
556 lwcollection_add_lwgeom(col, geom);
557 idlist[i++] = uid;
558
559 /* Grab the geometry type and note if all geometries share it */
560 /* If so, we can make this a homogeneous collection and save some space */
561 if ( lwgeom_get_type(geom) != subtype && subtype )
562 {
563 is_homogeneous = false;
564 }
565 else
566 {
567 subtype = lwgeom_get_type(geom);
568 }
569
570 }
571 array_free_iterator(iter_geoms);
572 array_free_iterator(iter_ids);
573
574 if(i==0)
575 {
576 elog(NOTICE, "No valid geometry - id pairs found");
577 PG_FREE_IF_COPY(arr_geoms, 0);
578 PG_FREE_IF_COPY(arr_ids, 1);
579 PG_RETURN_NULL();
580 }
581 if ( is_homogeneous )
582 {
583 col->type = lwtype_get_collectiontype(subtype);
584 }
585
586 /* Read sensible precision defaults (about one meter) given the srs */
587 sp = srid_axis_precision(lwgeom_get_srid(lwcollection_as_lwgeom(col)), TWKB_DEFAULT_PRECISION);
588
589 /* If user specified XY precision, use it */
590 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
591 sp.precision_xy = PG_GETARG_INT32(2);
592
593 /* If user specified Z precision, use it */
594 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
595 sp.precision_z = PG_GETARG_INT32(3);
596
597 /* If user specified M precision, use it */
598 if ( PG_NARGS() > 4 && ! PG_ARGISNULL(4) )
599 sp.precision_m = PG_GETARG_INT32(4);
600
601 /* We are building an ID'ed output */
603
604 /* If user wants registered twkb sizes */
605 if ( PG_NARGS() > 5 && ! PG_ARGISNULL(5) && PG_GETARG_BOOL(5) )
607
608 /* If user wants bounding boxes */
609 if ( PG_NARGS() > 6 && ! PG_ARGISNULL(6) && PG_GETARG_BOOL(6) )
611
612 /* Write out the TWKB */
613 PG_RETURN_BYTEA_P(lwgeom_to_twkb_with_idlist(
614 lwcollection_as_lwgeom(col), idlist, variant, sp.precision_xy, sp.precision_z, sp.precision_m));
615}
616
617
618/* puts a bbox inside the geometry */
620Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS)
621{
622 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
624 LWGEOM *lwgeom;
625
626 lwgeom = lwgeom_from_gserialized(geom);
627 lwgeom_add_bbox(lwgeom);
628 result = geometry_serialize(lwgeom);
629
630 PG_FREE_IF_COPY(geom, 0);
631 PG_RETURN_POINTER(result);
632}
633
634/* removes a bbox from a geometry */
636Datum LWGEOM_dropBBOX(PG_FUNCTION_ARGS)
637{
638 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
639
640 /* No box? we're done already! */
641 if ( ! gserialized_has_bbox(geom) )
642 PG_RETURN_POINTER(geom);
643
644 PG_RETURN_POINTER(gserialized_drop_gbox(geom));
645}
646
647
648/* for the wkt parser */
649void elog_ERROR(const char* string)
650{
651 elog(ERROR, "%s", string);
652}
653
654/*
655* This just does the same thing as the _in function,
656* except it has to handle a 'text' input. First
657* unwrap the text into a cstring, then call
658* geometry_in
659*/
661Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS)
662{
663 text *wkt_text = PG_GETARG_TEXT_P(0);
664 char *wkt;
665 Datum result;
666
667 /* Unwrap the PgSQL text type into a cstring */
668 wkt = text_to_cstring(wkt_text);
669
670 /* Now we call over to the geometry_in function
671 * We need to initialize the fcinfo since cache might be used
672 */
673 result = CallerFInfoFunctionCall1(LWGEOM_in, fcinfo->flinfo, InvalidOid, CStringGetDatum(wkt));
674
675 /* Return null on null */
676 if ( ! result )
677 PG_RETURN_NULL();
678
679 PG_RETURN_DATUM(result);
680}
681
682
683/*
684 * This function must advance the StringInfo.cursor pointer
685 * and leave it at the end of StringInfo.buf. If it fails
686 * to do so the backend will raise an exception with message:
687 * ERROR: incorrect binary data format in bind parameter #
688 *
689 */
691Datum LWGEOM_recv(PG_FUNCTION_ARGS)
692{
693 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
694 int32 geom_typmod = -1;
695 GSERIALIZED *geom;
696 LWGEOM *lwgeom;
697
698 if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) {
699 geom_typmod = PG_GETARG_INT32(2);
700 }
701
702 lwgeom = lwgeom_from_wkb((uint8_t*)buf->data, buf->len, LW_PARSER_CHECK_ALL);
703 if ( !lwgeom )
704 {
705 ereport(ERROR,(errmsg("recv error - invalid geometry")));
706 PG_RETURN_NULL();
707 }
708
709 if ( lwgeom_needs_bbox(lwgeom) )
710 lwgeom_add_bbox(lwgeom);
711
712 /* Set cursor to the end of buffer (so the backend is happy) */
713 buf->cursor = buf->len;
714
715 geom = geometry_serialize(lwgeom);
716 lwgeom_free(lwgeom);
717
718 if ( geom_typmod >= 0 )
719 {
720 geom = postgis_valid_typmod(geom, geom_typmod);
721 POSTGIS_DEBUG(3, "typmod and geometry were consistent");
722 }
723 else
724 {
725 POSTGIS_DEBUG(3, "typmod was -1");
726 }
727
728
729 PG_RETURN_POINTER(geom);
730}
731
732
733
735Datum LWGEOM_send(PG_FUNCTION_ARGS)
736{
737 POSTGIS_DEBUG(2, "LWGEOM_send called");
738
739 PG_RETURN_POINTER(
740 DatumGetPointer(
741 DirectFunctionCall1(
743 PG_GETARG_DATUM(0)
744 )));
745}
746
748Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS)
749{
750 POSTGIS_DEBUG(2, "LWGEOM_to_bytea called");
751
752 PG_RETURN_POINTER(
753 DatumGetPointer(
754 DirectFunctionCall1(
756 PG_GETARG_DATUM(0)
757 )));
758}
759
761Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS)
762{
764
765 POSTGIS_DEBUG(2, "LWGEOM_from_bytea start");
766
767 result = (GSERIALIZED *)DatumGetPointer(DirectFunctionCall1(
768 LWGEOMFromEWKB, PG_GETARG_DATUM(0)));
769
770 PG_RETURN_POINTER(result);
771}
772
static uint8_t variant
Definition cu_in_twkb.c:26
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
GSERIALIZED * postgis_valid_typmod(GSERIALIZED *gser, int32_t typmod)
Check the consistency of the metadata we want to enforce in the typmod: srid, type and dimensionality...
int gserialized_has_bbox(const GSERIALIZED *g)
Check if a GSERIALIZED has a bounding box without deserializing first.
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
GSERIALIZED * gserialized_drop_gbox(GSERIALIZED *g)
Remove the bounding box from a GSERIALIZED.
Definition gserialized.c:81
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
char * lwpoint_to_latlon(const LWPOINT *p, const char *format)
Definition lwprint.c:437
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
#define LW_PARSER_CHECK_ALL
Definition liblwgeom.h:2150
char * lwgeom_to_hexwkb_buffer(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:845
uint32_t lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition lwgeom.c:1222
#define COLLECTIONTYPE
Definition liblwgeom.h:108
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition lwgeom.c:955
void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
Set the SRID on an LWGEOM For collections, only the parent gets an SRID, all the children get SRID_UN...
Definition lwgeom.c:1638
#define LW_FAILURE
Definition liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
#define LW_PARSER_CHECK_NONE
Definition liblwgeom.h:2149
lwvarlena_t * lwgeom_to_hexwkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:875
void lwgeom_parser_result_init(LWGEOM_PARSER_RESULT *parser_result)
Definition lwin_wkt.c:915
int lwgeom_parse_wkt(LWGEOM_PARSER_RESULT *parser_result, char *wktstr, int parse_flags)
Parse a WKT geometry string into an LWGEOM structure.
lwvarlena_t * lwgeom_to_wkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:851
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition lwgeom.c:1299
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:962
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:102
int lwgeom_isfinite(const LWGEOM *lwgeom)
Check if a LWGEOM has any non-finite (NaN or Inf) coordinates.
Definition lwgeom.c:2835
uint8_t * bytes_from_hexbytes(const char *hexbuf, size_t hexsize)
Definition lwin_wkb.c:92
LWGEOM * lwgeom_from_twkb(const uint8_t *twkb, size_t twkb_size, char check)
WKB inputs must have a declared size, to prevent malformed WKB from reading off the end of the memory...
Definition lwin_twkb.c:654
lwvarlena_t * lwgeom_to_twkb_with_idlist(const LWGEOM *geom, int64_t *idlist, uint8_t variant, int8_t precision_xy, int8_t precision_z, int8_t precision_m)
Convert LWGEOM to a char* in TWKB format.
Definition lwout_twkb.c:589
void lwfree(void *mem)
Definition lwutil.c:248
#define TWKB_ID
Definition liblwgeom.h:2229
#define WKB_EXTENDED
Definition liblwgeom.h:2212
#define WKB_NDR
Definition liblwgeom.h:2213
#define TWKB_DEFAULT_PRECISION
Definition liblwgeom.h:2232
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
#define TWKB_SIZE
Definition liblwgeom.h:2228
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:969
LWGEOM * lwgeom_from_wkb(const uint8_t *wkb, const size_t wkb_size, const char check)
WKB inputs must have a declared size, to prevent malformed WKB from reading off the end of the memory...
Definition lwin_wkb.c:842
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition lwgeom.c:723
void lwgeom_parser_result_free(LWGEOM_PARSER_RESULT *parser_result)
Definition lwin_wkt.c:921
#define TWKB_BBOX
Definition liblwgeom.h:2227
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition lwgeom.c:337
#define WKB_XDR
Definition liblwgeom.h:2214
LWGEOM * lwgeom_from_geojson(const char *geojson, char **srs)
Create an LWGEOM object from a GeoJSON representation.
lwvarlena_t * lwgeom_to_twkb(const LWGEOM *geom, uint8_t variant, int8_t precision_xy, int8_t precision_z, int8_t precision_m)
Definition lwout_twkb.c:636
This library is the generic geometry handling section of PostGIS.
#define str(s)
Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS)
Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(LWGEOM_in)
Datum LWGEOM_in(PG_FUNCTION_ARGS)
Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS)
Datum LWGEOM_out(PG_FUNCTION_ARGS)
Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS)
Datum LWGEOMFromTWKB(PG_FUNCTION_ARGS)
Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS)
Datum TWKBFromLWGEOMArray(PG_FUNCTION_ARGS)
Datum LWGEOM_send(PG_FUNCTION_ARGS)
Datum LWGEOM_dropBBOX(PG_FUNCTION_ARGS)
Datum LWGEOM_to_text(PG_FUNCTION_ARGS)
Datum LWGEOMFromEWKB(PG_FUNCTION_ARGS)
Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS)
void elog_ERROR(const char *string)
Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS)
Datum LWGEOM_recv(PG_FUNCTION_ARGS)
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
Definition lwinline.h:141
unsigned int int32
Definition shpopen.c:54
uint8_t type
Definition liblwgeom.h:578
Parser result structure: returns the result of attempting to convert (E)WKT/(E)WKB to LWGEOM.
Definition liblwgeom.h:2157