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