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