PostGIS  3.4.0dev-r@@SVN_REVISION@@
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Pages
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  /* If we picked up an SRID at the head of the WKB set it manually */
137  if ( srid ) lwgeom_set_srid(lwgeom, srid);
138  /* Add a bbox if necessary */
139  if ( lwgeom_needs_bbox(lwgeom) ) lwgeom_add_bbox(lwgeom);
140  lwfree(wkb);
141  ret = geometry_serialize(lwgeom);
142  lwgeom_free(lwgeom);
143  }
144  else if (str[0] == '{')
145  {
146  char *srs = NULL;
147  lwgeom = lwgeom_from_geojson(str, &srs);
148  if (srs)
149  {
150  srid = GetSRIDCacheBySRS(fcinfo, srs);
151  lwfree(srs);
152  lwgeom_set_srid(lwgeom, srid);
153  }
154  ret = geometry_serialize(lwgeom);
155  lwgeom_free(lwgeom);
156  }
157  /* WKT then. */
158  else
159  {
160  if ( lwgeom_parse_wkt(&lwg_parser_result, str, LW_PARSER_CHECK_ALL) == LW_FAILURE )
161  {
162  PG_PARSER_ERROR(lwg_parser_result);
163  PG_RETURN_NULL();
164  }
165  lwgeom = lwg_parser_result.geom;
166  if ( lwgeom_needs_bbox(lwgeom) )
167  lwgeom_add_bbox(lwgeom);
168  ret = geometry_serialize(lwgeom);
169  lwgeom_parser_result_free(&lwg_parser_result);
170  }
171 
172  if ( geom_typmod >= 0 )
173  {
174  ret = postgis_valid_typmod(ret, geom_typmod);
175  POSTGIS_DEBUG(3, "typmod and geometry were consistent");
176  }
177  else
178  {
179  POSTGIS_DEBUG(3, "typmod was -1");
180  }
181 
182  /* Don't free the parser result (and hence lwgeom) until we have done */
183  /* the typemod check with lwgeom */
184 
185  PG_RETURN_POINTER(ret);
186 
187 }
188 
189 /*
190  * LWGEOM_to_latlon(GEOMETRY, text)
191  * NOTE: Geometry must be a point. It is assumed that the coordinates
192  * of the point are in a lat/lon projection, and they will be
193  * normalized in the output to -90-90 and -180-180.
194  *
195  * The text parameter is a format string containing the format for the
196  * resulting text, similar to a date format string. Valid tokens
197  * are "D" for degrees, "M" for minutes, "S" for seconds, and "C" for
198  * cardinal direction (NSEW). DMS tokens may be repeated to indicate
199  * desired width and precision ("SSS.SSSS" means " 1.0023").
200  * "M", "S", and "C" are optional. If "C" is omitted, degrees are
201  * shown with a "-" sign if south or west. If "S" is omitted,
202  * minutes will be shown as decimal with as many digits of precision
203  * as you specify. If "M" is omitted, degrees are shown as decimal
204  * with as many digits precision as you specify.
205  *
206  * If the format string is omitted (null or 0-length) a default
207  * format will be used.
208  *
209  * returns text
210  */
212 Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS)
213 {
214  /* Get the parameters */
215  GSERIALIZED *pg_lwgeom = PG_GETARG_GSERIALIZED_P(0);
216  text *format_text = PG_GETARG_TEXT_P(1);
217 
218  LWGEOM *lwgeom;
219  char *format_str = NULL;
220 
221  char * formatted_str;
222  text * formatted_text;
223  char * tmp;
224 
225  /* Only supports points. */
226  uint8_t geom_type = gserialized_get_type(pg_lwgeom);
227  if (POINTTYPE != geom_type)
228  {
229  lwpgerror("Only points are supported, you tried type %s.", lwtype_name(geom_type));
230  }
231  /* Convert to LWGEOM type */
232  lwgeom = lwgeom_from_gserialized(pg_lwgeom);
233 
234  if (format_text == NULL) {
235  lwpgerror("ST_AsLatLonText: invalid format string (null");
236  PG_RETURN_NULL();
237  }
238 
239  if (!lwgeom_isfinite(lwgeom)) {
240  lwpgerror("ST_AsLatLonText: invalid coordinate");
241  PG_RETURN_NULL();
242  }
243 
244  format_str = text_to_cstring(format_text);
245  assert(format_str != NULL);
246 
247  /* The input string supposedly will be in the database encoding,
248  so convert to UTF-8. */
249  tmp = (char *)pg_do_encoding_conversion(
250  (uint8_t *)format_str, strlen(format_str), GetDatabaseEncoding(), PG_UTF8);
251  assert(tmp != NULL);
252  if ( tmp != format_str ) {
253  pfree(format_str);
254  format_str = tmp;
255  }
256 
257  /* Produce the formatted string. */
258  formatted_str = lwpoint_to_latlon((LWPOINT *)lwgeom, format_str);
259  assert(formatted_str != NULL);
260  pfree(format_str);
261 
262  /* Convert the formatted string from UTF-8 back to database encoding. */
263  tmp = (char *)pg_do_encoding_conversion(
264  (uint8_t *)formatted_str, strlen(formatted_str),
265  PG_UTF8, GetDatabaseEncoding());
266  assert(tmp != NULL);
267  if ( tmp != formatted_str) {
268  pfree(formatted_str);
269  formatted_str = tmp;
270  }
271 
272  /* Convert to the postgres output string type. */
273  formatted_text = cstring_to_text(formatted_str);
274  pfree(formatted_str);
275 
276  PG_RETURN_POINTER(formatted_text);
277 }
278 
279 /*
280  * LWGEOM_out(lwgeom) --> cstring
281  * output is 'SRID=#;<wkb in hex form>'
282  * ie. 'SRID=-99;0101000000000000000000F03F0000000000000040'
283  * WKB is machine endian
284  * if SRID=-1, the 'SRID=-1;' will probably not be present.
285  */
287 Datum LWGEOM_out(PG_FUNCTION_ARGS)
288 {
289  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
290  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
291  PG_RETURN_CSTRING(lwgeom_to_hexwkb_buffer(lwgeom, WKB_EXTENDED));
292 }
293 
294 /*
295  * AsHEXEWKB(geom, string)
296  */
298 Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS)
299 {
300  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
301  LWGEOM *lwgeom;
302  uint8_t variant = 0;
303 
304  /* If user specified endianness, respect it */
305  if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
306  {
307  text *type = PG_GETARG_TEXT_P(1);
308 
309  if ( ! strncmp(VARDATA(type), "xdr", 3) ||
310  ! strncmp(VARDATA(type), "XDR", 3) )
311  {
312  variant = variant | WKB_XDR;
313  }
314  else
315  {
316  variant = variant | WKB_NDR;
317  }
318  }
319 
320  /* Create WKB hex string */
321  lwgeom = lwgeom_from_gserialized(geom);
322  PG_RETURN_TEXT_P(lwgeom_to_hexwkb_varlena(lwgeom, variant | WKB_EXTENDED));
323 }
324 
325 
326 /*
327  * LWGEOM_to_text(lwgeom) --> text
328  * output is 'SRID=#;<wkb in hex form>'
329  * ie. 'SRID=-99;0101000000000000000000F03F0000000000000040'
330  * WKB is machine endian
331  * if SRID=-1, the 'SRID=-1;' will probably not be present.
332  */
334 Datum LWGEOM_to_text(PG_FUNCTION_ARGS)
335 {
336  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
337  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
338  PG_RETURN_TEXT_P(lwgeom_to_hexwkb_varlena(lwgeom, WKB_EXTENDED));
339 }
340 
341 /*
342  * LWGEOMFromEWKB(wkb, [SRID] )
343  * NOTE: wkb is in *binary* not hex form.
344  *
345  * NOTE: this function parses EWKB (extended form)
346  * which also contains SRID info.
347  */
349 Datum LWGEOMFromEWKB(PG_FUNCTION_ARGS)
350 {
351  bytea *bytea_wkb = PG_GETARG_BYTEA_P(0);
352  GSERIALIZED *geom;
353  LWGEOM *lwgeom;
354  uint8_t *wkb = (uint8_t*)VARDATA(bytea_wkb);
355 
356  lwgeom = lwgeom_from_wkb(wkb, VARSIZE_ANY_EXHDR(bytea_wkb), LW_PARSER_CHECK_ALL);
357  if (!lwgeom)
358  lwpgerror("Unable to parse WKB");
359 
360  if ((PG_NARGS() > 1) && (!PG_ARGISNULL(1)))
361  {
362  int32 srid = PG_GETARG_INT32(1);
363  lwgeom_set_srid(lwgeom, srid);
364  }
365 
366  if ( lwgeom_needs_bbox(lwgeom) )
367  lwgeom_add_bbox(lwgeom);
368 
369  geom = geometry_serialize(lwgeom);
370  lwgeom_free(lwgeom);
371  PG_FREE_IF_COPY(bytea_wkb, 0);
372  PG_RETURN_POINTER(geom);
373 }
374 /*
375  * LWGEOMFromTWKB(wkb)
376  * NOTE: twkb is in *binary* not hex form.
377  *
378  */
380 Datum LWGEOMFromTWKB(PG_FUNCTION_ARGS)
381 {
382  bytea *bytea_twkb = PG_GETARG_BYTEA_P(0);
383  GSERIALIZED *geom;
384  LWGEOM *lwgeom;
385  uint8_t *twkb = (uint8_t*)VARDATA(bytea_twkb);
386 
387  lwgeom = lwgeom_from_twkb(twkb, VARSIZE_ANY_EXHDR(bytea_twkb), LW_PARSER_CHECK_ALL);
388 
389  if (lwgeom_needs_bbox(lwgeom))
390  lwgeom_add_bbox(lwgeom);
391 
392  geom = geometry_serialize(lwgeom);
393  lwgeom_free(lwgeom);
394  PG_FREE_IF_COPY(bytea_twkb, 0);
395  PG_RETURN_POINTER(geom);
396 }
397 
398 /*
399  * WKBFromLWGEOM(lwgeom) --> wkb
400  * this will have no 'SRID=#;'
401  */
403 Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
404 {
405  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
406  LWGEOM *lwgeom;
407  uint8_t variant = 0;
408 
409  /* If user specified endianness, respect it */
410  if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
411  {
412  text *type = PG_GETARG_TEXT_P(1);
413 
414  if ( ! strncmp(VARDATA(type), "xdr", 3) ||
415  ! strncmp(VARDATA(type), "XDR", 3) )
416  {
417  variant = variant | WKB_XDR;
418  }
419  else
420  {
421  variant = variant | WKB_NDR;
422  }
423  }
424 
425  /* Create WKB hex string */
426  lwgeom = lwgeom_from_gserialized(geom);
427  PG_RETURN_BYTEA_P(lwgeom_to_wkb_varlena(lwgeom, variant | WKB_EXTENDED));
428 }
429 
431 Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS)
432 {
433  GSERIALIZED *geom;
434  LWGEOM *lwgeom;
435  uint8_t variant = 0;
436  srs_precision sp;
437 
438  /*check for null input since we cannot have the sql-function as strict.
439  That is because we use null as default for optional ID*/
440  if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
441 
442  geom = PG_GETARG_GSERIALIZED_P(0);
443 
444  /* Read sensible precision defaults (about one meter) given the srs */
445  sp = srid_axis_precision(gserialized_get_srid(geom), TWKB_DEFAULT_PRECISION);
446 
447  /* If user specified XY precision, use it */
448  if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
449  sp.precision_xy = PG_GETARG_INT32(1);
450 
451  /* If user specified Z precision, use it */
452  if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
453  sp.precision_z = PG_GETARG_INT32(2);
454 
455  /* If user specified M precision, use it */
456  if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
457  sp.precision_m = PG_GETARG_INT32(3);
458 
459  /* We don't permit ids for single geoemtries */
460  variant = variant & ~TWKB_ID;
461 
462  /* If user wants registered twkb sizes */
463  if ( PG_NARGS() > 4 && ! PG_ARGISNULL(4) && PG_GETARG_BOOL(4) )
464  variant |= TWKB_SIZE;
465 
466  /* If user wants bounding boxes */
467  if ( PG_NARGS() > 5 && ! PG_ARGISNULL(5) && PG_GETARG_BOOL(5) )
468  variant |= TWKB_BBOX;
469 
470  /* Create TWKB binary string */
471  lwgeom = lwgeom_from_gserialized(geom);
472  PG_RETURN_BYTEA_P(lwgeom_to_twkb(lwgeom, variant, sp.precision_xy, sp.precision_z, sp.precision_m));
473 }
474 
475 
477 Datum TWKBFromLWGEOMArray(PG_FUNCTION_ARGS)
478 {
479  ArrayType *arr_geoms = NULL;
480  ArrayType *arr_ids = NULL;
481  int num_geoms, num_ids, i = 0;
482 
483  ArrayIterator iter_geoms, iter_ids;
484  bool null_geom, null_id;
485  Datum val_geom, val_id;
486 
487  int is_homogeneous = true;
488  uint32_t subtype = 0;
489  int has_z = 0;
490  int has_m = 0;
491  LWCOLLECTION *col = NULL;
492  int64_t *idlist = NULL;
493  uint8_t variant = 0;
494 
495  srs_precision sp;
496 
497  /* The first two arguments are required */
498  if ( PG_NARGS() < 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1) )
499  PG_RETURN_NULL();
500 
501  arr_geoms = PG_GETARG_ARRAYTYPE_P(0);
502  arr_ids = PG_GETARG_ARRAYTYPE_P(1);
503 
504  num_geoms = ArrayGetNItems(ARR_NDIM(arr_geoms), ARR_DIMS(arr_geoms));
505  num_ids = ArrayGetNItems(ARR_NDIM(arr_ids), ARR_DIMS(arr_ids));
506 
507  if ( num_geoms != num_ids )
508  {
509  elog(ERROR, "size of geometry[] and integer[] arrays must match");
510  PG_RETURN_NULL();
511  }
512 
513  /* Loop through array and build a collection of geometry and */
514  /* a simple array of ids. If either side is NULL, skip it */
515 
516  iter_geoms = array_create_iterator(arr_geoms, 0, NULL);
517  iter_ids = array_create_iterator(arr_ids, 0, NULL);
518 
519  while( array_iterate(iter_geoms, &val_geom, &null_geom) &&
520  array_iterate(iter_ids, &val_id, &null_id) )
521  {
522  LWGEOM *geom;
523  int32_t uid;
524 
525  if ( null_geom || null_id )
526  {
527  elog(NOTICE, "ST_AsTWKB skipping NULL entry at position %d", i);
528  continue;
529  }
530 
531  geom = lwgeom_from_gserialized((GSERIALIZED*)DatumGetPointer(val_geom));
532  uid = DatumGetInt64(val_id);
533 
534  /* Construct collection/idlist first time through */
535  if ( ! col )
536  {
537  has_z = lwgeom_has_z(geom);
538  has_m = lwgeom_has_m(geom);
539  col = lwcollection_construct_empty(COLLECTIONTYPE, lwgeom_get_srid(geom), has_z, has_m);
540  }
541  if ( ! idlist )
542  idlist = palloc0(num_geoms * sizeof(int64_t));
543 
544 
545  /* Check if there is differences in dimensionality*/
546  if( lwgeom_has_z(geom)!=has_z || lwgeom_has_m(geom)!=has_m)
547  {
548  elog(ERROR, "Geometries have different dimensionality");
549  PG_FREE_IF_COPY(arr_geoms, 0);
550  PG_FREE_IF_COPY(arr_ids, 1);
551  PG_RETURN_NULL();
552  }
553  /* Store the values */
554  lwcollection_add_lwgeom(col, geom);
555  idlist[i++] = uid;
556 
557  /* Grab the geometry type and note if all geometries share it */
558  /* If so, we can make this a homogeneous collection and save some space */
559  if ( lwgeom_get_type(geom) != subtype && subtype )
560  {
561  is_homogeneous = false;
562  }
563  else
564  {
565  subtype = lwgeom_get_type(geom);
566  }
567 
568  }
569  array_free_iterator(iter_geoms);
570  array_free_iterator(iter_ids);
571 
572  if(i==0)
573  {
574  elog(NOTICE, "No valid geometry - id pairs found");
575  PG_FREE_IF_COPY(arr_geoms, 0);
576  PG_FREE_IF_COPY(arr_ids, 1);
577  PG_RETURN_NULL();
578  }
579  if ( is_homogeneous )
580  {
581  col->type = lwtype_get_collectiontype(subtype);
582  }
583 
584  /* Read sensible precision defaults (about one meter) given the srs */
585  sp = srid_axis_precision(lwgeom_get_srid(lwcollection_as_lwgeom(col)), TWKB_DEFAULT_PRECISION);
586 
587  /* If user specified XY precision, use it */
588  if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
589  sp.precision_xy = PG_GETARG_INT32(2);
590 
591  /* If user specified Z precision, use it */
592  if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
593  sp.precision_z = PG_GETARG_INT32(3);
594 
595  /* If user specified M precision, use it */
596  if ( PG_NARGS() > 4 && ! PG_ARGISNULL(4) )
597  sp.precision_m = PG_GETARG_INT32(4);
598 
599  /* We are building an ID'ed output */
600  variant = TWKB_ID;
601 
602  /* If user wants registered twkb sizes */
603  if ( PG_NARGS() > 5 && ! PG_ARGISNULL(5) && PG_GETARG_BOOL(5) )
604  variant |= TWKB_SIZE;
605 
606  /* If user wants bounding boxes */
607  if ( PG_NARGS() > 6 && ! PG_ARGISNULL(6) && PG_GETARG_BOOL(6) )
608  variant |= TWKB_BBOX;
609 
610  /* Write out the TWKB */
611  PG_RETURN_BYTEA_P(lwgeom_to_twkb_with_idlist(
612  lwcollection_as_lwgeom(col), idlist, variant, sp.precision_xy, sp.precision_z, sp.precision_m));
613 }
614 
615 
616 /* puts a bbox inside the geometry */
618 Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS)
619 {
620  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
622  LWGEOM *lwgeom;
623 
624  lwgeom = lwgeom_from_gserialized(geom);
625  lwgeom_add_bbox(lwgeom);
626  result = geometry_serialize(lwgeom);
627 
628  PG_FREE_IF_COPY(geom, 0);
629  PG_RETURN_POINTER(result);
630 }
631 
632 /* removes a bbox from a geometry */
634 Datum LWGEOM_dropBBOX(PG_FUNCTION_ARGS)
635 {
636  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
637 
638  /* No box? we're done already! */
639  if ( ! gserialized_has_bbox(geom) )
640  PG_RETURN_POINTER(geom);
641 
642  PG_RETURN_POINTER(gserialized_drop_gbox(geom));
643 }
644 
645 
646 /* for the wkt parser */
647 void elog_ERROR(const char* string)
648 {
649  elog(ERROR, "%s", string);
650 }
651 
652 /*
653 * This just does the same thing as the _in function,
654 * except it has to handle a 'text' input. First
655 * unwrap the text into a cstring, then call
656 * geometry_in
657 */
659 Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS)
660 {
661  text *wkt_text = PG_GETARG_TEXT_P(0);
662  char *wkt;
663  Datum result;
664 
665  /* Unwrap the PgSQL text type into a cstring */
666  wkt = text_to_cstring(wkt_text);
667 
668  /* Now we call over to the geometry_in function
669  * We need to initialize the fcinfo since cache might be used
670  */
671  result = CallerFInfoFunctionCall1(LWGEOM_in, fcinfo->flinfo, InvalidOid, CStringGetDatum(wkt));
672 
673  /* Return null on null */
674  if ( ! result )
675  PG_RETURN_NULL();
676 
677  PG_RETURN_DATUM(result);
678 }
679 
680 
681 /*
682  * This function must advance the StringInfo.cursor pointer
683  * and leave it at the end of StringInfo.buf. If it fails
684  * to do so the backend will raise an exception with message:
685  * ERROR: incorrect binary data format in bind parameter #
686  *
687  */
689 Datum LWGEOM_recv(PG_FUNCTION_ARGS)
690 {
691  StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
692  int32 geom_typmod = -1;
693  GSERIALIZED *geom;
694  LWGEOM *lwgeom;
695 
696  if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) {
697  geom_typmod = PG_GETARG_INT32(2);
698  }
699 
700  lwgeom = lwgeom_from_wkb((uint8_t*)buf->data, buf->len, LW_PARSER_CHECK_ALL);
701 
702  if ( lwgeom_needs_bbox(lwgeom) )
703  lwgeom_add_bbox(lwgeom);
704 
705  /* Set cursor to the end of buffer (so the backend is happy) */
706  buf->cursor = buf->len;
707 
708  geom = geometry_serialize(lwgeom);
709  lwgeom_free(lwgeom);
710 
711  if ( geom_typmod >= 0 )
712  {
713  geom = postgis_valid_typmod(geom, geom_typmod);
714  POSTGIS_DEBUG(3, "typmod and geometry were consistent");
715  }
716  else
717  {
718  POSTGIS_DEBUG(3, "typmod was -1");
719  }
720 
721 
722  PG_RETURN_POINTER(geom);
723 }
724 
725 
726 
728 Datum LWGEOM_send(PG_FUNCTION_ARGS)
729 {
730  POSTGIS_DEBUG(2, "LWGEOM_send called");
731 
732  PG_RETURN_POINTER(
733  DatumGetPointer(
734  DirectFunctionCall1(
736  PG_GETARG_DATUM(0)
737  )));
738 }
739 
741 Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS)
742 {
743  POSTGIS_DEBUG(2, "LWGEOM_to_bytea called");
744 
745  PG_RETURN_POINTER(
746  DatumGetPointer(
747  DirectFunctionCall1(
749  PG_GETARG_DATUM(0)
750  )));
751 }
752 
754 Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS)
755 {
757 
758  POSTGIS_DEBUG(2, "LWGEOM_from_bytea start");
759 
760  result = (GSERIALIZED *)DatumGetPointer(DirectFunctionCall1(
761  LWGEOMFromEWKB, PG_GETARG_DATUM(0)));
762 
763  PG_RETURN_POINTER(result);
764 }
765 
static uint8_t variant
Definition: cu_in_twkb.c:26
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:262
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:163
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:126
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:239
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
GSERIALIZED * gserialized_drop_gbox(GSERIALIZED *g)
Remove the bounding box from a GSERIALIZED.
Definition: gserialized.c:52
#define LW_PARSER_CHECK_ALL
Definition: liblwgeom.h:2115
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:1131
#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:1547
#define LW_FAILURE
Definition: liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
#define LW_PARSER_CHECK_NONE
Definition: liblwgeom.h:2114
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:880
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:1208
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:2681
void lwfree(void *mem)
Definition: lwutil.c:242
#define TWKB_ID
Definition: liblwgeom.h:2194
#define WKB_EXTENDED
Definition: liblwgeom.h:2177
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:431
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:2178
#define TWKB_DEFAULT_PRECISION
Definition: liblwgeom.h:2197
lwvarlena_t * lwgeom_to_hexwkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:875
#define TWKB_SIZE
Definition: liblwgeom.h:2193
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:188
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:834
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:886
#define TWKB_BBOX
Definition: liblwgeom.h:2192
#define WKB_XDR
Definition: liblwgeom.h:2179
This library is the generic geometry handling section of PostGIS.
#define str(s)
Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:403
Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:659
Datum TWKBFromLWGEOM(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:431
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:212
Datum LWGEOM_out(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:287
Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:741
Datum LWGEOMFromTWKB(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:380
Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:754
Datum TWKBFromLWGEOMArray(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:477
Datum LWGEOM_send(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:728
Datum LWGEOM_dropBBOX(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:634
Datum LWGEOM_to_text(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:334
Datum LWGEOMFromEWKB(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:349
Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:618
void elog_ERROR(const char *string)
Definition: lwgeom_inout.c:647
Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:298
Datum LWGEOM_recv(PG_FUNCTION_ARGS)
Definition: lwgeom_inout.c:689
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
Definition: lwinline.h:145
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:2122