source: trunk/lwgeom/lwgeom_pg.c @ 2815

Last change on this file since 2815 was 2815, checked in by mcayland, 8 years ago

Split the basic geometry accessors into a separate static library liblwgeom.a; this potentially allows re-use of the liblwgeom functions from within PostGIS, or could be extended at a later date to include databases other than MySQL. This patch includes a change to the liblwgeom handler functions; instead of sprinkling init_pg_func()s around the source, I have changed the default liblwgeom handlers to make use of a callback to allow linked libraries to set their own handlers the first time any of them are called. I have also tidied up the parser API a little in liblwgeom.h, which means wktparse.h can be removed from all of the headers in the lwgeom/ directory, plus renamed wktunparse.c to lwgunparse.c to keep things similar to lwgparse.c. Finally, I renamed liblwgeom.c to lwutil.c to avoid confusion within the new interface. TODO: the liblwgeom Makefile has some gcc-specific options, but these can be fixed later - it seemed more important to make the warnings visible to developers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mime-type set to text/plain
File size: 7.9 KB
Line 
1#include "../postgis_config.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <stdarg.h>
6#include <postgres.h>
7#include <fmgr.h>
8#include <executor/spi.h>
9#include "liblwgeom.h"
10#include "lwgeom_pg.h"
11
12
13#define PARANOIA_LEVEL 1
14
15/*
16 * This is required for builds against pgsql 8.2
17 */
18#ifdef PG_MODULE_MAGIC
19PG_MODULE_MAGIC;
20#endif
21
22void *
23pg_alloc(size_t size)
24{
25        void * result;
26
27        POSTGIS_DEBUGF(5, "  pg_alloc(%d) called", (int)size);
28
29        result = palloc(size);
30
31        POSTGIS_DEBUGF(5, "  pg_alloc(%d) returning %p", (int)size, result);
32
33        if ( ! result )
34        {
35                ereport(ERROR, (errmsg_internal("Out of virtual memory")));
36                return NULL;
37        }
38        return result;
39}
40
41void *
42pg_realloc(void *mem, size_t size)
43{
44        void * result;
45
46        POSTGIS_DEBUGF(5, "  pg_realloc(%p, %d) called", mem, (int)size);
47
48        result = repalloc(mem, size);
49
50        POSTGIS_DEBUGF(5, "  pg_realloc(%p, %d) returning %p", mem, (int)size, result);
51
52        return result;
53}
54
55void
56pg_free(void *ptr)
57{
58        pfree(ptr);
59}
60
61void
62pg_error(const char *fmt, ...)
63{
64#define ERRMSG_MAXLEN 256
65
66        char errmsg[ERRMSG_MAXLEN+1];
67        va_list ap;
68
69        va_start (ap, fmt);
70        vsnprintf (errmsg, ERRMSG_MAXLEN, fmt, ap);
71        va_end (ap);
72
73        errmsg[ERRMSG_MAXLEN]='\0';
74        ereport(ERROR, (errmsg_internal("%s", errmsg)));
75}
76
77void
78pg_notice(const char *fmt, ...)
79{
80        char *msg;
81        va_list ap;
82
83        va_start (ap, fmt);
84
85        /*
86         * This is a GNU extension.
87         * Dunno how to handle errors here.
88         */
89        if (!vasprintf (&msg, fmt, ap))
90        {
91                va_end (ap);
92                return;
93        }
94        ereport(NOTICE, (errmsg_internal("%s", msg)));
95        va_end(ap);
96        free(msg);
97}
98
99void
100lwgeom_init_allocators(void)
101{
102        /* liblwgeom callback - install PostgreSQL handlers */
103        lwalloc_var = pg_alloc;
104        lwrealloc_var = pg_realloc;
105        lwfree_var = pg_free;
106        lwerror = pg_error;
107        lwnotice = pg_notice;
108}
109
110PG_LWGEOM *
111pglwgeom_serialize(LWGEOM *in)
112{
113        size_t size;
114        PG_LWGEOM *result;
115
116#if POSTGIS_AUTOCACHE_BBOX
117        if ( ! in->bbox && is_worth_caching_lwgeom_bbox(in) )
118        {
119                lwgeom_addBBOX(in);
120        }
121#endif
122
123        size = lwgeom_serialize_size(in) + VARHDRSZ;
124
125        POSTGIS_DEBUGF(3, "lwgeom_serialize_size returned %d", (int)size-VARHDRSZ);
126
127        result = palloc(size);
128        SET_VARSIZE(result, size);
129        lwgeom_serialize_buf(in, SERIALIZED_FORM(result), &size);
130
131        POSTGIS_DEBUGF(3, "pglwgeom_serialize: serialized size: %d, computed size: %d", (int)size, VARSIZE(result)-VARHDRSZ);
132
133#if PARANOIA_LEVEL > 0
134        if ( size != VARSIZE(result)-VARHDRSZ )
135        {
136                lwerror("pglwgeom_serialize: serialized size:%d, computed size:%d", (int)size, VARSIZE(result)-VARHDRSZ);
137                return NULL;
138        }
139#endif
140
141        return result;
142}
143
144LWGEOM *
145pglwgeom_deserialize(PG_LWGEOM *in)
146{
147        return lwgeom_deserialize(SERIALIZED_FORM(in));
148}
149
150Oid
151getGeometryOID(void)
152{
153        static Oid OID = InvalidOid;
154        int SPIcode;
155        bool isnull;
156        char *query = "select OID from pg_type where typname = 'geometry'";     
157
158        if ( OID != InvalidOid ) return OID;
159       
160        SPIcode = SPI_connect();
161        if (SPIcode  != SPI_OK_CONNECT) {
162                lwerror("getGeometryOID(): couldn't connection to SPI");
163        }
164
165        SPIcode = SPI_exec(query, 0);
166        if (SPIcode != SPI_OK_SELECT ) {
167                lwerror("getGeometryOID(): error querying geometry oid");
168        }
169        if (SPI_processed != 1) {
170                lwerror("getGeometryOID(): error querying geometry oid");
171        }
172
173        OID = (Oid)SPI_getbinval(SPI_tuptable->vals[0],
174                SPI_tuptable->tupdesc, 1, &isnull);
175
176        if (isnull)
177                lwerror("getGeometryOID(): couldn't find geometry oid");
178
179        return OID;
180}
181
182PG_LWGEOM *
183PG_LWGEOM_construct(uchar *ser, int SRID, int wantbbox)
184{
185        int size;
186        uchar *iptr, *optr, *eptr;
187        int wantsrid = 0;
188        BOX2DFLOAT4 box;
189        PG_LWGEOM *result;
190
191        /* COMPUTE_BBOX FOR_COMPLEX_GEOMS */
192        if ( is_worth_caching_serialized_bbox(ser) )
193        {
194                /* if ( ! wantbbox ) elog(NOTICE, "PG_LWGEOM_construct forced wantbbox=1 due to rule FOR_COMPLEX_GEOMS"); */
195                wantbbox=1;
196        }
197
198        size = lwgeom_size(ser);
199        eptr = ser+size; /* end of subgeom */
200
201        iptr = ser+1; /* skip type */
202        if ( lwgeom_hasSRID(ser[0]) )
203        {
204                iptr += 4; /* skip SRID */
205                size -= 4;
206        }
207        if ( lwgeom_hasBBOX(ser[0]) )
208        {
209                iptr += sizeof(BOX2DFLOAT4); /* skip BBOX */
210                size -= sizeof(BOX2DFLOAT4);
211        }
212
213        if ( SRID != -1 )
214        {
215                wantsrid = 1;
216                size += 4;
217        }
218        if ( wantbbox )
219        {
220                size += sizeof(BOX2DFLOAT4);
221                getbox2d_p(ser, &box);
222        }
223
224        size+=4; /* size header */
225
226        result = lwalloc(size);
227        SET_VARSIZE(result, size);
228
229        result->type = lwgeom_makeType_full(
230                TYPE_HASZ(ser[0]), TYPE_HASM(ser[0]),
231                wantsrid, lwgeom_getType(ser[0]), wantbbox);
232        optr = result->data;
233        if ( wantbbox )
234        {
235                memcpy(optr, &box, sizeof(BOX2DFLOAT4));
236                optr += sizeof(BOX2DFLOAT4);
237        }
238        if ( wantsrid )
239        {
240                memcpy(optr, &SRID, 4);
241                optr += 4;
242        }
243        memcpy(optr, iptr, eptr-iptr);
244
245        return result;
246}
247
248/*
249 * Make a PG_LWGEOM object from a WKB binary representation.
250 */
251PG_LWGEOM *
252pglwgeom_from_ewkb(uchar *ewkb, size_t ewkblen)
253{
254        PG_LWGEOM *ret;
255    SERIALIZED_LWGEOM *serialized_lwgeom;
256        char *hexewkb;
257        size_t hexewkblen = ewkblen*2;
258        int i;
259
260        hexewkb = lwalloc(hexewkblen+1);
261        for (i=0; i<ewkblen; i++)
262        {
263                deparse_hex(ewkb[i], &hexewkb[i*2]);
264        }
265        hexewkb[hexewkblen] = '\0';
266
267    serialized_lwgeom = parse_lwgeom_wkt(hexewkb);
268   
269    ret = (PG_LWGEOM *)palloc(serialized_lwgeom->size + VARHDRSZ);
270    SET_VARSIZE(ret, serialized_lwgeom->size + VARHDRSZ);
271        memcpy(VARDATA(ret), serialized_lwgeom->lwgeom, serialized_lwgeom->size);
272
273        lwfree(hexewkb);
274
275        return ret;
276}
277
278/*
279 * Return the EWKB (binary) representation for a PG_LWGEOM.
280 */
281char *
282pglwgeom_to_ewkb(PG_LWGEOM *geom, char byteorder, size_t *outsize)
283{
284        uchar *srl = &(geom->type);
285        return unparse_WKB(srl, lwalloc, lwfree,
286                byteorder, outsize, 0);
287}
288
289/*
290 * Set the SRID of a PG_LWGEOM
291 * Returns a newly allocated PG_LWGEOM object.
292 * Allocation will be done using the lwalloc.
293 */
294PG_LWGEOM *
295pglwgeom_setSRID(PG_LWGEOM *lwgeom, int32 newSRID)
296{
297        uchar type = lwgeom->type;
298        int bbox_offset=0; /* 0=no bbox, otherwise sizeof(BOX2DFLOAT4) */
299        int len,len_new,len_left;
300        PG_LWGEOM *result;
301        uchar *loc_new, *loc_old;
302
303        if (lwgeom_hasBBOX(type))
304                bbox_offset = sizeof(BOX2DFLOAT4);
305
306        len = lwgeom->size;
307
308        if (lwgeom_hasSRID(type))
309        {
310                if ( newSRID != -1 ) {
311                        /* we create a new one and copy the SRID in */
312                        result = lwalloc(len);
313                        memcpy(result, lwgeom, len);
314                        memcpy(result->data+bbox_offset, &newSRID,4);
315                } else {
316                        /* we create a new one dropping the SRID */
317                        result = lwalloc(len-4);
318                        result->size = len-4;
319                        result->type = lwgeom_makeType_full(
320                                TYPE_HASZ(type), TYPE_HASM(type),
321                                0, lwgeom_getType(type),
322                                lwgeom_hasBBOX(type));
323                        loc_new = result->data;
324                        loc_old = lwgeom->data;
325                        len_left = len-4-1;
326
327                        /* handle bbox (if there) */
328                        if (lwgeom_hasBBOX(type))
329                        {
330                                memcpy(loc_new, loc_old, sizeof(BOX2DFLOAT4));
331                                loc_new += sizeof(BOX2DFLOAT4);
332                                loc_old += sizeof(BOX2DFLOAT4);
333                                len_left -= sizeof(BOX2DFLOAT4);
334                        }
335
336                        /* skip SRID, copy the remaining */
337                        loc_old += 4;
338                        len_left -= 4;
339                        memcpy(loc_new, loc_old, len_left);
340
341                }
342
343        }
344        else
345        {
346                /* just copy input, already w/out a SRID */
347                if ( newSRID == -1 ) {
348                        result = lwalloc(len);
349                        memcpy(result, lwgeom, len);
350                }
351                /* need to add one */
352                else {
353                        len_new = len + 4; /* +4 for SRID */
354                        result = lwalloc(len_new);
355                        memcpy(result, &len_new, 4); /* size copy in */
356                        result->type = lwgeom_makeType_full(
357                                TYPE_HASZ(type), TYPE_HASM(type),
358                                1, lwgeom_getType(type),lwgeom_hasBBOX(type));
359
360                        loc_new = result->data;
361                        loc_old = lwgeom->data;
362
363                        len_left = len -4-1; /* old length - size - type */
364
365                        /* handle bbox (if there) */
366
367                        if (lwgeom_hasBBOX(type))
368                        {
369                                memcpy(loc_new, loc_old, sizeof(BOX2DFLOAT4)) ; /* copy in bbox */
370                                loc_new += sizeof(BOX2DFLOAT4);
371                                loc_old += sizeof(BOX2DFLOAT4);
372                                len_left -= sizeof(BOX2DFLOAT4);
373                        }
374
375                        /* put in SRID */
376
377                        memcpy(loc_new, &newSRID,4);
378                        loc_new +=4;
379                        memcpy(loc_new, loc_old, len_left);
380                }
381        }
382        return result;
383}
384
385/*
386 * get the SRID from the LWGEOM
387 * none present => -1
388 */
389int
390pglwgeom_getSRID(PG_LWGEOM *lwgeom)
391{
392        uchar type = lwgeom->type;
393        uchar *loc = lwgeom->data;
394
395        if ( ! lwgeom_hasSRID(type)) return -1;
396
397        if (lwgeom_hasBBOX(type))
398        {
399                loc += sizeof(BOX2DFLOAT4);
400        }
401
402        return lw_get_int32(loc);
403}
404
405
406
Note: See TracBrowser for help on using the repository browser.