11
#include "access/gist.h"
12
#include "access/itup.h"
15
#include "utils/elog.h"
17
# include "lib/stringinfo.h" /* for binary input */
21
#include "liblwgeom.h"
22
#include "stringBuffer.h"
25
/* #define PGIS_DEBUG 1 */
27
#include "lwgeom_pg.h"
31
void elog_ERROR(const char* string);
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 parse_WKT_lwgeom(PG_FUNCTION_ARGS);
41
Datum LWGEOM_recv(PG_FUNCTION_ARGS);
42
Datum LWGEOM_send(PG_FUNCTION_ARGS);
44
Datum BOOL_to_text(PG_FUNCTION_ARGS);
48
* included here so we can be independent from postgis
49
* WKB structure -- exactly the same as TEXT
51
typedef struct Well_known_bin {
52
int32 size; /* total size of this structure */
53
uchar data[1]; /* THIS HOLD VARIABLE LENGTH DATA */
59
* format is '[SRID=#;]wkt|wkb'
60
* LWGEOM_in( 'SRID=99;POINT(0 0)')
61
* LWGEOM_in( 'POINT(0 0)') --> assumes SRID=-1
62
* LWGEOM_in( 'SRID=99;0101000000000000000000F03F000000000000004')
63
* returns a PG_LWGEOM object
65
PG_FUNCTION_INFO_V1(LWGEOM_in);
66
Datum LWGEOM_in(PG_FUNCTION_ARGS)
68
char *str = PG_GETARG_CSTRING(0);
69
SERIALIZED_LWGEOM *serialized_lwgeom;
73
/* will handle both HEXEWKB and EWKT */
74
serialized_lwgeom = parse_lwgeom_wkt(str);
75
lwgeom = lwgeom_deserialize(serialized_lwgeom->lwgeom);
77
ret = pglwgeom_serialize(lwgeom);
78
lwgeom_release(lwgeom);
80
if ( is_worth_caching_pglwgeom_bbox(ret) )
82
ret = (PG_LWGEOM *)DatumGetPointer(DirectFunctionCall1(
83
LWGEOM_addBBOX, PointerGetDatum(ret)));
86
PG_RETURN_POINTER(ret);
90
* LWGEOM_out(lwgeom) --> cstring
91
* output is 'SRID=#;<wkb in hex form>'
92
* ie. 'SRID=-99;0101000000000000000000F03F0000000000000040'
93
* WKB is machine endian
94
* if SRID=-1, the 'SRID=-1;' will probably not be present.
96
PG_FUNCTION_INFO_V1(LWGEOM_out);
97
Datum LWGEOM_out(PG_FUNCTION_ARGS)
104
lwgeom = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
105
result = unparse_WKB(SERIALIZED_FORM(lwgeom),lwalloc,lwfree,-1,NULL,1);
107
PG_RETURN_CSTRING(result);
111
* AsHEXEWKB(geom, string)
113
PG_FUNCTION_INFO_V1(LWGEOM_asHEXEWKB);
114
Datum LWGEOM_asHEXEWKB(PG_FUNCTION_ARGS)
121
unsigned int byteorder=-1;
125
lwgeom = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
127
if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
129
type = PG_GETARG_TEXT_P(1);
130
if (VARSIZE(type) < 7)
132
elog(ERROR,"AsHEXEWKB(geometry, <type>) - type should be 'XDR' or 'NDR'. type length is %i",VARSIZE(type) -VARHDRSZ);
136
if ( ! strncmp(VARDATA(type), "xdr", 3) ||
137
! strncmp(VARDATA(type), "XDR", 3) )
147
result = unparse_WKB(SERIALIZED_FORM(lwgeom),lwalloc,lwfree,
148
byteorder, &size, 1);
150
text_result = palloc(size+VARHDRSZ);
151
memcpy(VARDATA(text_result),result,size);
152
SET_VARSIZE(text_result, size+VARHDRSZ);
155
PG_RETURN_POINTER(text_result);
160
* LWGEOM_to_text(lwgeom) --> text
161
* output is 'SRID=#;<wkb in hex form>'
162
* ie. 'SRID=-99;0101000000000000000000F03F0000000000000040'
163
* WKB is machine endian
164
* if SRID=-1, the 'SRID=-1;' will probably not be present.
166
PG_FUNCTION_INFO_V1(LWGEOM_to_text);
167
Datum LWGEOM_to_text(PG_FUNCTION_ARGS)
176
lwgeom = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
177
result = unparse_WKB(SERIALIZED_FORM(lwgeom),lwalloc,lwfree,-1,&size,1);
179
text_result = palloc(size+VARHDRSZ);
180
memcpy(VARDATA(text_result),result,size);
181
SET_VARSIZE(text_result, size+VARHDRSZ);
184
PG_RETURN_POINTER(text_result);
188
* LWGEOMFromWKB(wkb, [SRID] )
189
* NOTE: wkb is in *binary* not hex form.
191
* NOTE: this function parses EWKB (extended form)
192
* which also contains SRID info. When the SRID
193
* argument is provided it will override any SRID
194
* info found in EWKB format.
196
* NOTE: this function is *unoptimized* as will copy
197
* the object when adding SRID and when adding BBOX.
198
* additionally, it suffers from the non-optimal
199
* pglwgeom_from_ewkb function.
202
PG_FUNCTION_INFO_V1(LWGEOMFromWKB);
203
Datum LWGEOMFromWKB(PG_FUNCTION_ARGS)
205
WellKnownBinary *wkb_input;
206
PG_LWGEOM *lwgeom, *lwgeom2;
208
wkb_input = (WellKnownBinary *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
210
lwgeom2 = pglwgeom_from_ewkb((uchar *)VARDATA(wkb_input),
211
VARSIZE(wkb_input)-VARHDRSZ);
213
if ( ( PG_NARGS()>1) && ( ! PG_ARGISNULL(1) ))
215
lwgeom = pglwgeom_setSRID(lwgeom2, PG_GETARG_INT32(1));
218
else lwgeom = lwgeom2;
220
if ( is_worth_caching_pglwgeom_bbox(lwgeom) )
222
lwgeom = (PG_LWGEOM *)DatumGetPointer(DirectFunctionCall1(
223
LWGEOM_addBBOX, PointerGetDatum(lwgeom)));
226
PG_RETURN_POINTER(lwgeom);
230
* WKBFromLWGEOM(lwgeom) --> wkb
231
* this will have no 'SRID=#;'
233
PG_FUNCTION_INFO_V1(WKBFromLWGEOM);
234
Datum WKBFromLWGEOM(PG_FUNCTION_ARGS)
236
/* #define BINARY_FROM_HEX 1 */
238
PG_LWGEOM *lwgeom_input; /* SRID=#;<hexized wkb> */
239
char *hexized_wkb; /* hexized_wkb_srid w/o srid */
240
char *result; /* wkb */
242
#ifdef BINARY_FROM_HEX
243
char *hexized_wkb_srid;
246
#endif /* BINARY_FROM_HEX */
248
unsigned int byteorder=-1;
252
profstart(PROF_QRUN);
257
if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
259
type = PG_GETARG_TEXT_P(1);
260
if (VARSIZE(type) < 7)
262
elog(ERROR,"asbinary(geometry, <type>) - type should be 'XDR' or 'NDR'. type length is %i",VARSIZE(type) -VARHDRSZ);
266
if ( ! strncmp(VARDATA(type), "xdr", 3) ||
267
! strncmp(VARDATA(type), "XDR", 3) )
277
lwgeom_input = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
279
#ifdef BINARY_FROM_HEX
280
hexized_wkb_srid = unparse_WKB(SERIALIZED_FORM(lwgeom_input),
281
lwalloc, lwfree, byteorder, &size, 1);
284
elog(NOTICE, "in WKBFromLWGEOM with WKB = '%s'", hexized_wkb_srid);
287
hexized_wkb = hexized_wkb_srid;
289
semicolonLoc = strchr(hexized_wkb_srid,';');
290
if (semicolonLoc != NULL)
292
hexized_wkb = (semicolonLoc+1);
296
elog(NOTICE, "in WKBFromLWGEOM with WKB (with no 'SRID=#;' = '%s'",
300
size_result = size/2 + VARHDRSZ;
301
result = palloc(size_result);
302
SET_VARSIZE(result, size_result);
304
/* have a hexized string, want to make it binary */
305
for (t=0; t< (size/2); t++)
307
((uchar *) VARDATA(result))[t] = parse_hex( hexized_wkb + (t*2) );
310
pfree(hexized_wkb_srid);
312
#else /* ndef BINARY_FROM_HEX */
314
hexized_wkb = unparse_WKB(SERIALIZED_FORM(lwgeom_input),
315
lwalloc, lwfree, byteorder, &size, 0);
317
size_result = size+VARHDRSZ;
318
result = palloc(size_result);
319
SET_VARSIZE(result, size_result);
320
memcpy(VARDATA(result), hexized_wkb, size);
327
lwnotice("unparse_WKB: prof: %lu", proftime[PROF_QRUN]);
331
lwnotice("Output size is %lu (comp: %lu)",
332
VARSIZE(result), (unsigned long)size);
333
#endif /* def PGIS_DEBUG */
336
PG_RETURN_POINTER(result);
339
/* puts a bbox inside the geometry */
340
PG_FUNCTION_INFO_V1(LWGEOM_addBBOX);
341
Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS)
343
PG_LWGEOM *lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
350
elog(NOTICE,"in LWGEOM_addBBOX");
353
if (lwgeom_hasBBOX( lwgeom->type ) )
356
elog(NOTICE,"LWGEOM_addBBOX -- already has bbox");
358
/* easy - already has one. Just copy! */
359
result = palloc (VARSIZE(lwgeom));
360
SET_VARSIZE(result, VARSIZE(lwgeom));
361
memcpy(VARDATA(result), VARDATA(lwgeom), VARSIZE(lwgeom)-VARHDRSZ);
362
PG_RETURN_POINTER(result);
366
elog(NOTICE,"LWGEOM_addBBOX -- giving it a bbox");
369
/* construct new one */
370
if ( ! getbox2d_p(SERIALIZED_FORM(lwgeom), &box) )
372
/* Empty geom, no bbox to add */
373
result = palloc (VARSIZE(lwgeom));
374
SET_VARSIZE(result, VARSIZE(lwgeom));
375
memcpy(VARDATA(result), VARDATA(lwgeom), VARSIZE(lwgeom)-VARHDRSZ);
376
PG_RETURN_POINTER(result);
378
old_type = lwgeom->type;
380
size = VARSIZE(lwgeom)+sizeof(BOX2DFLOAT4);
382
result = palloc(size); /* 16 for bbox2d */
383
SET_VARSIZE(result, size);
385
result->type = lwgeom_makeType_full(
388
lwgeom_hasSRID(old_type), lwgeom_getType(old_type), 1);
391
memcpy(result->data, &box, sizeof(BOX2DFLOAT4));
394
lwnotice("result->type hasbbox: %d", TYPE_HASBBOX(result->type));
395
lwnotice("LWGEOM_addBBOX -- about to copy serialized form");
398
/* everything but the type and length */
399
memcpy((char *)VARDATA(result)+sizeof(BOX2DFLOAT4)+1, (char *)VARDATA(lwgeom)+1, VARSIZE(lwgeom)-VARHDRSZ-1);
401
PG_RETURN_POINTER(result);
405
is_worth_caching_pglwgeom_bbox(const PG_LWGEOM *in)
410
if ( TYPE_GETTYPE(in->type) == POINTTYPE ) return false;
415
is_worth_caching_serialized_bbox(const uchar *in)
420
if ( TYPE_GETTYPE((uchar)in[0]) == POINTTYPE ) return false;
425
is_worth_caching_lwgeom_bbox(const LWGEOM *in)
430
if ( TYPE_GETTYPE(in->type) == POINTTYPE ) return false;
434
/* removes a bbox from a geometry */
435
PG_FUNCTION_INFO_V1(LWGEOM_dropBBOX);
436
Datum LWGEOM_dropBBOX(PG_FUNCTION_ARGS)
438
PG_LWGEOM *lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
444
elog(NOTICE,"in LWGEOM_dropBBOX");
447
if (!lwgeom_hasBBOX( lwgeom->type ) )
450
elog(NOTICE,"LWGEOM_dropBBOX -- doesnt have a bbox already");
452
result = palloc (VARSIZE(lwgeom));
453
SET_VARSIZE(result, VARSIZE(lwgeom));
454
memcpy(VARDATA(result), VARDATA(lwgeom), VARSIZE(lwgeom)-VARHDRSZ);
455
PG_RETURN_POINTER(result);
459
elog(NOTICE,"LWGEOM_dropBBOX -- dropping the bbox");
462
/* construct new one */
463
old_type = lwgeom->type;
465
size = VARSIZE(lwgeom)-sizeof(BOX2DFLOAT4);
467
result = palloc(size); /* 16 for bbox2d */
468
SET_VARSIZE(result, size);
470
result->type = lwgeom_makeType_full(
473
lwgeom_hasSRID(old_type), lwgeom_getType(old_type), 0);
475
/* everything but the type and length */
476
memcpy((char *)VARDATA(result)+1, ((char *)(lwgeom->data))+sizeof(BOX2DFLOAT4), size-VARHDRSZ-1);
478
PG_RETURN_POINTER(result);
482
/* for the wkt parser */
483
void elog_ERROR(const char* string)
490
* parse_WKT_lwgeom(TEXT) -> LWGEOM
492
PG_FUNCTION_INFO_V1(parse_WKT_lwgeom);
493
Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS)
496
text *wkt_input = PG_GETARG_TEXT_P(0);
497
PG_LWGEOM *ret; /*with length */
498
SERIALIZED_LWGEOM *serialized_lwgeom;
505
wkt_size = VARSIZE(wkt_input)-VARHDRSZ; /* actual letters */
507
wkt = palloc( wkt_size+1); /* +1 for null */
508
memcpy(wkt, VARDATA(wkt_input), wkt_size );
509
wkt[wkt_size] = 0; /* null term */
513
elog(NOTICE,"in parse_WKT_lwgeom with input: '%s'",wkt);
516
serialized_lwgeom = parse_lwg((const char *)wkt, (allocator)lwalloc, (report_error)elog_ERROR);
517
lwgeom = lwgeom_deserialize(serialized_lwgeom->lwgeom);
519
ret = pglwgeom_serialize(lwgeom);
520
lwgeom_release(lwgeom);
523
elog(NOTICE,"parse_WKT_lwgeom:: finished parse");
528
if (ret == NULL) elog(ERROR,"parse_WKT:: couldnt parse!");
530
if ( is_worth_caching_pglwgeom_bbox(ret) )
532
ret = (PG_LWGEOM *)DatumGetPointer(DirectFunctionCall1(
533
LWGEOM_addBBOX, PointerGetDatum(ret)));
536
PG_RETURN_POINTER(ret);
542
* This function must advance the StringInfo.cursor pointer
543
* and leave it at the end of StringInfo.buf. If it fails
544
* to do so the backend will raise an exception with message:
545
* ERROR: incorrect binary data format in bind parameter #
548
PG_FUNCTION_INFO_V1(LWGEOM_recv);
549
Datum LWGEOM_recv(PG_FUNCTION_ARGS)
551
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
556
elog(NOTICE, "LWGEOM_recv start");
559
/* Add VARLENA size info to make it a valid varlena object */
560
wkb = (bytea *)palloc(buf->len+VARHDRSZ);
561
SET_VARSIZE(wkb, buf->len+VARHDRSZ);
562
memcpy(VARDATA(wkb), buf->data, buf->len);
565
elog(NOTICE, "LWGEOM_recv calling LWGEOMFromWKB");
568
/* Call LWGEOM_from_bytea function... */
569
result = (PG_LWGEOM *)DatumGetPointer(DirectFunctionCall1(
570
LWGEOMFromWKB, PointerGetDatum(wkb)));
573
elog(NOTICE, "LWGEOM_recv advancing StringInfo buffer");
577
elog(NOTICE, "LWGEOM_from_bytea returned %s", unparse_WKB(SERIALIZED_FORM(result),pg_alloc,pg_free,-1,NULL,1));
581
/* Set cursor to the end of buffer (so the backend is happy) */
582
buf->cursor = buf->len;
585
elog(NOTICE, "LWGEOM_recv returning");
588
PG_RETURN_POINTER(result);
591
PG_FUNCTION_INFO_V1(LWGEOM_send);
592
Datum LWGEOM_send(PG_FUNCTION_ARGS)
597
elog(NOTICE, "LWGEOM_send called");
600
result = (bytea *)DatumGetPointer(DirectFunctionCall1(
601
WKBFromLWGEOM, PG_GETARG_DATUM(0)));
603
PG_RETURN_POINTER(result);
607
#endif /* USE_VERSION > 73 */
609
PG_FUNCTION_INFO_V1(LWGEOM_to_bytea);
610
Datum LWGEOM_to_bytea(PG_FUNCTION_ARGS)
615
elog(NOTICE, "LWGEOM_to_bytea called");
618
result = (bytea *)DatumGetPointer(DirectFunctionCall1(
619
WKBFromLWGEOM, PG_GETARG_DATUM(0)));
621
PG_RETURN_POINTER(result);
624
PG_FUNCTION_INFO_V1(LWGEOM_from_bytea);
625
Datum LWGEOM_from_bytea(PG_FUNCTION_ARGS)
630
elog(NOTICE, "LWGEOM_from_bytea start");
633
result = (PG_LWGEOM *)DatumGetPointer(DirectFunctionCall1(
634
LWGEOMFromWKB, PG_GETARG_DATUM(0)));
636
PG_RETURN_POINTER(result);
639
PG_FUNCTION_INFO_V1(BOOL_to_text);
640
Datum BOOL_to_text(PG_FUNCTION_ARGS)
642
bool b = PG_GETARG_BOOL(0);
648
result = palloc(VARHDRSZ+1*sizeof(char));
649
SET_VARSIZE(result, VARHDRSZ+1*sizeof(char));
650
memcpy(VARDATA(result), &c, 1*sizeof(char));
652
PG_RETURN_POINTER(result);