]> granicus.if.org Git - postgis/commitdiff
Implement canonical input-output for geography (#850)
authorSandro Santilli <strk@keybit.net>
Tue, 17 Jan 2012 20:01:36 +0000 (20:01 +0000)
committerSandro Santilli <strk@keybit.net>
Tue, 17 Jan 2012 20:01:36 +0000 (20:01 +0000)
Note: canonical output is tested, input isn't.

git-svn-id: http://svn.osgeo.org/postgis/trunk@8860 b70326c6-7e19-0410-871a-916f4a2858ee

postgis/geography.sql.in.c
postgis/geography_inout.c
regress/binary.sql
regress/binary_expected

index cb1985cbd1327585ac7a2dd126925331eef6dd60..1b28539eb1bcd621671c864216ef9d03ec53f73b 100644 (file)
@@ -37,6 +37,18 @@ CREATE OR REPLACE FUNCTION geography_out(geography)
        AS 'MODULE_PATHNAME','geography_out'
        LANGUAGE 'C' IMMUTABLE STRICT; 
 
+-- Availability: 2.0.0
+CREATE OR REPLACE FUNCTION geography_recv(internal, oid, integer)
+       RETURNS geography
+       AS 'MODULE_PATHNAME','geography_recv'
+       LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- Availability: 2.0.0
+CREATE OR REPLACE FUNCTION geography_send(geography)
+       RETURNS bytea
+       AS 'MODULE_PATHNAME','geography_send'
+       LANGUAGE 'C' IMMUTABLE STRICT; 
+
 -- Availability: 1.5.0
 CREATE OR REPLACE FUNCTION geography_analyze(internal)
        RETURNS bool
@@ -48,6 +60,8 @@ CREATE TYPE geography (
        internallength = variable,
        input = geography_in,
        output = geography_out,
+       receive = geography_recv,
+       send = geography_send,
        typmod_in = geography_typmod_in,
        typmod_out = geography_typmod_out,
        delimiter = ':',
index 68da862cac4b407b527ef8ad9f55c5d28f53fd75..cd0bfea855893ed9938b8739fd7803d1a1160250 100644 (file)
@@ -42,11 +42,13 @@ Datum geography_as_svg(PG_FUNCTION_ARGS);
 Datum geography_from_binary(PG_FUNCTION_ARGS);
 Datum geography_from_geometry(PG_FUNCTION_ARGS);
 Datum geometry_from_geography(PG_FUNCTION_ARGS);
+Datum geography_send(PG_FUNCTION_ARGS);
+Datum geography_recv(PG_FUNCTION_ARGS);
 
 /* Datum geography_gist_selectivity(PG_FUNCTION_ARGS); TBD */
 /* Datum geography_gist_join_selectivity(PG_FUNCTION_ARGS); TBD */
-/* Datum geography_send(PG_FUNCTION_ARGS); TBD */
-/* Datum geography_recv(PG_FUNCTION_ARGS); TBD */
+
+GSERIALIZED* gserialized_geography_from_lwgeom(LWGEOM *lwgeom, int32 geog_typmod);
 
 /**
 * The geography type only support POINT, LINESTRING, POLYGON, MULTI* variants
@@ -72,6 +74,48 @@ void geography_valid_type(uint8_t type)
        }
 }
 
+GSERIALIZED* gserialized_geography_from_lwgeom(LWGEOM *lwgeom, int32 geog_typmod)
+{
+       GSERIALIZED *g_ser = NULL;
+
+       /* Set geodetic flag */
+       lwgeom_set_geodetic(lwgeom, true);
+
+       /* Check that this is a type we can handle */
+       geography_valid_type(lwgeom->type);
+
+       /* Check that the coordinates are in range */
+       if ( lwgeom_check_geodetic(lwgeom) == LW_FALSE )
+       {
+               ereport(ERROR, (
+                           errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                           errmsg("Coordinate values are out of range [-180 -90, 180 90] for GEOGRAPHY type" )));
+       }
+
+       /* Force default SRID to the default */
+       if ( (int)lwgeom->srid <= 0 )
+               lwgeom->srid = SRID_DEFAULT;
+
+       /*
+       ** Serialize our lwgeom and set the geodetic flag so subsequent
+       ** functions do the right thing.
+       */
+       g_ser = geography_serialize(lwgeom);
+
+       /* Check for typmod agreement */
+       if ( geog_typmod >= 0 )
+       {
+               postgis_valid_typmod(g_ser, geog_typmod);
+               POSTGIS_DEBUG(3, "typmod and geometry were consistent");
+       }
+       else
+       {
+               POSTGIS_DEBUG(3, "typmod was -1");
+       }
+
+       return g_ser;
+}
+
 
 /*
 ** geography_in(cstring) returns *GSERIALIZED
@@ -114,42 +158,12 @@ Datum geography_in(PG_FUNCTION_ARGS)
                lwgeom = lwg_parser_result.geom;
        }
 
-       /* Set geodetic flag */
-       lwgeom_set_geodetic(lwgeom, true);
-
-       /* Check that this is a type we can handle */
-       geography_valid_type(lwgeom->type);
-
-       /* Check that the coordinates are in range */
-       if ( lwgeom_check_geodetic(lwgeom) == LW_FALSE )
-       {
-               ereport(ERROR, (
-                           errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                           errmsg("Coordinate values are out of range [-180 -90, 180 90] for GEOGRAPHY type" )));
-       }
-
-       /* Force default SRID to the default */
-       if ( (int)lwgeom->srid <= 0 )
-               lwgeom->srid = SRID_DEFAULT;
+       
+       g_ser = gserialized_geography_from_lwgeom(lwgeom, geog_typmod);
 
-       /*
-       ** Serialize our lwgeom and set the geodetic flag so subsequent
-       ** functions do the right thing.
-       */
-       g_ser = geography_serialize(lwgeom);
        /* Clean up temporary object */
        lwgeom_free(lwgeom);
-       
-       /* Check for typmod agreement */
-       if ( geog_typmod >= 0 )
-       {
-               postgis_valid_typmod(g_ser, geog_typmod);
-               POSTGIS_DEBUG(3, "typmod and geometry were consistent");
-       }
-       else
-       {
-               POSTGIS_DEBUG(3, "typmod was -1");
-       }
+
 
        PG_RETURN_POINTER(g_ser);
 }
