PostGIS  3.7.0dev-r@@SVN_REVISION@@
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 
57 void elog_ERROR(const char* string);
58 
59 Datum LWGEOM_in(PG_FUNCTION_ARGS);
60 Datum LWGEOM_out(PG_FUNCTION_ARGS);
61 Datum LWGEOM_to_text(PG_FUNCTION_ARGS);
62 Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS);
63 Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS);
64 Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS);
65 Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS);
66 Datum LWGEOM_recv(PG_FUNCTION_ARGS);
67 Datum LWGEOM_send(PG_FUNCTION_ARGS);
68 Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS);
69 Datum WKBFromLWGEOM(PG_FUNCTION_ARGS);
70 Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS);
71 Datum TWKBFromLWGEOMArray(PG_FUNCTION_ARGS);
72 Datum 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  */
85 Datum 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  */
214 Datum 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  */
289 Datum 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  */
300 Datum 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  {
314  variant = variant | WKB_XDR;
315  }
316  else
317  {
318  variant = variant | WKB_NDR;
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  */
336 Datum 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  */
351 Datum 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  */
382 Datum 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  */
405 Datum 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  {
419  variant = variant | WKB_XDR;
420  }
421  else
422  {
423  variant = variant | WKB_NDR;
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 
433 Datum 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) )
466  variant |= TWKB_SIZE;
467 
468  /* If user wants bounding boxes */
469  if ( PG_NARGS() > 5 && ! PG_ARGISNULL(5) && PG_GETARG_BOOL(5) )
470  variant |= TWKB_BBOX;
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 
479 Datum 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);
541  col = lwcollection_construct_empty(COLLECTIONTYPE, lwgeom_get_srid(geom), has_z, has_m);
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 */
602  variant = TWKB_ID;
603 
604  /* If user wants registered twkb sizes */
605  if ( PG_NARGS() > 5 && ! PG_ARGISNULL(5) && PG_GETARG_BOOL(5) )
606  variant |= TWKB_SIZE;
607 
608  /* If user wants bounding boxes */
609  if ( PG_NARGS() > 6 && ! PG_ARGISNULL(6) && PG_GETARG_BOOL(6) )
610  variant |= TWKB_BBOX;
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 */
620 Datum 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 */
636 Datum 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 */
649 void 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 */
661 Datum 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  */
691 Datum 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 
735 Datum 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 
748 Datum 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 
761 Datum 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.
Definition: gserialized.c:192
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)...
Definition: gserialized.c:155
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:268
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:118
GSERIALIZED * gserialized_drop_gbox(GSERIALIZED *g)
Remove the bounding box from a GSERIALIZED.
Definition: gserialized.c:81
#define LW_PARSER_CHECK_ALL
Definition: liblwgeom.h:2147
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:309
uint32_t lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition: lwgeom.c:1194
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition: lwgeom.c:927
LWGEOM * lwgeom_from_geojson(const char *geojson, char **srs)
Create an LWGEOM object from a GeoJSON representation.
Definition: lwin_geojson.c:411
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:1610
#define LW_FAILURE
Definition: liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1218
#define LW_PARSER_CHECK_NONE
Definition: liblwgeom.h:2146
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 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.
char * lwgeom_to_hexwkb_buffer(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:845
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
uint8_t * bytes_from_hexbytes(const char *hexbuf, size_t hexsize)
Definition: lwin_wkb.c:92
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1271
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:934
#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:2807
void lwfree(void *mem)
Definition: lwutil.c:248
#define TWKB_ID
Definition: liblwgeom.h:2226
#define WKB_EXTENDED
Definition: liblwgeom.h:2209
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwcollection.c:92
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 WKB_NDR
Definition: liblwgeom.h:2210
#define TWKB_DEFAULT_PRECISION
Definition: liblwgeom.h:2229
lwvarlena_t * lwgeom_to_hexwkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:875
#define TWKB_SIZE
Definition: liblwgeom.h:2225
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:189
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
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
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:941
lwvarlena_t * lwgeom_to_wkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:851
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:695
void lwgeom_parser_result_free(LWGEOM_PARSER_RESULT *parser_result)
Definition: lwin_wkt.c:921
#define TWKB_BBOX
Definition: liblwgeom.h:2224
#define WKB_XDR
Definition: liblwgeom.h:2211
This library is the generic geometry handling section of PostGIS.
#define str(s)
Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:405
Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:661
Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:433
PG_FUNCTION_INFO_V1(LWGEOM_in)
Datum LWGEOM_in(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:85
Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:214
Datum LWGEOM_out(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:289
Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:748
Datum LWGEOMFromTWKB(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:382
Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:761
Datum TWKBFromLWGEOMArray(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:479
Datum LWGEOM_send(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:735
Datum LWGEOM_dropBBOX(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:636
Datum LWGEOM_to_text(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:336
Datum LWGEOMFromEWKB(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:351
Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:620
void elog_ERROR(const char *string)
Definition: lwgeom_inout.c:649
Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:300
Datum LWGEOM_recv(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:691
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
Definition: lwinline.h:141
type
Definition: ovdump.py:42
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:2154