PostGIS 3.0.6dev-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_pg.h"
49#include "geography.h" /* for lwgeom_valid_typmod */
50#include "lwgeom_transform.h"
51
52
53#include "access/htup_details.h"
54
55
56void elog_ERROR(const char* string);
57
58Datum LWGEOM_in(PG_FUNCTION_ARGS);
59Datum LWGEOM_out(PG_FUNCTION_ARGS);
60Datum LWGEOM_to_text(PG_FUNCTION_ARGS);
61Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS);
62Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS);
63Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS);
64Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS);
65Datum LWGEOM_recv(PG_FUNCTION_ARGS);
66Datum LWGEOM_send(PG_FUNCTION_ARGS);
67Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS);
68Datum WKBFromLWGEOM(PG_FUNCTION_ARGS);
69Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS);
70Datum TWKBFromLWGEOMArray(PG_FUNCTION_ARGS);
71Datum LWGEOMFromTWKB(PG_FUNCTION_ARGS);
72
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 * returns a GSERIALIZED object
82 */
84Datum LWGEOM_in(PG_FUNCTION_ARGS)
85{
86 char *input = PG_GETARG_CSTRING(0);
87 int32 geom_typmod = -1;
88 char *str = input;
89 LWGEOM_PARSER_RESULT lwg_parser_result;
90 LWGEOM *lwgeom;
91 GSERIALIZED *ret;
92 int32_t srid = 0;
93
94 if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) {
95 geom_typmod = PG_GETARG_INT32(2);
96 }
97
98 lwgeom_parser_result_init(&lwg_parser_result);
99
100 /* Empty string. */
101 if ( str[0] == '\0' ) {
102 ereport(ERROR,(errmsg("parse error - invalid geometry")));
103 PG_RETURN_NULL();
104 }
105
106 /* Starts with "SRID=" */
107 if( strncasecmp(str,"SRID=",5) == 0 )
108 {
109 /* Roll forward to semi-colon */
110 char *tmp = str;
111 while ( tmp && *tmp != ';' )
112 tmp++;
113
114 /* Check next character to see if we have WKB */
115 if ( tmp && *(tmp+1) == '0' )
116 {
117 /* Null terminate the SRID= string */
118 *tmp = '\0';
119 /* Set str to the start of the real WKB */
120 str = tmp + 1;
121 /* Move tmp to the start of the numeric part */
122 tmp = input + 5;
123 /* Parse out the SRID number */
124 srid = atoi(tmp);
125 }
126 }
127
128 /* WKB? Let's find out. */
129 if ( str[0] == '0' )
130 {
131 size_t hexsize = strlen(str);
132 unsigned char *wkb = bytes_from_hexbytes(str, hexsize);
133 /* TODO: 20101206: No parser checks! This is inline with current 1.5 behavior, but needs discussion */
134 lwgeom = lwgeom_from_wkb(wkb, hexsize/2, LW_PARSER_CHECK_NONE);
135 /* Parser should throw error, but if not, catch here. */
136 if ( !lwgeom ) PG_RETURN_NULL();
137 /* If we picked up an SRID at the head of the WKB set it manually */
138 if ( srid ) lwgeom_set_srid(lwgeom, srid);
139 /* Add a bbox if necessary */
140 if ( lwgeom_needs_bbox(lwgeom) ) lwgeom_add_bbox(lwgeom);
141 lwfree(wkb);
142 ret = geometry_serialize(lwgeom);
143 lwgeom_free(lwgeom);
144 }
145 /* WKT then. */
146 else
147 {
148 if ( lwgeom_parse_wkt(&lwg_parser_result, str, LW_PARSER_CHECK_ALL) == LW_FAILURE )
149 {
150 PG_PARSER_ERROR(lwg_parser_result);
151 PG_RETURN_NULL();
152 }
153 lwgeom = lwg_parser_result.geom;
154 if ( lwgeom_needs_bbox(lwgeom) )
155 lwgeom_add_bbox(lwgeom);
156 ret = geometry_serialize(lwgeom);
157 lwgeom_parser_result_free(&lwg_parser_result);
158 }
159
160 if ( geom_typmod >= 0 )
161 {
162 ret = postgis_valid_typmod(ret, geom_typmod);
163 POSTGIS_DEBUG(3, "typmod and geometry were consistent");
164 }
165 else
166 {
167 POSTGIS_DEBUG(3, "typmod was -1");
168 }
169
170 /* Don't free the parser result (and hence lwgeom) until we have done */
171 /* the typemod check with lwgeom */
172
173 PG_RETURN_POINTER(ret);
174
175}
176
177/*
178 * LWGEOM_to_latlon(GEOMETRY, text)
179 * NOTE: Geometry must be a point. It is assumed that the coordinates
180 * of the point are in a lat/lon projection, and they will be
181 * normalized in the output to -90-90 and -180-180.
182 *
183 * The text parameter is a format string containing the format for the
184 * resulting text, similar to a date format string. Valid tokens
185 * are "D" for degrees, "M" for minutes, "S" for seconds, and "C" for
186 * cardinal direction (NSEW). DMS tokens may be repeated to indicate
187 * desired width and precision ("SSS.SSSS" means " 1.0023").
188 * "M", "S", and "C" are optional. If "C" is omitted, degrees are
189 * shown with a "-" sign if south or west. If "S" is omitted,
190 * minutes will be shown as decimal with as many digits of precision
191 * as you specify. If "M" is omitted, degrees are shown as decimal
192 * with as many digits precision as you specify.
193 *
194 * If the format string is omitted (null or 0-length) a default
195 * format will be used.
196 *
197 * returns text
198 */
200Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS)
201{
202 /* Get the parameters */
203 GSERIALIZED *pg_lwgeom = PG_GETARG_GSERIALIZED_P(0);
204 text *format_text = PG_GETARG_TEXT_P(1);
205
206 LWGEOM *lwgeom;
207 char *format_str = NULL;
208
209 char * formatted_str;
210 text * formatted_text;
211 char * tmp;
212
213 /* Only supports points. */
214 uint8_t geom_type = gserialized_get_type(pg_lwgeom);
215 if (POINTTYPE != geom_type)
216 {
217 lwpgerror("Only points are supported, you tried type %s.", lwtype_name(geom_type));
218 }
219 /* Convert to LWGEOM type */
220 lwgeom = lwgeom_from_gserialized(pg_lwgeom);
221
222 if (format_text == NULL) {
223 lwpgerror("ST_AsLatLonText: invalid format string (null");
224 PG_RETURN_NULL();
225 }
226
227 if (!lwgeom_isfinite(lwgeom)) {
228 lwpgerror("ST_AsLatLonText: invalid coordinate");
229 PG_RETURN_NULL();
230 }
231
232 format_str = text_to_cstring(format_text);
233 assert(format_str != NULL);
234
235 /* The input string supposedly will be in the database encoding,
236 so convert to UTF-8. */
237 tmp = (char *)pg_do_encoding_conversion(
238 (uint8_t *)format_str, strlen(format_str), GetDatabaseEncoding(), PG_UTF8);
239 assert(tmp != NULL);
240 if ( tmp != format_str ) {
241 pfree(format_str);
242 format_str = tmp;
243 }
244
245 /* Produce the formatted string. */
246 formatted_str = lwpoint_to_latlon((LWPOINT *)lwgeom, format_str);
247 assert(formatted_str != NULL);
248 pfree(format_str);
249
250 /* Convert the formatted string from UTF-8 back to database encoding. */
251 tmp = (char *)pg_do_encoding_conversion(
252 (uint8_t *)formatted_str, strlen(formatted_str),
253 PG_UTF8, GetDatabaseEncoding());
254 assert(tmp != NULL);
255 if ( tmp != formatted_str) {
256 pfree(formatted_str);
257 formatted_str = tmp;
258 }
259
260 /* Convert to the postgres output string type. */
261 formatted_text = cstring_to_text(formatted_str);
262 pfree(formatted_str);
263
264 PG_RETURN_POINTER(formatted_text);
265}
266
267/*
268 * LWGEOM_out(lwgeom) --> cstring
269 * output is 'SRID=#;<wkb in hex form>'
270 * ie. 'SRID=-99;0101000000000000000000F03F0000000000000040'
271 * WKB is machine endian
272 * if SRID=-1, the 'SRID=-1;' will probably not be present.
273 */
275Datum LWGEOM_out(PG_FUNCTION_ARGS)
276{
277 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
278 LWGEOM *lwgeom;
279 char *hexwkb;
280 size_t hexwkb_size;
281
282 lwgeom = lwgeom_from_gserialized(geom);
283 hexwkb = lwgeom_to_hexwkb(lwgeom, WKB_EXTENDED, &hexwkb_size);
284 lwgeom_free(lwgeom);
285
286 PG_RETURN_CSTRING(hexwkb);
287}
288
289/*
290 * AsHEXEWKB(geom, string)
291 */
293Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS)
294{
295 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
296 LWGEOM *lwgeom;
297 char *hexwkb;
298 size_t hexwkb_size;
299 uint8_t variant = 0;
300 text *result;
301 text *type;
302 size_t text_size;
303
304 /* If user specified endianness, respect it */
305 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
306 {
307 type = PG_GETARG_TEXT_P(1);
308
309 if ( ! strncmp(VARDATA(type), "xdr", 3) ||
310 ! strncmp(VARDATA(type), "XDR", 3) )
311 {
313 }
314 else
315 {
317 }
318 }
319
320 /* Create WKB hex string */
321 lwgeom = lwgeom_from_gserialized(geom);
322 hexwkb = lwgeom_to_hexwkb(lwgeom, variant | WKB_EXTENDED, &hexwkb_size);
323 lwgeom_free(lwgeom);
324
325 /* Prepare the PgSQL text return type */
326 text_size = hexwkb_size - 1 + VARHDRSZ;
327 result = palloc(text_size);
328 memcpy(VARDATA(result), hexwkb, hexwkb_size - 1);
329 SET_VARSIZE(result, text_size);
330
331 /* Clean up and return */
332 lwfree(hexwkb);
333 PG_FREE_IF_COPY(geom, 0);
334 PG_RETURN_TEXT_P(result);
335}
336
337
338/*
339 * LWGEOM_to_text(lwgeom) --> text
340 * output is 'SRID=#;<wkb in hex form>'
341 * ie. 'SRID=-99;0101000000000000000000F03F0000000000000040'
342 * WKB is machine endian
343 * if SRID=-1, the 'SRID=-1;' will probably not be present.
344 */
346Datum LWGEOM_to_text(PG_FUNCTION_ARGS)
347{
348 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
349 LWGEOM *lwgeom;
350 char *hexwkb;
351 size_t hexwkb_size;
352 text *result;
353
354 /* Generate WKB hex text */
355 lwgeom = lwgeom_from_gserialized(geom);
356 hexwkb = lwgeom_to_hexwkb(lwgeom, WKB_EXTENDED, &hexwkb_size);
357 lwgeom_free(lwgeom);
358
359 /* Copy into text obect */
360 result = cstring_to_text(hexwkb);
361 lwfree(hexwkb);
362
363 /* Clean up and return */
364 PG_FREE_IF_COPY(geom, 0);
365 PG_RETURN_TEXT_P(result);
366}
367
368/*
369 * LWGEOMFromEWKB(wkb, [SRID] )
370 * NOTE: wkb is in *binary* not hex form.
371 *
372 * NOTE: this function parses EWKB (extended form)
373 * which also contains SRID info.
374 */
376Datum LWGEOMFromEWKB(PG_FUNCTION_ARGS)
377{
378 bytea *bytea_wkb = PG_GETARG_BYTEA_P(0);
379 GSERIALIZED *geom;
380 LWGEOM *lwgeom;
381 uint8_t *wkb = (uint8_t*)VARDATA(bytea_wkb);
382
383 lwgeom = lwgeom_from_wkb(wkb, VARSIZE_ANY_EXHDR(bytea_wkb), LW_PARSER_CHECK_ALL);
384 if (!lwgeom)
385 lwpgerror("Unable to parse WKB");
386
387 if ((PG_NARGS() > 1) && (!PG_ARGISNULL(1)))
388 {
389 int32 srid = PG_GETARG_INT32(1);
390 lwgeom_set_srid(lwgeom, srid);
391 }
392
393 if ( lwgeom_needs_bbox(lwgeom) )
394 lwgeom_add_bbox(lwgeom);
395
396 geom = geometry_serialize(lwgeom);
397 lwgeom_free(lwgeom);
398 PG_FREE_IF_COPY(bytea_wkb, 0);
399 PG_RETURN_POINTER(geom);
400}
401/*
402 * LWGEOMFromTWKB(wkb)
403 * NOTE: twkb is in *binary* not hex form.
404 *
405 */
407Datum LWGEOMFromTWKB(PG_FUNCTION_ARGS)
408{
409 bytea *bytea_twkb = PG_GETARG_BYTEA_P(0);
410 GSERIALIZED *geom;
411 LWGEOM *lwgeom;
412 uint8_t *twkb = (uint8_t*)VARDATA(bytea_twkb);
413
414 lwgeom = lwgeom_from_twkb(twkb, VARSIZE_ANY_EXHDR(bytea_twkb), LW_PARSER_CHECK_ALL);
415
416 if (lwgeom_needs_bbox(lwgeom))
417 lwgeom_add_bbox(lwgeom);
418
419 geom = geometry_serialize(lwgeom);
420 lwgeom_free(lwgeom);
421 PG_FREE_IF_COPY(bytea_twkb, 0);
422 PG_RETURN_POINTER(geom);
423}
424
425/*
426 * WKBFromLWGEOM(lwgeom) --> wkb
427 * this will have no 'SRID=#;'
428 */
430Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
431{
432 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
433 LWGEOM *lwgeom;
434 uint8_t *wkb;
435 size_t wkb_size;
436 uint8_t variant = 0;
437 bytea *result;
438 text *type;
439 /* If user specified endianness, respect it */
440 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
441 {
442 type = PG_GETARG_TEXT_P(1);
443
444 if ( ! strncmp(VARDATA(type), "xdr", 3) ||
445 ! strncmp(VARDATA(type), "XDR", 3) )
446 {
448 }
449 else
450 {
452 }
453 }
454 wkb_size= VARSIZE_ANY_EXHDR(geom);
455 /* Create WKB hex string */
456 lwgeom = lwgeom_from_gserialized(geom);
457
458 wkb = lwgeom_to_wkb(lwgeom, variant | WKB_EXTENDED , &wkb_size);
459 lwgeom_free(lwgeom);
460
461 /* Prepare the PgSQL text return type */
462 result = palloc(wkb_size + VARHDRSZ);
463 memcpy(VARDATA(result), wkb, wkb_size);
464 SET_VARSIZE(result, wkb_size+VARHDRSZ);
465
466 /* Clean up and return */
467 lwfree(wkb);
468 PG_FREE_IF_COPY(geom, 0);
469 PG_RETURN_BYTEA_P(result);
470}
471
473Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS)
474{
475 GSERIALIZED *geom;
476 LWGEOM *lwgeom;
477 uint8_t *twkb;
478 size_t twkb_size;
479 uint8_t variant = 0;
480 bytea *result;
481 srs_precision sp;
482
483 /*check for null input since we cannot have the sql-function as strict.
484 That is because we use null as default for optional ID*/
485 if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
486
487 geom = PG_GETARG_GSERIALIZED_P(0);
488
489 /* Read sensible precision defaults (about one meter) given the srs */
490 sp = srid_axis_precision(fcinfo, gserialized_get_srid(geom), TWKB_DEFAULT_PRECISION);
491
492 /* If user specified XY precision, use it */
493 if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
494 sp.precision_xy = PG_GETARG_INT32(1);
495
496 /* If user specified Z precision, use it */
497 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
498 sp.precision_z = PG_GETARG_INT32(2);
499
500 /* If user specified M precision, use it */
501 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
502 sp.precision_m = PG_GETARG_INT32(3);
503
504 /* We don't permit ids for single geoemtries */
505 variant = variant & ~TWKB_ID;
506
507 /* If user wants registered twkb sizes */
508 if ( PG_NARGS() > 4 && ! PG_ARGISNULL(4) && PG_GETARG_BOOL(4) )
510
511 /* If user wants bounding boxes */
512 if ( PG_NARGS() > 5 && ! PG_ARGISNULL(5) && PG_GETARG_BOOL(5) )
514
515 /* Create TWKB binary string */
516 lwgeom = lwgeom_from_gserialized(geom);
517 twkb = lwgeom_to_twkb(lwgeom, variant, sp.precision_xy, sp.precision_z, sp.precision_m, &twkb_size);
518
519 /* Prepare the PgSQL text return type */
520 result = palloc(twkb_size + VARHDRSZ);
521 memcpy(VARDATA(result), twkb, twkb_size);
522 SET_VARSIZE(result, twkb_size + VARHDRSZ);
523
524 PG_RETURN_BYTEA_P(result);
525}
526
527
529Datum TWKBFromLWGEOMArray(PG_FUNCTION_ARGS)
530{
531 ArrayType *arr_geoms = NULL;
532 ArrayType *arr_ids = NULL;
533 int num_geoms, num_ids, i = 0;
534
535 ArrayIterator iter_geoms, iter_ids;
536 bool null_geom, null_id;
537 Datum val_geom, val_id;
538
539 int is_homogeneous = true;
540 uint32_t subtype = 0;
541 int has_z = 0;
542 int has_m = 0;
543 LWCOLLECTION *col = NULL;
544 int64_t *idlist = NULL;
545 uint8_t variant = 0;
546
547 srs_precision sp;
548 uint8_t *twkb;
549 size_t twkb_size;
550 bytea *result;
551
552 /* The first two arguments are required */
553 if ( PG_NARGS() < 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1) )
554 PG_RETURN_NULL();
555
556 arr_geoms = PG_GETARG_ARRAYTYPE_P(0);
557 arr_ids = PG_GETARG_ARRAYTYPE_P(1);
558
559 num_geoms = ArrayGetNItems(ARR_NDIM(arr_geoms), ARR_DIMS(arr_geoms));
560 num_ids = ArrayGetNItems(ARR_NDIM(arr_ids), ARR_DIMS(arr_ids));
561
562 if ( num_geoms != num_ids )
563 {
564 elog(ERROR, "size of geometry[] and integer[] arrays must match");
565 PG_RETURN_NULL();
566 }
567
568 /* Loop through array and build a collection of geometry and */
569 /* a simple array of ids. If either side is NULL, skip it */
570
571 iter_geoms = array_create_iterator(arr_geoms, 0, NULL);
572 iter_ids = array_create_iterator(arr_ids, 0, NULL);
573
574 while( array_iterate(iter_geoms, &val_geom, &null_geom) &&
575 array_iterate(iter_ids, &val_id, &null_id) )
576 {
577 LWGEOM *geom;
578 int32_t uid;
579
580 if ( null_geom || null_id )
581 {
582 elog(NOTICE, "ST_AsTWKB skipping NULL entry at position %d", i);
583 continue;
584 }
585
586 geom = lwgeom_from_gserialized((GSERIALIZED*)DatumGetPointer(val_geom));
587 uid = DatumGetInt64(val_id);
588
589 /* Construct collection/idlist first time through */
590 if ( ! col )
591 {
592 has_z = lwgeom_has_z(geom);
593 has_m = lwgeom_has_m(geom);
595 }
596 if ( ! idlist )
597 idlist = palloc0(num_geoms * sizeof(int64_t));
598
599
600 /* Check if there is differences in dimensionality*/
601 if( lwgeom_has_z(geom)!=has_z || lwgeom_has_m(geom)!=has_m)
602 {
603 elog(ERROR, "Geometries have different dimensionality");
604 PG_FREE_IF_COPY(arr_geoms, 0);
605 PG_FREE_IF_COPY(arr_ids, 1);
606 PG_RETURN_NULL();
607 }
608 /* Store the values */
609 lwcollection_add_lwgeom(col, geom);
610 idlist[i++] = uid;
611
612 /* Grab the geometry type and note if all geometries share it */
613 /* If so, we can make this a homogeneous collection and save some space */
614 if ( lwgeom_get_type(geom) != subtype && subtype )
615 {
616 is_homogeneous = false;
617 }
618 else
619 {
620 subtype = lwgeom_get_type(geom);
621 }
622
623 }
624 array_free_iterator(iter_geoms);
625 array_free_iterator(iter_ids);
626
627 if(i==0)
628 {
629 elog(NOTICE, "No valid geometry - id pairs found");
630 PG_FREE_IF_COPY(arr_geoms, 0);
631 PG_FREE_IF_COPY(arr_ids, 1);
632 PG_RETURN_NULL();
633 }
634 if ( is_homogeneous )
635 {
636 col->type = lwtype_get_collectiontype(subtype);
637 }
638
639 /* Read sensible precision defaults (about one meter) given the srs */
640 sp = srid_axis_precision(fcinfo, lwgeom_get_srid(lwcollection_as_lwgeom(col)), TWKB_DEFAULT_PRECISION);
641
642 /* If user specified XY precision, use it */
643 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
644 sp.precision_xy = PG_GETARG_INT32(2);
645
646 /* If user specified Z precision, use it */
647 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
648 sp.precision_z = PG_GETARG_INT32(3);
649
650 /* If user specified M precision, use it */
651 if ( PG_NARGS() > 4 && ! PG_ARGISNULL(4) )
652 sp.precision_m = PG_GETARG_INT32(4);
653
654 /* We are building an ID'ed output */
656
657 /* If user wants registered twkb sizes */
658 if ( PG_NARGS() > 5 && ! PG_ARGISNULL(5) && PG_GETARG_BOOL(5) )
660
661 /* If user wants bounding boxes */
662 if ( PG_NARGS() > 6 && ! PG_ARGISNULL(6) && PG_GETARG_BOOL(6) )
664
665 /* Write out the TWKB */
667 idlist, variant,
668 sp.precision_xy, sp.precision_z, sp.precision_m,
669 &twkb_size);
670
671 /* Convert to a bytea return type */
672 result = palloc(twkb_size + VARHDRSZ);
673 memcpy(VARDATA(result), twkb, twkb_size);
674 SET_VARSIZE(result, twkb_size + VARHDRSZ);
675
676 /* Clean up */
677 pfree(twkb);
678 pfree(idlist);
680 PG_FREE_IF_COPY(arr_geoms, 0);
681 PG_FREE_IF_COPY(arr_ids, 1);
682
683 PG_RETURN_BYTEA_P(result);
684}
685
686
687/* puts a bbox inside the geometry */
689Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS)
690{
691 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
692 GSERIALIZED *result;
693 LWGEOM *lwgeom;
694
695 lwgeom = lwgeom_from_gserialized(geom);
696 lwgeom_add_bbox(lwgeom);
697 result = geometry_serialize(lwgeom);
698
699 PG_FREE_IF_COPY(geom, 0);
700 PG_RETURN_POINTER(result);
701}
702
703/* removes a bbox from a geometry */
705Datum LWGEOM_dropBBOX(PG_FUNCTION_ARGS)
706{
707 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
708
709 /* No box? we're done already! */
710 if ( ! gserialized_has_bbox(geom) )
711 PG_RETURN_POINTER(geom);
712
713 PG_RETURN_POINTER(gserialized_drop_gbox(geom));
714}
715
716
717/* for the wkt parser */
718void elog_ERROR(const char* string)
719{
720 elog(ERROR, "%s", string);
721}
722
723/*
724* This just does the same thing as the _in function,
725* except it has to handle a 'text' input. First
726* unwrap the text into a cstring, then call
727* geometry_in
728*/
730Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS)
731{
732 text *wkt_text = PG_GETARG_TEXT_P(0);
733 char *wkt;
734 Datum result;
735
736 /* Unwrap the PgSQL text type into a cstring */
737 wkt = text_to_cstring(wkt_text);
738
739 /* Now we call over to the geometry_in function */
740 result = DirectFunctionCall1(LWGEOM_in, CStringGetDatum(wkt));
741
742 /* Return null on null */
743 if ( ! result )
744 PG_RETURN_NULL();
745
746 PG_RETURN_DATUM(result);
747}
748
749
750/*
751 * This function must advance the StringInfo.cursor pointer
752 * and leave it at the end of StringInfo.buf. If it fails
753 * to do so the backend will raise an exception with message:
754 * ERROR: incorrect binary data format in bind parameter #
755 *
756 */
758Datum LWGEOM_recv(PG_FUNCTION_ARGS)
759{
760 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
761 int32 geom_typmod = -1;
762 GSERIALIZED *geom;
763 LWGEOM *lwgeom;
764
765 if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) {
766 geom_typmod = PG_GETARG_INT32(2);
767 }
768
769 lwgeom = lwgeom_from_wkb((uint8_t*)buf->data, buf->len, LW_PARSER_CHECK_ALL);
770 if ( !lwgeom )
771 {
772 ereport(ERROR,(errmsg("recv error - invalid geometry")));
773 PG_RETURN_NULL();
774 }
775
776 if ( lwgeom_needs_bbox(lwgeom) )
777 lwgeom_add_bbox(lwgeom);
778
779 /* Set cursor to the end of buffer (so the backend is happy) */
780 buf->cursor = buf->len;
781
782 geom = geometry_serialize(lwgeom);
783 lwgeom_free(lwgeom);
784
785 if ( geom_typmod >= 0 )
786 {
787 geom = postgis_valid_typmod(geom, geom_typmod);
788 POSTGIS_DEBUG(3, "typmod and geometry were consistent");
789 }
790 else
791 {
792 POSTGIS_DEBUG(3, "typmod was -1");
793 }
794
795
796 PG_RETURN_POINTER(geom);
797}
798
799
800
802Datum LWGEOM_send(PG_FUNCTION_ARGS)
803{
804 POSTGIS_DEBUG(2, "LWGEOM_send called");
805
806 PG_RETURN_POINTER(
807 DatumGetPointer(
808 DirectFunctionCall1(
810 PG_GETARG_DATUM(0)
811 )));
812}
813
815Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS)
816{
817 POSTGIS_DEBUG(2, "LWGEOM_to_bytea called");
818
819 PG_RETURN_POINTER(
820 DatumGetPointer(
821 DirectFunctionCall1(
823 PG_GETARG_DATUM(0)
824 )));
825}
826
828Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS)
829{
830 GSERIALIZED *result;
831
832 POSTGIS_DEBUG(2, "LWGEOM_from_bytea start");
833
834 result = (GSERIALIZED *)DatumGetPointer(DirectFunctionCall1(
835 LWGEOMFromEWKB, PG_GETARG_DATUM(0)));
836
837 PG_RETURN_POINTER(result);
838}
839
static uint8_t variant
Definition cu_in_twkb.c:26
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:52
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,...
Definition gserialized.c:89
char * lwpoint_to_latlon(const LWPOINT *p, const char *format)
Definition lwprint.c:428
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:2061
uint32_t lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition lwgeom.c:1114
#define COLLECTIONTYPE
Definition liblwgeom.h:122
char * lwgeom_to_hexwkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
Definition lwout_wkb.c:874
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition lwgeom.c:909
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:1530
#define LW_FAILURE
Definition liblwgeom.h:110
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1138
#define LW_PARSER_CHECK_NONE
Definition liblwgeom.h:2060
uint8_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, size_t *twkb_size)
Convert LWGEOM to a char* in TWKB format.
Definition lwout_twkb.c:589
void lwgeom_parser_result_init(LWGEOM_PARSER_RESULT *parser_result)
Definition lwin_wkt.c:880
int lwgeom_parse_wkt(LWGEOM_PARSER_RESULT *parser_result, char *wktstr, int parse_flags)
Parse a WKT geometry string into an LWGEOM structure.
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition lwgeom.c:1191
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:916
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:116
int lwgeom_isfinite(const LWGEOM *lwgeom)
Check if a LWGEOM has any non-finite (NaN or Inf) coordinates.
Definition lwgeom.c:2529
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
void lwfree(void *mem)
Definition lwutil.c:242
#define TWKB_ID
Definition liblwgeom.h:2140
uint8_t * lwgeom_to_twkb(const LWGEOM *geom, uint8_t variant, int8_t precision_xy, int8_t precision_z, int8_t precision_m, size_t *twkb_size)
Definition lwout_twkb.c:636
#define WKB_EXTENDED
Definition liblwgeom.h:2123
#define WKB_NDR
Definition liblwgeom.h:2124
uint8_t * lwgeom_to_wkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
Convert LWGEOM to a char* in WKB format.
Definition lwout_wkb.c:790
void lwcollection_free(LWCOLLECTION *col)
#define TWKB_DEFAULT_PRECISION
Definition liblwgeom.h:2143
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
#define TWKB_SIZE
Definition liblwgeom.h:2139
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:923
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:833
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition lwgeom.c:677
void lwgeom_parser_result_free(LWGEOM_PARSER_RESULT *parser_result)
Definition lwin_wkt.c:886
#define TWKB_BBOX
Definition liblwgeom.h:2138
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition lwgeom.c:291
#define WKB_XDR
Definition liblwgeom.h:2125
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:135
char * text_to_cstring(const text *textptr)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
unsigned int int32
Definition shpopen.c:273
uint8_t type
Definition liblwgeom.h:564
Parser result structure: returns the result of attempting to convert (E)WKT/(E)WKB to LWGEOM.
Definition liblwgeom.h:2068