@@ -593,3 +607,50 @@ Datum geometry_from_geography(PG_FUNCTION_ARGS)
        PG_RETURN_POINTER(ret);
 }
 
+PG_FUNCTION_INFO_V1(geography_recv);
+Datum geography_recv(PG_FUNCTION_ARGS)
+{
+       StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+       int32 geog_typmod = -1;
+       LWGEOM *lwgeom = NULL;
+       GSERIALIZED *g_ser = NULL;
+
+       if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) {
+               geog_typmod = PG_GETARG_INT32(2);
+       }
+
+       lwgeom = lwgeom_from_wkb((uint8_t*)buf->data, buf->len, LW_PARSER_CHECK_ALL);
+
+       g_ser = gserialized_geography_from_lwgeom(lwgeom, geog_typmod);
+
+       /* Clean up temporary object */
+       lwgeom_free(lwgeom);
+
+       /* Set cursor to the end of buffer (so the backend is happy) */
+       buf->cursor = buf->len;
+
+       PG_RETURN_POINTER(g_ser);
+}
+
+
+PG_FUNCTION_INFO_V1(geography_send);
+Datum geography_send(PG_FUNCTION_ARGS)
+{
+       LWGEOM *lwgeom = NULL;
+       GSERIALIZED *g = NULL;
+       size_t size_result;
+       uint8_t *wkb;
+       bytea *result;
+
+       g = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       lwgeom = lwgeom_from_gserialized(g);
+       wkb = lwgeom_to_wkb(lwgeom, WKB_EXTENDED, &size_result);
+       lwgeom_free(lwgeom);
+
+       result = palloc(size_result + VARHDRSZ);
+       SET_VARSIZE(result, size_result + VARHDRSZ);
+       memcpy(VARDATA(result), wkb, size_result);
+       pfree(wkb);
+
+       PG_RETURN_POINTER(result);
+}
index 0c90bb7fa370f2711500f2a9c3bb96309111f05a..e1c67a7c6abb90b6f2230109dfae28d5266c2cdc 100644 (file)
@@ -1,36 +1,46 @@
 SET client_min_messages TO warning;
 CREATE SCHEMA tm;
 
-CREATE TABLE tm.types (id serial, g geometry);
-
-INSERT INTO tm.types(g) values ('POINT EMPTY');
-INSERT INTO tm.types(g) values ('LINESTRING EMPTY');
-INSERT INTO tm.types(g) values ('POLYGON EMPTY');
-INSERT INTO tm.types(g) values ('MULTIPOINT EMPTY');
-INSERT INTO tm.types(g) values ('MULTILINESTRING EMPTY');
-INSERT INTO tm.types(g) values ('MULTIPOLYGON EMPTY');
-INSERT INTO tm.types(g) values ('GEOMETRYCOLLECTION EMPTY');
-INSERT INTO tm.types(g) values ('CIRCULARSTRING EMPTY');
-INSERT INTO tm.types(g) values ('COMPOUNDCURVE EMPTY');
-INSERT INTO tm.types(g) values ('CURVEPOLYGON EMPTY');
-INSERT INTO tm.types(g) values ('MULTICURVE EMPTY');
-INSERT INTO tm.types(g) values ('MULTISURFACE EMPTY');
-INSERT INTO tm.types(g) values ('POLYHEDRALSURFACE EMPTY');
-INSERT INTO tm.types(g) values ('TRIANGLE EMPTY');
-INSERT INTO tm.types(g) values ('TIN EMPTY');
+CREATE TABLE tm.geoms (id serial, g geometry);
+
+INSERT INTO tm.geoms(g) values ('POINT EMPTY');
+INSERT INTO tm.geoms(g) values ('LINESTRING EMPTY');
+INSERT INTO tm.geoms(g) values ('POLYGON EMPTY');
+INSERT INTO tm.geoms(g) values ('MULTIPOINT EMPTY');
+INSERT INTO tm.geoms(g) values ('MULTILINESTRING EMPTY');
+INSERT INTO tm.geoms(g) values ('MULTIPOLYGON EMPTY');
+INSERT INTO tm.geoms(g) values ('GEOMETRYCOLLECTION EMPTY');
+INSERT INTO tm.geoms(g) values ('CIRCULARSTRING EMPTY');
+INSERT INTO tm.geoms(g) values ('COMPOUNDCURVE EMPTY');
+INSERT INTO tm.geoms(g) values ('CURVEPOLYGON EMPTY');
+INSERT INTO tm.geoms(g) values ('MULTICURVE EMPTY');
+INSERT INTO tm.geoms(g) values ('MULTISURFACE EMPTY');
+INSERT INTO tm.geoms(g) values ('POLYHEDRALSURFACE EMPTY');
+INSERT INTO tm.geoms(g) values ('TRIANGLE EMPTY');
+INSERT INTO tm.geoms(g) values ('TIN EMPTY');
 
 -- all zm flags
-INSERT INTO tm.types(g)
-SELECT st_force_3dz(g) FROM tm.types WHERE id < 15 ORDER BY id;
-INSERT INTO tm.types(g)
-SELECT st_force_3dm(g) FROM tm.types WHERE id < 15 ORDER BY id;
-INSERT INTO tm.types(g)
-SELECT st_force_4d(g) FROM tm.types WHERE id < 15 ORDER BY id;
+INSERT INTO tm.geoms(g)
+SELECT st_force_3dz(g) FROM tm.geoms WHERE id < 15 ORDER BY id;
+INSERT INTO tm.geoms(g)
+SELECT st_force_3dm(g) FROM tm.geoms WHERE id < 15 ORDER BY id;
+INSERT INTO tm.geoms(g)
+SELECT st_force_4d(g) FROM tm.geoms WHERE id < 15 ORDER BY id;
 
 -- known srid
-INSERT INTO tm.types(g)
-SELECT st_setsrid(g,1) FROM tm.types ORDER BY id;
+INSERT INTO tm.geoms(g)
+SELECT st_setsrid(g,4326) FROM tm.geoms ORDER BY id;
+
+COPY ( SELECT g FROM tm.geoms ORDER BY id ) TO STDOUT WITH BINARY;
+
+CREATE TABLE tm.geogs AS SELECT id,g::geography FROM tm.geoms
+WHERE geometrytype(g) NOT LIKE '%CURVE%'
+  AND geometrytype(g) NOT LIKE '%CIRCULAR%'
+  AND geometrytype(g) NOT LIKE '%SURFACE%'
+  AND geometrytype(g) NOT LIKE 'TRIANGLE%'
+  AND geometrytype(g) NOT LIKE 'TIN%'
+;
 
-COPY ( SELECT g FROM tm.types ORDER BY id ) TO STDOUT WITH BINARY;
+COPY ( SELECT g FROM tm.geogs ORDER BY id ) TO STDOUT WITH BINARY;
 
 DROP SCHEMA tm CASCADE;
index f235b597a6103dd86a071600e9111b99f2cb41c1..0efbd17d83c3cc0b32d74af21d6ce1a73dc443a5 100644 (file)
Binary files a/regress/binary_expected and b/regress/binary_expected differ