diff --git a/.gitignore b/.gitignore index e69de29..dd88dc6 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,51 @@ +/postgis-2.5.3.tar.gz +/postgis-3.0.0.pdf +/postgis-3.0.0.tar.gz +/postgis-3.0.1.tar.gz +/postgis-3.0.1.pdf +/postgis-2.5.4.tar.gz +/postgis-3.0.2.pdf +/postgis-3.0.2.tar.gz +/postgis-2.5.5.tar.gz +/postgis-3.0.3.tar.gz +/postgis-3.0.3.pdf +/postgis-3.1.0.pdf +/postgis-3.1.0.tar.gz +/postgis-3.1.1.tar.gz +/postgis-3.1.1.pdf +/postgis-3.1.2.tar.gz +/postgis-3.1.2.pdf +/postgis-3.1.3.pdf +/postgis-3.1.3.tar.gz +/postgis-3.1.4.pdf +/postgis-3.1.4.tar.gz +/postgis-3.2.0.pdf +/postgis-3.2.0.tar.gz +/postgis-3.2.1.pdf +/postgis-3.2.1.tar.gz +/postgis-3.2.2.tar.gz +/postgis-3.2.2.pdf +/postgis-3.3.1.tar.gz +/postgis-3.3.1.pdf +/postgis-3.3.2.tar.gz +/postgis-3.3.2.pdf +/postgis-3.3.3.pdf +/postgis-3.3.3.tar.gz +/postgis-3.3.4.pdf +/postgis-3.3.4.tar.gz +/postgis-3.4.0-en.pdf +/postgis-3.4.0.tar.gz +/postgis-3.4.1.tar.gz +/postgis-3.4.1-en.pdf +/postgis-3.4.2-en.pdf +/postgis-3.4.2.tar.gz +/postgis-3.4.3-en.pdf +/postgis-3.4.3.tar.gz +/postgis-3.5.0-en.pdf +/postgis-3.5.0.tar.gz +/postgis-3.5.1-en.pdf +/postgis-3.5.1.tar.gz +/postgis-3.5.2-en.pdf +/postgis-3.5.2.tar.gz +/postgis-3.5.3-en.pdf +/postgis-3.5.3.tar.gz diff --git a/postgis-c99-2.patch b/postgis-c99-2.patch new file mode 100644 index 0000000..457bfce --- /dev/null +++ b/postgis-c99-2.patch @@ -0,0 +1,17 @@ +Include for isnan. This avoids an implicit function +declaration and a build failure with future compilers. + +Submitted upstream: + +diff -ur postgis-3.3.2.orig/loader/shp2pgsql-core.c postgis-3.3.2/loader/shp2pgsql-core.c +--- postgis-3.3.2.orig/loader/shp2pgsql-core.c 2022-11-13 08:09:23.000000000 +0100 ++++ postgis-3.3.2/loader/shp2pgsql-core.c 2023-04-09 22:01:46.377934865 +0200 +@@ -15,6 +15,8 @@ + + #include "../postgis_config.h" + ++#include /* for isnan */ ++ + #include "shp2pgsql-core.h" + #include "../liblwgeom/liblwgeom.h" + #include "../liblwgeom/lwgeom_log.h" /* for LWDEBUG macros */ diff --git a/postgis-c99.patch b/postgis-c99.patch new file mode 100644 index 0000000..cfc363a --- /dev/null +++ b/postgis-c99.patch @@ -0,0 +1,54 @@ +commit ae53a53246ccb26a6e82fede1a4184b41bcf097d +Author: Regina Obe +Date: Sat Feb 19 00:21:01 2022 -0500 + + Fix PG 15 building atoi removed. References #5100 for PostGIS 3.3.0 + +diff -ur postgis-3.3.2.orig/postgis-2.5.5/postgis/gserialized_typmod.c postgis-3.3.2/postgis-2.5.5/postgis/gserialized_typmod.c +--- postgis-3.3.2.orig/postgis-2.5.5/postgis/gserialized_typmod.c 2023-04-09 21:52:47.909294055 +0200 ++++ postgis-3.3.2/postgis-2.5.5/postgis/gserialized_typmod.c 2023-04-09 21:55:24.744826310 +0200 +@@ -35,7 +35,7 @@ + + #include "utils/elog.h" + #include "utils/array.h" +-#include "utils/builtins.h" /* for pg_atoi */ ++#include "utils/builtins.h" /* for cstring_to_text */ + #include "lib/stringinfo.h" /* For binary input */ + #include "catalog/pg_type.h" /* for CSTRINGOID */ + +@@ -267,8 +267,33 @@ + } + if ( i == 1 ) /* SRID */ + { +- int srid = pg_atoi(DatumGetCString(elem_values[i]), +- sizeof(int32), '\0'); ++ char *int_string = DatumGetCString(elem_values[i]); ++ char *endp; ++ long l; ++ int32_t srid; ++ ++ errno = 0; ++ l = strtol(int_string, &endp, 10); ++ ++ if (int_string == endp) ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), ++ errmsg("invalid input syntax for type %s: \"%s\"", ++ "integer", int_string))); ++ ++ if (errno == ERANGE || l < INT_MIN || l > INT_MAX) ++ ereport(ERROR, ++ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), ++ errmsg("value \"%s\" is out of range for type %s", int_string, ++ "integer"))); ++ ++ if (*endp != '\0') ++ ereport(ERROR, ++ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), ++ errmsg("invalid input syntax for type %s: \"%s\"", ++ "integer", int_string))); ++ ++ srid = clamp_srid(l); + srid = clamp_srid(srid); + POSTGIS_DEBUGF(3, "srid: %d", srid); + if ( srid != SRID_UNKNOWN ) diff --git a/postgis2-proj8.patch b/postgis2-proj8.patch new file mode 100644 index 0000000..b4d9214 --- /dev/null +++ b/postgis2-proj8.patch @@ -0,0 +1,3227 @@ +diff -rupN postgis-2.5.5/autogen.sh postgis-2.5.5-new/autogen.sh +--- postgis-2.5.5/autogen.sh 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/autogen.sh 2022-08-06 12:13:08.260741405 +0200 +@@ -81,6 +81,9 @@ ${ACLOCAL} -I macros || giveup + echo "* Running ${AUTOCONF} (${AUTOCONF_VER})" + ${AUTOCONF} || giveup + ++# Work around an autoconf bug insisting in having this file ++touch build-aux/config.rpath ++ + if test -f "${PWD}/configure"; then + echo "======================================" + echo "Now you are ready to run './configure'" +diff -rupN postgis-2.5.5/configure.ac postgis-2.5.5-new/configure.ac +--- postgis-2.5.5/configure.ac 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/configure.ac 2022-08-06 12:15:04.877744014 +0200 +@@ -851,42 +851,64 @@ if test ! "x$PROJDIR" = "x"; then + AC_MSG_RESULT([Using user-specified proj directory: $PROJDIR]) + + dnl Add the include directory to PROJ_CPPFLAGS +- PROJ_CPPFLAGS="-I$PROJDIR/include -DACCEPT_USE_OF_DEPRECATED_PROJ_API_H=1" +- PROJ_LDFLAGS="-L$PROJDIR/lib" ++ PROJ_CPPFLAGS="-I$PROJDIR/include" ++ PROJ_LDFLAGS="-L$PROJDIR/lib -lproj" + else + AC_MSG_ERROR([the --with-projdir directory "$PROJDIR" cannot be found]) + fi + fi ++elif test ! -z "$PKG_CONFIG"; then ++ dnl To keep compatibility with PROJ pre 4.8, default to lproj if not found ++ PKG_CHECK_MODULES([PROJ], [proj], ++ [ ++ PROJ_CPPFLAGS="$PROJ_CFLAGS" ++ PROJ_LDFLAGS="$PROJ_LIBS" ++ POSTGIS_PROJ_VERSION=`$PKG_CONFIG proj --modversion | sed 's/\([[0-9]]\).*\([[0-9]]\).*\([[0-9]]\)/\1\2/'` ++ ], ++ [ ++ PROJ_LDFLAGS="-lproj" ++ ]) ++else ++ dnl To keep compatibility with PROJ pre 4.8, default to lproj ++ PROJ_LDFLAGS="-lproj" + fi + ++ + dnl Check that we can find the proj_api.h header file + CPPFLAGS_SAVE="$CPPFLAGS" + CPPFLAGS="$PROJ_CPPFLAGS" +-AC_CHECK_HEADER([proj_api.h], [], [AC_MSG_ERROR([could not find proj_api.h - you may need to specify the directory of a PROJ.4 installation using --with-projdir])], +-[ +-#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 1 +-]) +- +-dnl Return the PROJ.4 version number +-AC_PROJ_VERSION([POSTGIS_PROJ_VERSION]) ++AC_CHECK_HEADER([proj_api.h], ++ [], ++ [AC_CHECK_HEADER([proj.h], ++ [], ++ [AC_MSG_ERROR([could not find proj.h or proj_api.h - you may need to specify the directory of a PROJ installation using --with-projdir])] ++ )] ++ ) ++ ++dnl Return the PROJ.4 version number if not detected by pkg-config ++if test "x$POSTGIS_PROJ_VERSION" = "x"; then ++ AC_PROJ_VERSION([POSTGIS_PROJ_VERSION]) ++fi + AC_DEFINE_UNQUOTED([POSTGIS_PROJ_VERSION], [$POSTGIS_PROJ_VERSION], [PROJ library version]) + AC_SUBST([POSTGIS_PROJ_VERSION]) + CPPFLAGS="$CPPFLAGS_SAVE" + ++dnl Ensure that we are using PROJ >= 4.9.0 (requires pj_set_searchpath) ++if test ! "$POSTGIS_PROJ_VERSION" -ge 49; then ++ AC_MSG_ERROR([PostGIS requires PROJ >= 4.9.0]) ++fi ++ + AC_SUBST([PROJ_CPPFLAGS]) + AC_SUBST([PROJ_LDFLAGS]) + +-dnl Ensure that we are using PROJ >= 4.6.0 (requires pj_set_searchpath) +-if test ! "$POSTGIS_PROJ_VERSION" -ge 46; then +- AC_MSG_ERROR([PostGIS requires PROJ >= 4.6.0]) +-fi +- + dnl Ensure we can link against libproj + LIBS_SAVE="$LIBS" + LIBS="$PROJ_LDFLAGS" +-AC_CHECK_LIB([proj], [pj_get_release], +- [], +- [AC_MSG_ERROR([could not find libproj - you may need to specify the directory of a PROJ.4 installation using --with-projdir])], ++AC_CHECK_LIB([proj], [pj_get_release], [], ++ [AC_CHECK_LIB([proj], [proj_info], [], ++ [AC_MSG_ERROR([could not find libproj - you may need to specify the directory of a PROJ installation using --with-projdir])], ++ [] ++ )], + []) + LIBS="$LIBS_SAVE" + +diff -rupN postgis-2.5.5/liblwgeom/cunit/cu_geodetic.c postgis-2.5.5-new/liblwgeom/cunit/cu_geodetic.c +--- postgis-2.5.5/liblwgeom/cunit/cu_geodetic.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/cunit/cu_geodetic.c 2022-08-06 11:49:41.821709943 +0200 +@@ -1276,7 +1276,7 @@ static void test_spheroid_distance(void) + { + GEOGRAPHIC_POINT g1, g2; + double d; +-#if ! PROJ_GEODESIC ++#ifndef PROJ_GEODESIC + double epsilon; /* irregular */ + #else + const double epsilon = 1e-8; /* at least 10 nm precision */ +@@ -1291,7 +1291,7 @@ static void test_spheroid_distance(void) + point_set(0.0, 0.0, &g1); + point_set(0.0, 1.0, &g2); + d = spheroid_distance(&g1, &g2, &s); +-#if ! PROJ_GEODESIC ++#ifndef PROJ_GEODESIC + epsilon = 1e-6; + #endif + CU_ASSERT_DOUBLE_EQUAL(d, 110574.3885577987957342, epsilon); +@@ -1301,7 +1301,7 @@ static void test_spheroid_distance(void) + point_set(-10.0, 0.0, &g1); + point_set(0.0, 0.0, &g2); + d = spheroid_distance(&g1, &g2, &s); +-#if ! PROJ_GEODESIC ++#ifndef PROJ_GEODESIC + epsilon = 1e-3; + #endif + CU_ASSERT_DOUBLE_EQUAL(d, 1113194.9079327357264771, epsilon); +@@ -1311,7 +1311,7 @@ static void test_spheroid_distance(void) + point_set(-1.0, 0.0, &g1); + point_set(0.0, 0.0, &g2); + d = spheroid_distance(&g1, &g2, &s); +-#if ! PROJ_GEODESIC ++#ifndef PROJ_GEODESIC + epsilon = 1e-4; + #endif + CU_ASSERT_DOUBLE_EQUAL(d, 111319.4907932735726477, epsilon); +@@ -1321,7 +1321,7 @@ static void test_spheroid_distance(void) + point_set(-180.0, 0.0, &g1); + point_set(0.0, 1.0, &g2); + d = spheroid_distance(&g1, &g2, &s); +-#if ! PROJ_GEODESIC ++#ifndef PROJ_GEODESIC + epsilon = 1e-5; + #endif + CU_ASSERT_DOUBLE_EQUAL(d, 19893357.0700676468277450, epsilon); +@@ -1331,7 +1331,7 @@ static void test_spheroid_distance(void) + point_set(-180.0, 0.0, &g1); + point_set(0.0, 90.0, &g2); + d = spheroid_distance(&g1, &g2, &s); +-#if ! PROJ_GEODESIC ++#ifndef PROJ_GEODESIC + epsilon = 1e-6; + #endif + CU_ASSERT_DOUBLE_EQUAL(d, 10001965.7293127228117396, epsilon); +@@ -1372,7 +1372,7 @@ static void test_spheroid_area(void) + a1 = lwgeom_area_sphere(lwg, &s); + CU_ASSERT_DOUBLE_EQUAL(a1, 12341436880.106982993974659, 0.1); + /* spheroid: Planimeter -E -p 20 -r --input-string "3 -2;4 -2;4 -1;3 -1" */ +-#if PROJ_GEODESIC ++#ifdef PROJ_GEODESIC + // printf("XXXXX %d\n", PJ_VERSION); + a2 = lwgeom_area_spheroid(lwg, &s); + CU_ASSERT_DOUBLE_EQUAL(a2, 12286884908.946891319597874, 0.1); +@@ -1386,7 +1386,7 @@ static void test_spheroid_area(void) + a1 = lwgeom_area_sphere(lwg, &s); + CU_ASSERT_DOUBLE_EQUAL(a1, 12360265021.368023059138681, 0.1); + /* spheroid: Planimeter -E -p 20 --input-string "2 8.5;1 8.5;1 9.5;2 9.5" */ +-#if PROJ_GEODESIC ++#ifdef PROJ_GEODESIC + a2 = lwgeom_area_spheroid(lwg, &s); + CU_ASSERT_DOUBLE_EQUAL(a2, 12305128751.042900673161556, 0.1); + #endif +@@ -1399,7 +1399,7 @@ static void test_spheroid_area(void) + a1 = lwgeom_area_sphere(lwg, &s); + CU_ASSERT_DOUBLE_EQUAL(a1, 12360265021.368023059138681, 0.1); + /* spheroid: Planimeter -E -p 20 -r --input-string "2 179.5;1 179.5;1 178.5;2 178.5" */ +-#if PROJ_GEODESIC ++#ifdef PROJ_GEODESIC + a2 = lwgeom_area_spheroid(lwg, &s); + CU_ASSERT_DOUBLE_EQUAL(a2, 12305128751.042900673161556, 0.1); + #endif +@@ -1412,7 +1412,7 @@ static void test_spheroid_area(void) + a1 = lwgeom_area_sphere(lwg, &s); + CU_ASSERT_DOUBLE_EQUAL(a1, 12360265021.368023059138681, 0.1); + /* spheroid: Planimeter -E -p 20 --input-string "2 179.5;1 179.5;1 -179.5;2 -179.5" */ +-#if PROJ_GEODESIC ++#ifdef PROJ_GEODESIC + a2 = lwgeom_area_spheroid(lwg, &s); + CU_ASSERT_DOUBLE_EQUAL(a2, 12305128751.042900673161556, 0.1); + #endif +diff -rupN postgis-2.5.5/liblwgeom/cunit/cu_geos_cluster.c postgis-2.5.5-new/liblwgeom/cunit/cu_geos_cluster.c +--- postgis-2.5.5/liblwgeom/cunit/cu_geos_cluster.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/cunit/cu_geos_cluster.c 2022-08-06 11:48:23.729708197 +0200 +@@ -10,6 +10,8 @@ + * + **********************************************************************/ + ++#include ++ + #include "CUnit/Basic.h" + + #include "../lwgeom_log.h" +diff -rupN postgis-2.5.5/liblwgeom/g_box.c postgis-2.5.5-new/liblwgeom/g_box.c +--- postgis-2.5.5/liblwgeom/g_box.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/g_box.c 2022-08-06 11:48:23.730708197 +0200 +@@ -398,11 +398,11 @@ GBOX* gbox_from_string(const char *str) + + char* gbox_to_string(const GBOX *gbox) + { +- static int sz = 138; ++ const size_t sz = 138; + char *str = NULL; + + if ( ! gbox ) +- return strdup("NULL POINTER"); ++ return lwstrdup("NULL POINTER"); + + str = (char*)lwalloc(sz); + +diff -rupN postgis-2.5.5/liblwgeom/liblwgeom.h.in postgis-2.5.5-new/liblwgeom/liblwgeom.h.in +--- postgis-2.5.5/liblwgeom/liblwgeom.h.in 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/liblwgeom.h.in 2022-08-06 12:19:54.803750500 +0200 +@@ -32,15 +32,25 @@ + #include + #include + #include +-#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 1 ++ ++#include "../postgis_config.h" ++ ++#if POSTGIS_PROJ_VERSION < 60 + #include "proj_api.h" ++typedef struct PJ ++{ ++ projPJ pj_from; ++ projPJ pj_to; ++} PJ; ++#else ++#include "proj.h" ++#endif + +-#if defined(PJ_VERSION) && PJ_VERSION >= 490 +-/* Enable new geodesic functions */ +-#define PROJ_GEODESIC 1 ++#if POSTGIS_PROJ_VERSION < 49 ++#undef PROJ_GEODESIC + #else +-/* Use the old (pre-2.2) geodesic functions */ +-#define PROJ_GEODESIC 0 ++/* Enable new geodesic functions API */ ++#define PROJ_GEODESIC + #endif + + /** +@@ -82,13 +92,13 @@ const char* lwgeom_version(void); + /** + * LWTYPE numbers, used internally by PostGIS + */ +-#define POINTTYPE 1 +-#define LINETYPE 2 +-#define POLYGONTYPE 3 +-#define MULTIPOINTTYPE 4 +-#define MULTILINETYPE 5 +-#define MULTIPOLYGONTYPE 6 +-#define COLLECTIONTYPE 7 ++#define POINTTYPE 1 ++#define LINETYPE 2 ++#define POLYGONTYPE 3 ++#define MULTIPOINTTYPE 4 ++#define MULTILINETYPE 5 ++#define MULTIPOLYGONTYPE 6 ++#define COLLECTIONTYPE 7 + #define CIRCSTRINGTYPE 8 + #define COMPOUNDTYPE 9 + #define CURVEPOLYTYPE 10 +@@ -270,16 +280,16 @@ extern lwinterrupt_callback *lwgeom_regi + /******************************************************************/ + + typedef struct { +- double afac, bfac, cfac, dfac, efac, ffac, gfac, hfac, ifac, xoff, yoff, zoff; ++ double afac, bfac, cfac, dfac, efac, ffac, gfac, hfac, ifac, xoff, yoff, zoff; + } AFFINE; + + /******************************************************************/ + + typedef struct + { +- double xmin, ymin, zmin; +- double xmax, ymax, zmax; +- int32_t srid; ++ double xmin, ymin, zmin; ++ double xmax, ymax, zmax; ++ int32_t srid; + } + BOX3D; + +@@ -291,15 +301,15 @@ BOX3D; + */ + typedef struct + { +- uint8_t flags; +- double xmin; +- double xmax; +- double ymin; +- double ymax; +- double zmin; +- double zmax; +- double mmin; +- double mmax; ++ uint8_t flags; ++ double xmin; ++ double xmax; ++ double ymin; ++ double ymax; ++ double zmin; ++ double zmax; ++ double mmin; ++ double mmax; + } GBOX; + + +@@ -313,13 +323,13 @@ typedef struct + */ + typedef struct + { +- double a; /* semimajor axis */ +- double b; /* semiminor axis b = (a - fa) */ +- double f; /* flattening f = (a-b)/a */ +- double e; /* eccentricity (first) */ +- double e_sq; /* eccentricity squared (first) e_sq = (a*a-b*b)/(a*a) */ +- double radius; /* spherical average radius = (2*a+b)/3 */ +- char name[20]; /* name of ellipse */ ++ double a; /* semimajor axis */ ++ double b; /* semiminor axis b = (a - fa) */ ++ double f; /* flattening f = (a-b)/a */ ++ double e; /* eccentricity (first) */ ++ double e_sq; /* eccentricity squared (first) e_sq = (a*a-b*b)/(a*a) */ ++ double radius; /* spherical average radius = (2*a+b)/3 */ ++ char name[20]; /* name of ellipse */ + } + SPHEROID; + +@@ -328,31 +338,31 @@ SPHEROID; + */ + typedef struct + { +- double x, y; ++ double x, y; + } + POINT2D; + + typedef struct + { +- double x, y, z; ++ double x, y, z; + } + POINT3DZ; + + typedef struct + { +- double x, y, z; ++ double x, y, z; + } + POINT3D; + + typedef struct + { +- double x, y, m; ++ double x, y, m; + } + POINT3DM; + + typedef struct + { +- double x, y, z, m; ++ double x, y, z, m; + } + POINT4D; + +@@ -365,14 +375,14 @@ POINT4D; + */ + typedef struct + { +- /* Array of POINT 2D, 3D or 4D, possibly misaligned. */ +- uint8_t *serialized_pointlist; ++ /* Array of POINT 2D, 3D or 4D, possibly misaligned. */ ++ uint8_t *serialized_pointlist; + +- /* Use FLAGS_* macros to handle */ +- uint8_t flags; ++ /* Use FLAGS_* macros to handle */ ++ uint8_t flags; + +- uint32_t npoints; /* how many points we are currently storing */ +- uint32_t maxpoints; /* how many points we have space for in serialized_pointlist */ ++ uint32_t npoints; /* how many points we are currently storing */ ++ uint32_t maxpoints; /* how many points we have space for in serialized_pointlist */ + } + POINTARRAY; + +@@ -381,10 +391,10 @@ POINTARRAY; + */ + typedef struct + { +- uint32_t size; /* For PgSQL use only, use VAR* macros to manipulate. */ +- uint8_t srid[3]; /* 24 bits of SRID */ +- uint8_t flags; /* HasZ, HasM, HasBBox, IsGeodetic, IsReadOnly */ +- uint8_t data[1]; /* See gserialized.txt */ ++ uint32_t size; /* For PgSQL use only, use VAR* macros to manipulate. */ ++ uint8_t srid[3]; /* 24 bits of SRID */ ++ uint8_t flags; /* HasZ, HasM, HasBBox, IsGeodetic, IsReadOnly */ ++ uint8_t data[1]; /* See gserialized.txt */ + } GSERIALIZED; + + +@@ -396,198 +406,198 @@ typedef struct + */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- void *data; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ void *data; + } + LWGEOM; + + /* POINTYPE */ + typedef struct + { +- uint8_t type; /* POINTTYPE */ +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- POINTARRAY *point; /* hide 2d/3d (this will be an array of 1 point) */ ++ uint8_t type; /* POINTTYPE */ ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ POINTARRAY *point; /* hide 2d/3d (this will be an array of 1 point) */ + } + LWPOINT; /* "light-weight point" */ + + /* LINETYPE */ + typedef struct + { +- uint8_t type; /* LINETYPE */ +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- POINTARRAY *points; /* array of POINT3D */ ++ uint8_t type; /* LINETYPE */ ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ POINTARRAY *points; /* array of POINT3D */ + } + LWLINE; /* "light-weight line" */ + + /* TRIANGLE */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- POINTARRAY *points; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ POINTARRAY *points; + } + LWTRIANGLE; + + /* CIRCSTRINGTYPE */ + typedef struct + { +- uint8_t type; /* CIRCSTRINGTYPE */ +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- POINTARRAY *points; /* array of POINT(3D/3DM) */ ++ uint8_t type; /* CIRCSTRINGTYPE */ ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ POINTARRAY *points; /* array of POINT(3D/3DM) */ + } + LWCIRCSTRING; /* "light-weight circularstring" */ + + /* POLYGONTYPE */ + typedef struct + { +- uint8_t type; /* POLYGONTYPE */ +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t nrings; /* how many rings we are currently storing */ +- uint32_t maxrings; /* how many rings we have space for in **rings */ +- POINTARRAY **rings; /* list of rings (list of points) */ ++ uint8_t type; /* POLYGONTYPE */ ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t nrings; /* how many rings we are currently storing */ ++ uint32_t maxrings; /* how many rings we have space for in **rings */ ++ POINTARRAY **rings; /* list of rings (list of points) */ + } + LWPOLY; /* "light-weight polygon" */ + + /* MULTIPOINTTYPE */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t ngeoms; /* how many geometries we are currently storing */ +- uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ +- LWPOINT **geoms; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t ngeoms; /* how many geometries we are currently storing */ ++ uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ ++ LWPOINT **geoms; + } + LWMPOINT; + + /* MULTILINETYPE */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t ngeoms; /* how many geometries we are currently storing */ +- uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ +- LWLINE **geoms; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t ngeoms; /* how many geometries we are currently storing */ ++ uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ ++ LWLINE **geoms; + } + LWMLINE; + + /* MULTIPOLYGONTYPE */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t ngeoms; /* how many geometries we are currently storing */ +- uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ +- LWPOLY **geoms; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t ngeoms; /* how many geometries we are currently storing */ ++ uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ ++ LWPOLY **geoms; + } + LWMPOLY; + + /* COLLECTIONTYPE */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t ngeoms; /* how many geometries we are currently storing */ +- uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ +- LWGEOM **geoms; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t ngeoms; /* how many geometries we are currently storing */ ++ uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ ++ LWGEOM **geoms; + } + LWCOLLECTION; + + /* COMPOUNDTYPE */ + typedef struct + { +- uint8_t type; /* COMPOUNDTYPE */ +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t ngeoms; /* how many geometries we are currently storing */ +- uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ +- LWGEOM **geoms; ++ uint8_t type; /* COMPOUNDTYPE */ ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t ngeoms; /* how many geometries we are currently storing */ ++ uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ ++ LWGEOM **geoms; + } + LWCOMPOUND; /* "light-weight compound line" */ + + /* CURVEPOLYTYPE */ + typedef struct + { +- uint8_t type; /* CURVEPOLYTYPE */ +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t nrings; /* how many rings we are currently storing */ +- uint32_t maxrings; /* how many rings we have space for in **rings */ +- LWGEOM **rings; /* list of rings (list of points) */ ++ uint8_t type; /* CURVEPOLYTYPE */ ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t nrings; /* how many rings we are currently storing */ ++ uint32_t maxrings; /* how many rings we have space for in **rings */ ++ LWGEOM **rings; /* list of rings (list of points) */ + } + LWCURVEPOLY; /* "light-weight polygon" */ + + /* MULTICURVE */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t ngeoms; /* how many geometries we are currently storing */ +- uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ +- LWGEOM **geoms; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t ngeoms; /* how many geometries we are currently storing */ ++ uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ ++ LWGEOM **geoms; + } + LWMCURVE; + + /* MULTISURFACETYPE */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t ngeoms; /* how many geometries we are currently storing */ +- uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ +- LWGEOM **geoms; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t ngeoms; /* how many geometries we are currently storing */ ++ uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ ++ LWGEOM **geoms; + } + LWMSURFACE; + + /* POLYHEDRALSURFACETYPE */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t ngeoms; /* how many geometries we are currently storing */ +- uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ +- LWPOLY **geoms; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t ngeoms; /* how many geometries we are currently storing */ ++ uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ ++ LWPOLY **geoms; + } + LWPSURFACE; + + /* TINTYPE */ + typedef struct + { +- uint8_t type; +- uint8_t flags; +- GBOX *bbox; +- int32_t srid; +- uint32_t ngeoms; /* how many geometries we are currently storing */ +- uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ +- LWTRIANGLE **geoms; ++ uint8_t type; ++ uint8_t flags; ++ GBOX *bbox; ++ int32_t srid; ++ uint32_t ngeoms; /* how many geometries we are currently storing */ ++ uint32_t maxgeoms; /* how many geometries we have space for in **geoms */ ++ LWTRIANGLE **geoms; + } + LWTIN; + +@@ -954,7 +964,7 @@ extern POINTARRAY *ptarray_addPoint(cons + + /** + * @brief Remove a point from a pointarray. +- * @param which - is the offset (starting at 0) ++ * @param which - is the offset (starting at 0) + * @return #POINTARRAY is newly allocated + */ + extern POINTARRAY *ptarray_removePoint(POINTARRAY *pa, uint32_t where); +@@ -1647,8 +1657,8 @@ extern double lwgeom_length_spheroid(con + extern int lwgeom_covers_lwgeom_sphere(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2); + + typedef struct { +- POINT2D* center; +- double radius; ++ POINT2D* center; ++ double radius; + } LWBOUNDINGCIRCLE; + + extern void lwboundingcircle_destroy(LWBOUNDINGCIRCLE* c); +@@ -2003,7 +2013,7 @@ extern int gserialized_get_gbox_p(const + #define LW_PARSER_CHECK_ZCLOSURE 8 + + #define LW_PARSER_CHECK_NONE 0 +-#define LW_PARSER_CHECK_ALL (LW_PARSER_CHECK_MINPOINTS | LW_PARSER_CHECK_ODD | LW_PARSER_CHECK_CLOSURE) ++#define LW_PARSER_CHECK_ALL (LW_PARSER_CHECK_MINPOINTS | LW_PARSER_CHECK_ODD | LW_PARSER_CHECK_CLOSURE) + + /** + * Parser result structure: returns the result of attempting to convert +@@ -2011,14 +2021,14 @@ extern int gserialized_get_gbox_p(const + */ + typedef struct struct_lwgeom_parser_result + { +- const char *wkinput; /* Copy of pointer to input WKT/WKB */ +- uint8_t *serialized_lwgeom; /* Pointer to serialized LWGEOM */ +- size_t size; /* Size of serialized LWGEOM in bytes */ +- LWGEOM *geom; /* Pointer to LWGEOM struct */ +- const char *message; /* Error/warning message */ +- int errcode; /* Error/warning number */ +- int errlocation; /* Location of error */ +- int parser_check_flags; /* Bitmask of validity checks run during this parse */ ++ const char *wkinput; /* Copy of pointer to input WKT/WKB */ ++ uint8_t *serialized_lwgeom; /* Pointer to serialized LWGEOM */ ++ size_t size; /* Size of serialized LWGEOM in bytes */ ++ LWGEOM *geom; /* Pointer to LWGEOM struct */ ++ const char *message; /* Error/warning message */ ++ int errcode; /* Error/warning number */ ++ int errlocation; /* Location of error */ ++ int parser_check_flags; /* Bitmask of validity checks run during this parse */ + } + LWGEOM_PARSER_RESULT; + +@@ -2043,20 +2053,20 @@ LWGEOM_PARSER_RESULT; + */ + typedef struct struct_lwgeom_unparser_result + { +- uint8_t *serialized_lwgeom; /* Copy of pointer to input serialized LWGEOM */ +- char *wkoutput; /* Pointer to WKT or WKB output */ +- size_t size; /* Size of serialized LWGEOM in bytes */ +- const char *message; /* Error/warning message */ +- int errlocation; /* Location of error */ ++ uint8_t *serialized_lwgeom; /* Copy of pointer to input serialized LWGEOM */ ++ char *wkoutput; /* Pointer to WKT or WKB output */ ++ size_t size; /* Size of serialized LWGEOM in bytes */ ++ const char *message; /* Error/warning message */ ++ int errlocation; /* Location of error */ + } + LWGEOM_UNPARSER_RESULT; + + /* + * Unparser error messages (these must match the message array in lwgunparse.c) + */ +-#define UNPARSER_ERROR_MOREPOINTS 1 +-#define UNPARSER_ERROR_ODDPOINTS 2 +-#define UNPARSER_ERROR_UNCLOSED 3 ++#define UNPARSER_ERROR_MOREPOINTS 1 ++#define UNPARSER_ERROR_ODDPOINTS 2 ++#define UNPARSER_ERROR_UNCLOSED 3 + + + /* +@@ -2200,27 +2210,27 @@ LWGEOM *lwgeom_unstroke(const LWGEOM *ge + * lwcurve_linearize + */ + typedef enum { +- /** +- * Tolerance expresses the number of segments to use +- * for each quarter of circle (quadrant). Must be +- * an integer. +- */ +- LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD = 0, +- /** +- * Tolerance expresses the maximum distance between +- * an arbitrary point on the curve and the closest +- * point to it on the resulting approximation, in +- * cartesian units. +- */ +- LW_LINEARIZE_TOLERANCE_TYPE_MAX_DEVIATION = 1, +- /** +- * Tolerance expresses the maximum angle between +- * the radii generating approximation line vertices, +- * given in radiuses. A value of 1 would result +- * in an approximation of a semicircle composed by +- * 180 segments +- */ +- LW_LINEARIZE_TOLERANCE_TYPE_MAX_ANGLE = 2 ++ /** ++ * Tolerance expresses the number of segments to use ++ * for each quarter of circle (quadrant). Must be ++ * an integer. ++ */ ++ LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD = 0, ++ /** ++ * Tolerance expresses the maximum distance between ++ * an arbitrary point on the curve and the closest ++ * point to it on the resulting approximation, in ++ * cartesian units. ++ */ ++ LW_LINEARIZE_TOLERANCE_TYPE_MAX_DEVIATION = 1, ++ /** ++ * Tolerance expresses the maximum angle between ++ * the radii generating approximation line vertices, ++ * given in radiuses. A value of 1 would result ++ * in an approximation of a semicircle composed by ++ * 180 segments ++ */ ++ LW_LINEARIZE_TOLERANCE_TYPE_MAX_ANGLE = 2 + } LW_LINEARIZE_TOLERANCE_TYPE; + + typedef enum { +@@ -2229,7 +2239,7 @@ typedef enum { + * vertices would be the same no matter the order + * of the points defining the input curve. + */ +- LW_LINEARIZE_FLAG_SYMMETRIC = 1 << 0, ++ LW_LINEARIZE_FLAG_SYMMETRIC = 1 << 0, + + /** + * Retain angle instructs the engine to try its best +@@ -2249,7 +2259,7 @@ typedef enum { + * instead be smaller (shorter) than the others. + * + */ +- LW_LINEARIZE_FLAG_RETAIN_ANGLE = 1 << 1 ++ LW_LINEARIZE_FLAG_RETAIN_ANGLE = 1 << 1 + } LW_LINEARIZE_FLAGS; + + /** +@@ -2332,6 +2342,9 @@ int lwgeom_is_simple(const LWGEOM *lwgeo + * PROJ4-dependent extra functions on LWGEOM + ******************************************************************************/ + ++int lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr); ++ ++#if POSTGIS_PROJ_VERSION < 60 + /** + * Get a projection from a string representation + * +@@ -2339,14 +2352,14 @@ int lwgeom_is_simple(const LWGEOM *lwgeo + */ + projPJ lwproj_from_string(const char* txt); + ++#endif + /** + * Transform (reproject) a geometry in-place. + * @param geom the geometry to transform +- * @param inpj the input (or current, or source) projection +- * @param outpj the output (or destination) projection ++ * @param PJ the input and output + */ +-int lwgeom_transform(LWGEOM *geom, projPJ inpj, projPJ outpj); +-int ptarray_transform(POINTARRAY *pa, projPJ inpj, projPJ outpj); ++int lwgeom_transform(LWGEOM *geom, PJ* pj); ++int ptarray_transform(POINTARRAY *pa, PJ* pj); + + + /******************************************************************************* +diff -rupN postgis-2.5.5/liblwgeom/liblwgeom_internal.h postgis-2.5.5-new/liblwgeom/liblwgeom_internal.h +--- postgis-2.5.5/liblwgeom/liblwgeom_internal.h 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/liblwgeom_internal.h 2022-08-06 11:48:23.733708197 +0200 +@@ -38,13 +38,14 @@ + #include + #include + #include ++#include ++#include ++#include + + #if HAVE_IEEEFP_H + #include + #endif + +-#include +- + #include "liblwgeom.h" + + /** +@@ -363,11 +364,6 @@ char lwcollection_same(const LWCOLLECTIO + char lwcircstring_same(const LWCIRCSTRING *p1, const LWCIRCSTRING *p2); + + /* +-* Transform +-*/ +-int point4d_transform(POINT4D *pt, projPJ srcpj, projPJ dstpj); +- +-/* + * Shift + */ + void ptarray_longitude_shift(POINTARRAY *pa); +@@ -502,5 +498,6 @@ int ptarray_npoints_in_rect(const POINTA + int gbox_contains_point2d(const GBOX *g, const POINT2D *p); + int lwpoly_contains_point(const LWPOLY *poly, const POINT2D *pt); + POINT4D* lwmpoint_extract_points_4d(const LWMPOINT* g, uint32_t* npoints, int* input_empty); ++char* lwstrdup(const char* a); + + #endif /* _LIBLWGEOM_INTERNAL_H */ +diff -rupN postgis-2.5.5/liblwgeom/lwgeom_transform.c postgis-2.5.5-new/liblwgeom/lwgeom_transform.c +--- postgis-2.5.5/liblwgeom/lwgeom_transform.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/lwgeom_transform.c 2022-08-06 11:59:22.562722935 +0200 +@@ -45,12 +45,53 @@ to_dec(POINT4D *pt) + pt->y *= 180.0/M_PI; + } + ++/***************************************************************************/ ++ ++#if POSTGIS_PROJ_VERSION < 60 ++ ++ ++static int ++point4d_transform(POINT4D *pt, PJ* pj) ++{ ++ POINT3D orig_pt = {pt->x, pt->y, pt->z}; /* Copy for error report*/ ++ ++ if (pj_is_latlong(pj->pj_from)) to_rad(pt) ; ++ ++ LWDEBUGF(4, "transforming POINT(%f %f) from '%s' to '%s'", ++ orig_pt.x, orig_pt.y, pj_get_def(pj->pj_from,0), pj_get_def(pj->pj_to,0)); ++ ++ if (pj_transform(pj->pj_from, pj->pj_to, 1, 0, &(pt->x), &(pt->y), &(pt->z)) != 0) ++ { ++ int pj_errno_val = *pj_get_errno_ref(); ++ if (pj_errno_val == -38) ++ { ++ lwnotice("PostGIS was unable to transform the point because either no grid" ++ " shift files were found, or the point does not lie within the " ++ "range for which the grid shift is defined. Refer to the " ++ "ST_Transform() section of the PostGIS manual for details on how " ++ "to configure PostGIS to alter this behaviour."); ++ lwerror("transform: couldn't project point (%g %g %g): %s (%d)", ++ orig_pt.x, orig_pt.y, orig_pt.z, ++ pj_strerrno(pj_errno_val), pj_errno_val); ++ } ++ else ++ { ++ lwerror("transform: %s (%d)", ++ pj_strerrno(pj_errno_val), pj_errno_val); ++ } ++ return LW_FAILURE; ++ } ++ ++ if (pj_is_latlong(pj->pj_to)) to_dec(pt); ++ return LW_SUCCESS; ++} ++ + /** + * Transform given POINTARRAY + * from inpj projection to outpj projection + */ + int +-ptarray_transform(POINTARRAY *pa, projPJ inpj, projPJ outpj) ++ptarray_transform(POINTARRAY *pa, PJ* pj) + { + uint32_t i; + POINT4D p; +@@ -58,20 +99,51 @@ ptarray_transform(POINTARRAY *pa, projPJ + for ( i = 0; i < pa->npoints; i++ ) + { + getPoint4d_p(pa, i, &p); +- if ( ! point4d_transform(&p, inpj, outpj) ) return LW_FAILURE; ++ if ( ! point4d_transform(&p, pj) ) return LW_FAILURE; + ptarray_set_point4d(pa, i, &p); + } + + return LW_SUCCESS; + } + ++int ++lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr) ++{ ++ char *pj_errstr; ++ int rv; ++ PJ pj; ++ ++ pj.pj_from = lwproj_from_string(instr); ++ if (!pj.pj_from) ++ { ++ pj_errstr = pj_strerrno(*pj_get_errno_ref()); ++ if (!pj_errstr) pj_errstr = ""; ++ lwerror("could not parse proj string '%s'", instr); ++ return LW_FAILURE; ++ } ++ ++ pj.pj_to = lwproj_from_string(outstr); ++ if (!pj.pj_to) ++ { ++ pj_free(pj.pj_from); ++ pj_errstr = pj_strerrno(*pj_get_errno_ref()); ++ if (!pj_errstr) pj_errstr = ""; ++ lwerror("could not parse proj string '%s'", outstr); ++ return LW_FAILURE; ++ } ++ ++ rv = lwgeom_transform(geom, &pj); ++ pj_free(pj.pj_from); ++ pj_free(pj.pj_to); ++ return rv; ++} + + /** +- * Transform given SERIALIZED geometry ++ * Transform given LWGEOM geometry + * from inpj projection to outpj projection + */ + int +-lwgeom_transform(LWGEOM *geom, projPJ inpj, projPJ outpj) ++lwgeom_transform(LWGEOM *geom, PJ* pj) + { + uint32_t i; + +@@ -87,7 +159,7 @@ lwgeom_transform(LWGEOM *geom, projPJ in + case TRIANGLETYPE: + { + LWLINE *g = (LWLINE*)geom; +- if ( ! ptarray_transform(g->points, inpj, outpj) ) return LW_FAILURE; ++ if ( ! ptarray_transform(g->points, pj) ) return LW_FAILURE; + break; + } + case POLYGONTYPE: +@@ -95,7 +167,7 @@ lwgeom_transform(LWGEOM *geom, projPJ in + LWPOLY *g = (LWPOLY*)geom; + for ( i = 0; i < g->nrings; i++ ) + { +- if ( ! ptarray_transform(g->rings[i], inpj, outpj) ) return LW_FAILURE; ++ if ( ! ptarray_transform(g->rings[i], pj) ) return LW_FAILURE; + } + break; + } +@@ -113,7 +185,7 @@ lwgeom_transform(LWGEOM *geom, projPJ in + LWCOLLECTION *g = (LWCOLLECTION*)geom; + for ( i = 0; i < g->ngeoms; i++ ) + { +- if ( ! lwgeom_transform(g->geoms[i], inpj, outpj) ) return LW_FAILURE; ++ if ( ! lwgeom_transform(g->geoms[i], pj) ) return LW_FAILURE; + } + break; + } +@@ -127,52 +199,287 @@ lwgeom_transform(LWGEOM *geom, projPJ in + return LW_SUCCESS; + } + +-int +-point4d_transform(POINT4D *pt, projPJ srcpj, projPJ dstpj) ++projPJ ++lwproj_from_string(const char *str1) + { +- POINT3D orig_pt = {pt->x, pt->y, pt->z}; /* Copy for error report*/ ++ if (!str1 || str1[0] == '\0') ++ { ++ return NULL; ++ } ++ return pj_init_plus(str1); ++} + +- if (pj_is_latlong(srcpj)) to_rad(pt) ; ++/***************************************************************************/ + +- LWDEBUGF(4, "transforming POINT(%f %f) from '%s' to '%s'", +- orig_pt.x, orig_pt.y, pj_get_def(srcpj,0), pj_get_def(dstpj,0)); ++#else /* POSTGIS_PROJ_VERION >= 60 */ + +- if (pj_transform(srcpj, dstpj, 1, 0, &(pt->x), &(pt->y), &(pt->z)) != 0) ++int ++lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr) ++{ ++ PJ *pj = proj_create_crs_to_crs(NULL, instr, outstr, NULL); ++ if (!pj) + { +- int pj_errno_val = *pj_get_errno_ref(); +- if (pj_errno_val == -38) ++ PJ *pj_in = proj_create(NULL, instr); ++ PJ *pj_out = proj_create(NULL, outstr); ++ if (!pj_in) + { +- lwnotice("PostGIS was unable to transform the point because either no grid" +- " shift files were found, or the point does not lie within the " +- "range for which the grid shift is defined. Refer to the " +- "ST_Transform() section of the PostGIS manual for details on how " +- "to configure PostGIS to alter this behaviour."); +- lwerror("transform: couldn't project point (%g %g %g): %s (%d)", +- orig_pt.x, orig_pt.y, orig_pt.z, +- pj_strerrno(pj_errno_val), pj_errno_val); ++ lwerror("could not parse proj string '%s'", instr); + } +- else ++ if (!pj_out) + { +- lwerror("transform: couldn't project point (%g %g %g): %s (%d)", +- orig_pt.x, orig_pt.y, orig_pt.z, +- pj_strerrno(pj_errno_val), pj_errno_val); ++ proj_destroy(pj_in); ++ lwerror("could not parse proj string '%s'", outstr); + } + return LW_FAILURE; + } + +- if (pj_is_latlong(dstpj)) to_dec(pt); ++ return lwgeom_transform(geom, pj); ++} ++ ++int ++lwgeom_transform(LWGEOM* geom, PJ* pj) ++{ ++ uint32_t i; ++ ++ /* No points to transform in an empty! */ ++ if (lwgeom_is_empty(geom)) ++ return LW_SUCCESS; ++ ++ switch(geom->type) ++ { ++ case POINTTYPE: ++ case LINETYPE: ++ case CIRCSTRINGTYPE: ++ case TRIANGLETYPE: ++ { ++ LWLINE *g = (LWLINE*)geom; ++ if (!ptarray_transform(g->points, pj)) ++ return LW_FAILURE; ++ break; ++ } ++ case POLYGONTYPE: ++ { ++ LWPOLY *g = (LWPOLY*)geom; ++ for (i = 0; i < g->nrings; i++) ++ { ++ if (!ptarray_transform(g->rings[i], pj)) ++ return LW_FAILURE; ++ } ++ break; ++ } ++ case MULTIPOINTTYPE: ++ case MULTILINETYPE: ++ case MULTIPOLYGONTYPE: ++ case COLLECTIONTYPE: ++ case COMPOUNDTYPE: ++ case CURVEPOLYTYPE: ++ case MULTICURVETYPE: ++ case MULTISURFACETYPE: ++ case POLYHEDRALSURFACETYPE: ++ case TINTYPE: ++ { ++ LWCOLLECTION *g = (LWCOLLECTION*)geom; ++ for (i = 0; i < g->ngeoms; i++) ++ { ++ if (!lwgeom_transform(g->geoms[i], pj)) ++ return LW_FAILURE; ++ } ++ break; ++ } ++ default: ++ { ++ lwerror("lwgeom_transform: Cannot handle type '%s'", ++ lwtype_name(geom->type)); ++ return LW_FAILURE; ++ } ++ } + return LW_SUCCESS; + } + +-projPJ +-lwproj_from_string(const char *str1) ++static int ++proj_crs_is_swapped(const PJ* pj_crs) + { +- if (!str1 || str1[0] == '\0') ++ PJ *pj_cs; ++ int rv = LW_FALSE; ++ ++ if (proj_get_type(pj_crs) == PJ_TYPE_COMPOUND_CRS) + { +- return NULL; ++ PJ *pj_horiz_crs = proj_crs_get_sub_crs(NULL, pj_crs, 0); ++ pj_cs = proj_crs_get_coordinate_system(NULL, pj_horiz_crs); ++ proj_destroy(pj_horiz_crs); + } +- return pj_init_plus(str1); ++ else if (proj_get_type(pj_crs) == PJ_TYPE_BOUND_CRS) ++ { ++ PJ *pj_bound_crs = proj_get_source_crs(NULL, pj_crs); ++ pj_cs = proj_crs_get_coordinate_system(NULL, pj_bound_crs); ++ proj_destroy(pj_bound_crs); ++ } ++ else ++ { ++ pj_cs = proj_crs_get_coordinate_system(NULL, pj_crs); ++ } ++ int axis_count = proj_cs_get_axis_count(NULL, pj_cs); ++ if (axis_count > 0) ++ { ++ const char *out_name, *out_abbrev, *out_direction; ++ double out_unit_conv_factor; ++ const char *out_unit_name, *out_unit_auth_name, *out_unit_code; ++ /* Read only first axis, see if it is degrees / north */ ++ proj_cs_get_axis_info(NULL, pj_cs, 0, ++ &out_name, ++ &out_abbrev, ++ &out_direction, ++ &out_unit_conv_factor, ++ &out_unit_name, ++ &out_unit_auth_name, ++ &out_unit_code ++ ); ++ rv = (strcasecmp(out_direction, "north") == 0); ++ } ++ proj_destroy(pj_cs); ++ return rv; ++} ++ ++ ++int ++ptarray_transform(POINTARRAY* pa, PJ* pj) ++{ ++ uint32_t i; ++ POINT4D p; ++ size_t n_converted; ++ size_t n_points = pa->npoints; ++ size_t point_size = ptarray_point_size(pa); ++ int has_z = ptarray_has_z(pa); ++ double *pa_double = (double*)(pa->serialized_pointlist); ++ int input_swapped, output_swapped; ++ ++ /* XXXX TODO check that the PJ has decimal degrees as units in input/output */ ++ ++ PJ* pj_source_crs = proj_get_source_crs(NULL, pj); ++ PJ* pj_target_crs = proj_get_target_crs(NULL, pj); ++ ++ if (!(pj_source_crs && pj_source_crs)) ++ { ++ lwerror("ptarray_transform: unable to access source and target crs"); ++ return LW_FAILURE; ++ } ++ ++ input_swapped = proj_crs_is_swapped(pj_source_crs); ++ output_swapped = proj_crs_is_swapped(pj_target_crs); ++ proj_destroy(pj_source_crs); ++ proj_destroy(pj_target_crs); ++ ++ /* Convert to radians if necessary */ ++ if (proj_angular_input(pj, PJ_FWD)) ++ { ++ for (i = 0; i < pa->npoints; i++) ++ { ++ getPoint4d_p(pa, i, &p); ++ to_rad(&p); ++ } ++ } ++ ++ if (input_swapped) ++ ptarray_swap_ordinates(pa, LWORD_X, LWORD_Y); ++ ++ /* ++ * size_t proj_trans_generic(PJ *P, PJ_DIRECTION direction, ++ * double *x, size_t sx, size_t nx, ++ * double *y, size_t sy, size_t ny, ++ * double *z, size_t sz, size_t nz, ++ * double *t, size_t st, size_t nt) ++ */ ++ ++ n_converted = proj_trans_generic( ++ pj, PJ_FWD, ++ pa_double, point_size, n_points, /* X */ ++ pa_double + 1, point_size, n_points, /* Y */ ++ has_z ? pa_double + 2 : NULL, ++ has_z ? point_size : 0, ++ has_z ? n_points : 0, /* Z */ ++ NULL, 0, 0 /* M */ ++ ); ++ ++ if (n_converted != n_points) ++ { ++ lwerror("ptarray_transform: converted (%d) != input (%d)", ++ n_converted, n_points); ++ return LW_FAILURE; ++ } ++ ++ int pj_errno_val = proj_errno(pj); ++ if (pj_errno_val) ++ { ++ lwerror("transform: %s (%d)", ++ proj_errno_string(pj_errno_val), pj_errno_val); ++ return LW_FAILURE; ++ } ++ ++ if (output_swapped) ++ ptarray_swap_ordinates(pa, LWORD_X, LWORD_Y); ++ ++ /* Convert radians to degrees if necessary */ ++ if (proj_angular_output(pj, PJ_FWD)) ++ { ++ for (i = 0; i < pa->npoints; i++) ++ { ++ getPoint4d_p(pa, i, &p); ++ to_dec(&p); ++ } ++ } ++ ++ return LW_SUCCESS; + } + ++#if 0 ++int ++point4d_transform(POINT4D *pt, PJ* pj) ++{ ++ POINT4D pt_src = *pt; /* Copy for error report*/ ++ PJ_COORD pj_coord_src, pj_coord_dst; ++ int input_swapped = proj_crs_is_swapped(proj_get_source_crs(NULL, pj)); ++ int output_swapped = proj_crs_is_swapped(proj_get_target_crs(NULL, pj)); ++ ++ if (proj_angular_input(pj, PJ_FWD)) ++ to_rad(pt); ++ ++ LWDEBUGF(4, "transforming POINT(%f %f) using '%s'", ++ pt_src.x, pt_src.y, (proj_pj_info(pj)).definition); ++ ++ if (input_swapped) ++ pj_coord_src = proj_coord(pt->y, pt->x, pt->z, pt->m); ++ else ++ pj_coord_src = proj_coord(pt->x, pt->y, pt->z, pt->m); ++ ++ pj_coord_dst = proj_trans(pj, PJ_FWD, pj_coord_src); ++ ++ int pj_errno_val = proj_errno(pj); ++ if (pj_errno_val) ++ { ++ lwerror("point4d_transform: couldn't project point (%g %g %g): %s (%d)", ++ pt_src.x, pt_src.y, pt_src.z, ++ proj_errno_string(pj_errno_val), pj_errno_val); ++ return LW_FAILURE; ++ } ++ ++ if (output_swapped) ++ { ++ pt->x = pj_coord_dst.xyzt.x; ++ pt->y = pj_coord_dst.xyzt.y; ++ } ++ else ++ { ++ pt->x = pj_coord_dst.xyzt.x; ++ pt->y = pj_coord_dst.xyzt.y; ++ } ++ pt->z = pj_coord_dst.xyzt.z; ++ pt->m = pt_src.m; ++ ++ if (proj_angular_output(pj, PJ_FWD)) ++ to_dec(pt); ++ return LW_SUCCESS; ++} ++#endif /* point4d_transform */ + + ++#endif +diff -rupN postgis-2.5.5/liblwgeom/lwin_encoded_polyline.c postgis-2.5.5-new/liblwgeom/lwin_encoded_polyline.c +--- postgis-2.5.5/liblwgeom/lwin_encoded_polyline.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/lwin_encoded_polyline.c 2022-08-06 11:48:23.734708197 +0200 +@@ -25,6 +25,8 @@ + + #include + #include ++#include ++ + #include "liblwgeom.h" + #include "../postgis_config.h" + +diff -rupN postgis-2.5.5/liblwgeom/lwspheroid.c postgis-2.5.5-new/liblwgeom/lwspheroid.c +--- postgis-2.5.5/liblwgeom/lwspheroid.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/lwspheroid.c 2022-08-06 11:48:23.735708197 +0200 +@@ -28,8 +28,8 @@ + #include "lwgeodetic.h" + #include "lwgeom_log.h" + +-/* GeographicLib */ +-#if PROJ_GEODESIC ++/* In proj4.9, GeographicLib is in special header */ ++#ifdef PROJ_GEODESIC + #include + #endif + +@@ -45,7 +45,7 @@ void spheroid_init(SPHEROID *s, double a + s->radius = (2.0 * a + b ) / 3.0; + } + +-#if ! PROJ_GEODESIC ++#ifndef PROJ_GEODESIC + static double spheroid_mu2(double alpha, const SPHEROID *s) + { + double b2 = POW2(s->b); +@@ -64,7 +64,7 @@ static double spheroid_big_b(double u2) + #endif /* ! PROJ_GEODESIC */ + + +-#if PROJ_GEODESIC ++#ifdef PROJ_GEODESIC + + /** + * Computes the shortest distance along the surface of the spheroid +@@ -165,7 +165,7 @@ static double ptarray_area_spheroid(cons + return fabs(area); + } + +-/* Above use GeographicLib */ ++/* Above use Proj GeographicLib */ + #else /* ! PROJ_GEODESIC */ + /* Below use pre-version 2.2 geodesic functions */ + +diff -rupN postgis-2.5.5/liblwgeom/lwunionfind.c postgis-2.5.5-new/liblwgeom/lwunionfind.c +--- postgis-2.5.5/liblwgeom/lwunionfind.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/lwunionfind.c 2022-08-06 11:48:23.735708197 +0200 +@@ -26,6 +26,7 @@ + #include "liblwgeom.h" + #include "lwunionfind.h" + #include ++#include + + static int cmp_int(const void *a, const void *b); + static int cmp_int_ptr(const void *a, const void *b); +diff -rupN postgis-2.5.5/liblwgeom/lwutil.c postgis-2.5.5-new/liblwgeom/lwutil.c +--- postgis-2.5.5/liblwgeom/lwutil.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/lwutil.c 2022-08-06 11:48:23.735708197 +0200 +@@ -246,6 +246,15 @@ lwfree(void *mem) + lwfree_var(mem); + } + ++char * ++lwstrdup(const char* a) ++{ ++ size_t l = strlen(a)+1; ++ char *b = lwalloc(l); ++ strncpy(b, a, l); ++ return b; ++} ++ + /* + * Returns a new string which contains a maximum of maxlength characters starting + * from startpos and finishing at endpos (0-based indexing). If the string is +diff -rupN postgis-2.5.5/liblwgeom/ptarray.c postgis-2.5.5-new/liblwgeom/ptarray.c +--- postgis-2.5.5/liblwgeom/ptarray.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/liblwgeom/ptarray.c 2022-08-06 11:48:23.736708197 +0200 +@@ -26,6 +26,7 @@ + + #include + #include ++#include + + #include "../postgis_config.h" + /*#define POSTGIS_DEBUG_LEVEL 4*/ +@@ -390,8 +391,8 @@ ptarray_swap_ordinates(POINTARRAY *pa, L + double d, *dp1, *dp2; + POINT4D p; + +- dp1 = ((double*)&p)+(unsigned)o1; +- dp2 = ((double*)&p)+(unsigned)o2; ++ dp1 = ((double*)&p)+(unsigned)o1; ++ dp2 = ((double*)&p)+(unsigned)o2; + for (i=0 ; i < pa->npoints ; i++) + { + getPoint4d_p(pa, i, &p); +diff -rupN postgis-2.5.5/libpgcommon/lwgeom_cache.c postgis-2.5.5-new/libpgcommon/lwgeom_cache.c +--- postgis-2.5.5/libpgcommon/lwgeom_cache.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/libpgcommon/lwgeom_cache.c 2022-08-06 11:48:23.737708197 +0200 +@@ -77,35 +77,36 @@ GetGenericCacheCollection(FunctionCallIn + + + /** +-* Get the Proj4 entry from the generic cache if one exists. ++* Get the Proj entry from the generic cache if one exists. + * If it doesn't exist, make a new empty one and return it. + */ +-PROJ4PortalCache * +-GetPROJ4SRSCache(FunctionCallInfo fcinfo) ++PROJPortalCache * ++GetPROJSRSCache(FunctionCallInfo fcinfo) + { + GenericCacheCollection* generic_cache = GetGenericCacheCollection(fcinfo); +- PROJ4PortalCache* cache = (PROJ4PortalCache*)(generic_cache->entry[PROJ_CACHE_ENTRY]); ++ PROJPortalCache* cache = (PROJPortalCache*)(generic_cache->entry[PROJ_CACHE_ENTRY]); + + if ( ! cache ) + { + /* Allocate in the upper context */ +- cache = MemoryContextAlloc(FIContext(fcinfo), sizeof(PROJ4PortalCache)); ++ cache = MemoryContextAlloc(FIContext(fcinfo), sizeof(PROJPortalCache)); + + if (cache) + { + int i; + +- POSTGIS_DEBUGF(3, "Allocating PROJ4Cache for portal with transform() MemoryContext %p", FIContext(fcinfo)); ++ POSTGIS_DEBUGF(3, "Allocating PROJCache for portal with transform() MemoryContext %p", FIContext(fcinfo)); + /* Put in any required defaults */ +- for (i = 0; i < PROJ4_CACHE_ITEMS; i++) ++ for (i = 0; i < PROJ_CACHE_ITEMS; i++) + { +- cache->PROJ4SRSCache[i].srid = SRID_UNKNOWN; +- cache->PROJ4SRSCache[i].projection = NULL; +- cache->PROJ4SRSCache[i].projection_mcxt = NULL; ++ cache->PROJSRSCache[i].srid_from = SRID_UNKNOWN; ++ cache->PROJSRSCache[i].srid_to = SRID_UNKNOWN; ++ cache->PROJSRSCache[i].projection = NULL; ++ cache->PROJSRSCache[i].projection_mcxt = NULL; + } + cache->type = PROJ_CACHE_ENTRY; +- cache->PROJ4SRSCacheCount = 0; +- cache->PROJ4SRSCacheContext = FIContext(fcinfo); ++ cache->PROJSRSCacheCount = 0; ++ cache->PROJSRSCacheContext = FIContext(fcinfo); + + /* Store the pointer in GenericCache */ + generic_cache->entry[PROJ_CACHE_ENTRY] = (GenericCache*)cache; +diff -rupN postgis-2.5.5/libpgcommon/lwgeom_cache.h postgis-2.5.5-new/libpgcommon/lwgeom_cache.h +--- postgis-2.5.5/libpgcommon/lwgeom_cache.h 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/libpgcommon/lwgeom_cache.h 2022-08-06 11:48:23.737708197 +0200 +@@ -62,31 +62,32 @@ typedef struct { + * fcinfo->flinfo->fn_extra to avoid collisions. + */ + +-/* An entry in the PROJ4 SRS cache */ +-typedef struct struct_PROJ4SRSCacheItem ++/* An entry in the PROJ SRS cache */ ++typedef struct struct_PROJSRSCacheItem + { +- int srid; +- projPJ projection; ++ int srid_from; ++ int srid_to; ++ PJ* projection; + MemoryContext projection_mcxt; + } +-PROJ4SRSCacheItem; ++PROJSRSCacheItem; + + /* PROJ 4 lookup transaction cache methods */ +-#define PROJ4_CACHE_ITEMS 8 ++#define PROJ_CACHE_ITEMS 8 + + /* + * The proj4 cache holds a fixed number of reprojection + * entries. In normal usage we don't expect it to have + * many entries, so we always linearly scan the list. + */ +-typedef struct struct_PROJ4PortalCache ++typedef struct struct_PROJPortalCache + { + int type; +- PROJ4SRSCacheItem PROJ4SRSCache[PROJ4_CACHE_ITEMS]; +- int PROJ4SRSCacheCount; +- MemoryContext PROJ4SRSCacheContext; ++ PROJSRSCacheItem PROJSRSCache[PROJ_CACHE_ITEMS]; ++ int PROJSRSCacheCount; ++ MemoryContext PROJSRSCacheContext; + } +-PROJ4PortalCache; ++PROJPortalCache; + + /** + * Generic signature for functions to manage a geometry +@@ -103,7 +104,7 @@ typedef struct + /* + * Cache retrieval functions + */ +-PROJ4PortalCache *GetPROJ4SRSCache(FunctionCallInfo fcinfo); ++PROJPortalCache *GetPROJSRSCache(FunctionCallInfo fcinfo); + GeomCache *GetGeomCache(FunctionCallInfo fcinfo, + const GeomCacheMethods *cache_methods, + const GSERIALIZED *g1, +diff -rupN postgis-2.5.5/libpgcommon/lwgeom_transform.c postgis-2.5.5-new/libpgcommon/lwgeom_transform.c +--- postgis-2.5.5/libpgcommon/lwgeom_transform.c 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/libpgcommon/lwgeom_transform.c 2022-08-06 12:22:51.237754447 +0200 +@@ -34,37 +34,51 @@ + #include + + ++/** ++* Global variable to hold cached information about what ++* schema functions are installed in. Currently used by ++* SetSpatialRefSysSchema and GetProjStringsSPI ++*/ ++static char *spatialRefSysSchema = NULL; + + +-/* Expose an internal Proj function */ +-int pj_transform_nodatum(projPJ srcdefn, projPJ dstdefn, long point_count, int point_offset, double *x, double *y, double *z ); +- + /* + * PROJ 4 backend hash table initial hash size + * (since 16 is the default portal hash table size, and we would + * typically have 2 entries per portal + * then we shall use a default size of 32) + */ +-#define PROJ4_BACKEND_HASH_SIZE 32 ++#define PROJ_BACKEND_HASH_SIZE 32 + + + /** +- * Backend projPJ hash table ++ * Backend PROJ hash table + * +- * This hash table stores a key/value pair of MemoryContext/projPJ objects. +- * Whenever we create a projPJ object using pj_init(), we create a separate ++ * This hash table stores a key/value pair of MemoryContext/PJ objects. ++ * Whenever we create a PJ object using pj_init(), we create a separate + * MemoryContext as a child context of the current executor context. +- * The MemoryContext/projPJ object is stored in this hash table so +- * that when PROJ4SRSCacheDelete() is called during query cleanup, we can +- * lookup the projPJ object based upon the MemoryContext parameter and hence ++ * The MemoryContext/PJ object is stored in this hash table so ++ * that when PROJSRSCacheDelete() is called during query cleanup, we can ++ * lookup the PJ object based upon the MemoryContext parameter and hence + * pj_free() it. + */ + static HTAB *PJHash = NULL; + ++/** ++ * Utility structure to get many potential string representations ++ * from spatial_ref_sys query. ++ */ ++typedef struct { ++ char* epsgtext; ++ char* srtext; ++ char* proj4text; ++} PjStrs; ++ ++ + typedef struct struct_PJHashEntry + { + MemoryContext ProjectionContext; +- projPJ projection; ++ PJ* projection; + } + PJHashEntry; + +@@ -73,42 +87,92 @@ PJHashEntry; + uint32 mcxt_ptr_hash(const void *key, Size keysize); + + static HTAB *CreatePJHash(void); +-static void AddPJHashEntry(MemoryContext mcxt, projPJ projection); +-static projPJ GetPJHashEntry(MemoryContext mcxt); + static void DeletePJHashEntry(MemoryContext mcxt); ++static PJ* GetPJHashEntry(MemoryContext mcxt); ++static void AddPJHashEntry(MemoryContext mcxt, PJ* projection); + + /* Internal Cache API */ +-/* static PROJ4PortalCache *GetPROJ4SRSCache(FunctionCallInfo fcinfo) ; */ +-static bool IsInPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid); +-static projPJ GetProjectionFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid); +-static void AddToPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid, int other_srid); +-static void DeleteFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid); ++/* static PROJPortalCache *GetPROJSRSCache(FunctionCallInfo fcinfo) ; */ ++static bool IsInPROJSRSCache(PROJPortalCache *PROJCache, int srid_from, int srid_to); ++static void AddToPROJSRSCache(PROJPortalCache *PROJCache, int srid_from, int srid_to); ++static void DeleteFromPROJSRSCache(PROJPortalCache *PROJCache, int srid_from, int srid_to); ++ + + /* Search path for PROJ.4 library */ +-static bool IsPROJ4LibPathSet = false; +-void SetPROJ4LibPath(void); ++static bool IsPROJLibPathSet = false; ++void SetPROJLibPath(void); ++ ++ ++/* ++* Given a function call context, figure out what namespace the ++* function is being called from, and copy that into a global ++* for use by GetProjStringsSPI ++*/ ++static void ++SetSpatialRefSysSchema(FunctionCallInfo fcinfo) ++{ ++ char *nsp_name; ++ ++ /* Schema info is already cached, we're done here */ ++ if (spatialRefSysSchema) return; ++ ++ /* For some reason we have a hobbled fcinfo/flinfo */ ++ if (!fcinfo || !fcinfo->flinfo) return; ++ ++ nsp_name = get_namespace_name(get_func_namespace(fcinfo->flinfo->fn_oid)); ++ /* early exit if we cannot lookup nsp_name, cf #4067 */ ++ if (!nsp_name) return; ++ ++ elog(DEBUG4, "%s located %s in namespace %s", __func__, get_func_name(fcinfo->flinfo->fn_oid), nsp_name); ++ spatialRefSysSchema = MemoryContextStrdup(CacheMemoryContext, nsp_name); ++ return; ++} ++ ++static void ++PROJSRSDestroyPJ(PJ* pj) ++{ ++#if POSTGIS_PROJ_VERSION < 60 ++/* Ape the Proj 6+ API for versions < 6 */ ++ if (pj->pj_from) ++ pj_free(pj->pj_from); ++ if (pj->pj_to) ++ pj_free(pj->pj_to); ++ free(pj); ++#else ++ proj_destroy(pj); ++#endif ++} + ++#if 0 ++static const char * ++PJErrStr() ++{ ++ const char *pj_errstr = pj_strerrno(*pj_get_errno_ref()); ++ if (!pj_errstr) ++ return ""; ++ return pj_errstr; ++} ++#endif + + static void + #if POSTGIS_PGSQL_VERSION < 96 +-PROJ4SRSCacheDelete(MemoryContext context) ++PROJSRSCacheDelete(MemoryContext context) + { + #else +-PROJ4SRSCacheDelete(void *ptr) ++PROJSRSCacheDelete(void *ptr) + { + MemoryContext context = (MemoryContext)ptr; + #endif +- projPJ projection; + +- /* Lookup the projPJ pointer in the global hash table so we can free it */ +- projection = GetPJHashEntry(context); ++ /* Lookup the PJ pointer in the global hash table so we can free it */ ++ PJ* projection = GetPJHashEntry(context); + + if (!projection) +- elog(ERROR, "PROJ4SRSCacheDelete: Trying to delete non-existant projection object with MemoryContext key (%p)", (void *)context); ++ elog(ERROR, "PROJSRSCacheDelete: Trying to delete non-existant projection object with MemoryContext key (%p)", (void *)context); + + POSTGIS_DEBUGF(3, "deleting projection object (%p) with MemoryContext key (%p)", projection, context); + /* Free it */ +- pj_free(projection); ++ PROJSRSDestroyPJ(projection); + + /* Remove the hash entry as it is no longer needed */ + DeletePJHashEntry(context); +@@ -117,7 +181,7 @@ PROJ4SRSCacheDelete(void *ptr) + #if POSTGIS_PGSQL_VERSION < 96 + + static void +-PROJ4SRSCacheInit(MemoryContext context) ++PROJSRSCacheInit(MemoryContext context) + { + /* + * Do nothing as the cache is initialised when the transform() +@@ -126,7 +190,7 @@ PROJ4SRSCacheInit(MemoryContext context) + } + + static void +-PROJ4SRSCacheReset(MemoryContext context) ++PROJSRSCacheReset(MemoryContext context) + { + /* + * Do nothing, but we must supply a function since this call is mandatory according to tgl +@@ -135,7 +199,7 @@ PROJ4SRSCacheReset(MemoryContext context + } + + static bool +-PROJ4SRSCacheIsEmpty(MemoryContext context) ++PROJSRSCacheIsEmpty(MemoryContext context) + { + /* + * Always return false since this call is mandatory according to tgl +@@ -145,19 +209,19 @@ PROJ4SRSCacheIsEmpty(MemoryContext conte + } + + static void +-PROJ4SRSCacheStats(MemoryContext context, int level) ++PROJSRSCacheStats(MemoryContext context, int level) + { + /* + * Simple stats display function - we must supply a function since this call is mandatory according to tgl + * (see postgis-devel archives July 2007) + */ + +- fprintf(stderr, "%s: PROJ4 context\n", context->name); ++ fprintf(stderr, "%s: PROJ context\n", context->name); + } + + #ifdef MEMORY_CONTEXT_CHECKING + static void +-PROJ4SRSCacheCheck(MemoryContext context) ++PROJSRSCacheCheck(MemoryContext context) + { + /* + * Do nothing - stub required for when PostgreSQL is compiled +@@ -167,26 +231,26 @@ PROJ4SRSCacheCheck(MemoryContext context + #endif + + /* Memory context definition must match the current version of PostgreSQL */ +-static MemoryContextMethods PROJ4SRSCacheContextMethods = ++static MemoryContextMethods PROJSRSCacheContextMethods = + { + NULL, + NULL, + NULL, +- PROJ4SRSCacheInit, +- PROJ4SRSCacheReset, +- PROJ4SRSCacheDelete, ++ PROJSRSCacheInit, ++ PROJSRSCacheReset, ++ PROJSRSCacheDelete, + NULL, +- PROJ4SRSCacheIsEmpty, +- PROJ4SRSCacheStats ++ PROJSRSCacheIsEmpty, ++ PROJSRSCacheStats + #ifdef MEMORY_CONTEXT_CHECKING +- ,PROJ4SRSCacheCheck ++ ,PROJSRSCacheCheck + #endif + }; + + #endif /* POSTGIS_PGSQL_VERSION < 96 */ + + /* +- * PROJ4 projPJ Hash Table functions ++ * PROJ PJ Hash Table functions + */ + + +@@ -213,10 +277,10 @@ static HTAB *CreatePJHash(void) + ctl.entrysize = sizeof(PJHashEntry); + ctl.hash = mcxt_ptr_hash; + +- return hash_create("PostGIS PROJ4 Backend projPJ MemoryContext Hash", PROJ4_BACKEND_HASH_SIZE, &ctl, (HASH_ELEM | HASH_FUNCTION)); ++ return hash_create("PostGIS PROJ Backend MemoryContext Hash", PROJ_BACKEND_HASH_SIZE, &ctl, (HASH_ELEM | HASH_FUNCTION)); + } + +-static void AddPJHashEntry(MemoryContext mcxt, projPJ projection) ++static void AddPJHashEntry(MemoryContext mcxt, PJ* projection) + { + bool found; + void **key; +@@ -225,7 +289,7 @@ static void AddPJHashEntry(MemoryContext + /* The hash key is the MemoryContext pointer */ + key = (void *)&mcxt; + +- he = (PJHashEntry *) hash_search(PJHash, key, HASH_ENTER, &found); ++ he = (PJHashEntry*) hash_search(PJHash, key, HASH_ENTER, &found); + if (!found) + { + /* Insert the entry into the new hash element */ +@@ -234,12 +298,12 @@ static void AddPJHashEntry(MemoryContext + } + else + { +- elog(ERROR, "AddPJHashEntry: PROJ4 projection object already exists for this MemoryContext (%p)", ++ elog(ERROR, "AddPJHashEntry: PROJ projection object already exists for this MemoryContext (%p)", + (void *)mcxt); + } + } + +-static projPJ GetPJHashEntry(MemoryContext mcxt) ++static PJ* GetPJHashEntry(MemoryContext mcxt) + { + void **key; + PJHashEntry *he; +@@ -266,118 +330,140 @@ static void DeletePJHashEntry(MemoryCont + he = (PJHashEntry *) hash_search(PJHash, key, HASH_REMOVE, NULL); + + if (!he) +- elog(ERROR, "DeletePJHashEntry: There was an error removing the PROJ4 projection object from this MemoryContext (%p)", (void *)mcxt); ++ elog(ERROR, "DeletePJHashEntry: There was an error removing the PROJ projection object from this MemoryContext (%p)", (void *)mcxt); + else + he->projection = NULL; + } + +-bool +-IsInPROJ4Cache(Proj4Cache PROJ4Cache, int srid) { +- return IsInPROJ4SRSCache((PROJ4PortalCache *)PROJ4Cache, srid) ; +-} +- +-/* ++/***************************************************************************** + * Per-cache management functions + */ + + static bool +-IsInPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid) ++IsInPROJSRSCache(PROJPortalCache *cache, int srid_from, int srid_to) + { + /* + * Return true/false depending upon whether the item + * is in the SRS cache. + */ +- +- int i; +- +- for (i = 0; i < PROJ4_CACHE_ITEMS; i++) ++ uint32_t i; ++ for (i = 0; i < PROJ_CACHE_ITEMS; i++) + { +- if (PROJ4Cache->PROJ4SRSCache[i].srid == srid) +- return 1; ++ if (cache->PROJSRSCache[i].srid_from == srid_from && ++ cache->PROJSRSCache[i].srid_to == srid_to) ++ return true; + } +- + /* Otherwise not found */ +- return 0; ++ return false; + } + +-projPJ GetProjectionFromPROJ4Cache(Proj4Cache cache, int srid) ++static PJ* ++GetProjectionFromPROJCache(PROJPortalCache *cache, int srid_from, int srid_to) + { +- return GetProjectionFromPROJ4SRSCache((PROJ4PortalCache *)cache, srid) ; ++ uint32_t i; ++ for (i = 0; i < PROJ_CACHE_ITEMS; i++) ++ { ++ if (cache->PROJSRSCache[i].srid_from == srid_from && ++ cache->PROJSRSCache[i].srid_to == srid_to) ++ return cache->PROJSRSCache[i].projection; ++ } ++ ++ return NULL; + } + +-/** +- * Return the projection object from the cache (we should +- * already have checked it exists using IsInPROJ4SRSCache first) +- */ +-static projPJ +-GetProjectionFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid) ++static char* ++SPI_pstrdup(const char* str) + { +- int i; +- +- for (i = 0; i < PROJ4_CACHE_ITEMS; i++) ++ char* ostr = NULL; ++ if (str) + { +- if (PROJ4Cache->PROJ4SRSCache[i].srid == srid) +- return PROJ4Cache->PROJ4SRSCache[i].projection; ++ ostr = SPI_palloc(strlen(str)+1); ++ strcpy(ostr, str); + } +- +- return NULL; ++ return ostr; + } + +-char* GetProj4StringSPI(int srid) ++static PjStrs ++GetProjStringsSPI(int srid) + { +- static int maxproj4len = 512; ++ const int maxprojlen = 512; ++ const int spibufferlen = 512; + int spi_result; +- char *proj_str = palloc(maxproj4len); +- char proj4_spi_buffer[256]; ++ char proj_spi_buffer[spibufferlen]; ++ PjStrs strs; ++ memset(&strs, 0, sizeof(strs)); + + /* Connect */ + spi_result = SPI_connect(); + if (spi_result != SPI_OK_CONNECT) + { +- elog(ERROR, "GetProj4StringSPI: Could not connect to database using SPI"); ++ elog(ERROR, "Could not connect to database using SPI"); + } + +- static char *proj_str_tmpl = +- "SELECT proj4text, auth_name, auth_srid, srtext " +- "FROM %s " +- "WHERE srid = %d " +- "LIMIT 1"; +- snprintf(proj4_spi_buffer, 255, proj_str_tmpl, postgis_spatial_ref_sys(), srid); ++ /* ++ * This global is allocated in CacheMemoryContext (lifespan of this backend) ++ * and is set by SetSpatialRefSysSchema the first time ++ * that GetPJUsingFCInfo is called. ++ */ ++ static char *proj_str_tmpl = "SELECT proj4text, auth_name, auth_srid, srtext " ++ "FROM %s%sspatial_ref_sys " ++ "WHERE srid = %d " ++ "LIMIT 1"; ++ if (spatialRefSysSchema) ++ { ++ snprintf(proj_spi_buffer, spibufferlen, proj_str_tmpl, spatialRefSysSchema, ".", srid); ++ } ++ else ++ { ++ snprintf(proj_spi_buffer, spibufferlen, proj_str_tmpl, "", "", srid); ++ } + + /* Execute the query, noting the readonly status of this SQL */ +- spi_result = SPI_execute(proj4_spi_buffer, true, 1); ++ spi_result = SPI_execute(proj_spi_buffer, true, 1); + +- /* Read back the PROJ4 text */ ++ /* Read back the PROJ text */ + if (spi_result == SPI_OK_SELECT && SPI_processed > 0) + { + /* Select the first (and only tuple) */ + TupleDesc tupdesc = SPI_tuptable->tupdesc; + SPITupleTable *tuptable = SPI_tuptable; + HeapTuple tuple = tuptable->vals[0]; +- char *proj4text = SPI_getvalue(tuple, tupdesc, 1); +- +- if ( proj4text ) +- { +- /* Make a projection object out of it */ +- strncpy(proj_str, proj4text, maxproj4len - 1); +- } +- else +- { +- proj_str[0] = 0; +- } ++ /* Always return the proj4text */ ++ char* proj4text = SPI_getvalue(tuple, tupdesc, 1); ++ if (proj4text && strlen(proj4text)) ++ strs.proj4text = SPI_pstrdup(proj4text); ++ ++ /* For Proj >= 6 prefer "EPSG:XXXX" to proj strings */ ++ /* as proj_create_crs_to_crs() will give us more consistent */ ++ /* results with EPSG numbers than with proj strings */ ++ char* authname = SPI_getvalue(tuple, tupdesc, 2); ++ char* authsrid = SPI_getvalue(tuple, tupdesc, 3); ++ if (authname && authsrid && ++ strcmp(authname,"EPSG") == 0 && ++ strlen(authsrid)) ++ { ++ char tmp[maxprojlen]; ++ snprintf(tmp, maxprojlen, "EPSG:%s", authsrid); ++ strs.epsgtext = SPI_pstrdup(tmp); ++ } ++ ++ /* Proj6+ can parse srtext, so return that too */ ++ char* srtext = SPI_getvalue(tuple, tupdesc, 4); ++ if (srtext && strlen(srtext)) ++ strs.srtext = SPI_pstrdup(srtext); + } + else + { +- elog(ERROR, "GetProj4StringSPI: Cannot find SRID (%d) in spatial_ref_sys", srid); ++ elog(ERROR, "Cannot find SRID (%d) in spatial_ref_sys", srid); + } + + spi_result = SPI_finish(); + if (spi_result != SPI_OK_FINISH) + { +- elog(ERROR, "GetProj4StringSPI: Could not disconnect from database using SPI"); ++ elog(ERROR, "Could not disconnect from database using SPI"); + } + +- return proj_str; ++ return strs; + } + + +@@ -387,29 +473,32 @@ char* GetProj4StringSPI(int srid) + * (WGS84 UTM N/S, Polar Stereographic N/S - see SRID_* macros), + * return the proj4text for those. + */ +-static char* GetProj4String(int srid) ++static PjStrs ++GetProjStrings(int srid) + { +- static int maxproj4len = 512; ++ const int maxprojlen = 512; ++ PjStrs strs; ++ memset(&strs, 0, sizeof(strs)); + + /* SRIDs in SPATIAL_REF_SYS */ + if ( srid < SRID_RESERVE_OFFSET ) + { +- return GetProj4StringSPI(srid); ++ return GetProjStringsSPI(srid); + } + /* Automagic SRIDs */ + else + { +- char *proj_str = palloc(maxproj4len); ++ strs.proj4text = palloc(maxprojlen); + int id = srid; + /* UTM North */ + if ( id >= SRID_NORTH_UTM_START && id <= SRID_NORTH_UTM_END ) + { +- snprintf(proj_str, maxproj4len, "+proj=utm +zone=%d +ellps=WGS84 +datum=WGS84 +units=m +no_defs", id - SRID_NORTH_UTM_START + 1); ++ snprintf(strs.proj4text, maxprojlen, "+proj=utm +zone=%d +ellps=WGS84 +datum=WGS84 +units=m +no_defs", id - SRID_NORTH_UTM_START + 1); + } + /* UTM South */ + else if ( id >= SRID_SOUTH_UTM_START && id <= SRID_SOUTH_UTM_END ) + { +- snprintf(proj_str, maxproj4len, "+proj=utm +zone=%d +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs", id - SRID_SOUTH_UTM_START + 1); ++ snprintf(strs.proj4text, maxprojlen, "+proj=utm +zone=%d +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs", id - SRID_SOUTH_UTM_START + 1); + } + /* Lambert zones (about 30x30, larger in higher latitudes) */ + /* There are three latitude zones, divided at -90,-60,-30,0,30,60,90. */ +@@ -434,102 +523,190 @@ static char* GetProj4String(int srid) + else + lwerror("Unknown yzone encountered!"); + +- snprintf(proj_str, maxproj4len, "+proj=laea +ellps=WGS84 +datum=WGS84 +lat_0=%g +lon_0=%g +units=m +no_defs", lat_0, lon_0); ++ snprintf(strs.proj4text, maxprojlen, "+proj=laea +ellps=WGS84 +datum=WGS84 +lat_0=%g +lon_0=%g +units=m +no_defs", lat_0, lon_0); + } + /* Lambert Azimuthal Equal Area South Pole */ + else if ( id == SRID_SOUTH_LAMBERT ) + { +- strncpy(proj_str, "+proj=laea +lat_0=-90 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxproj4len ); ++ strncpy(strs.proj4text, "+proj=laea +lat_0=-90 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxprojlen ); + } + /* Polar Sterographic South */ + else if ( id == SRID_SOUTH_STEREO ) + { +- strncpy(proj_str, "+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxproj4len); ++ strncpy(strs.proj4text, "+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxprojlen); + } + /* Lambert Azimuthal Equal Area North Pole */ + else if ( id == SRID_NORTH_LAMBERT ) + { +- strncpy(proj_str, "+proj=laea +lat_0=90 +lon_0=-40 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxproj4len ); ++ strncpy(strs.proj4text, "+proj=laea +lat_0=90 +lon_0=-40 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxprojlen ); + } + /* Polar Stereographic North */ + else if ( id == SRID_NORTH_STEREO ) + { +- strncpy(proj_str, "+proj=stere +lat_0=90 +lat_ts=71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxproj4len ); ++ strncpy(strs.proj4text, "+proj=stere +lat_0=90 +lat_ts=71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxprojlen ); + } + /* World Mercator */ + else if ( id == SRID_WORLD_MERCATOR ) + { +- strncpy(proj_str, "+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxproj4len ); ++ strncpy(strs.proj4text, "+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs", maxprojlen ); + } + else + { + elog(ERROR, "Invalid reserved SRID (%d)", srid); +- return NULL; ++ return strs; + } + +- POSTGIS_DEBUGF(3, "returning on SRID=%d: %s", srid, proj_str); +- return proj_str; ++ POSTGIS_DEBUGF(3, "returning on SRID=%d: %s", srid, strs.proj4text); ++ return strs; + } + } + +-void AddToPROJ4Cache(Proj4Cache cache, int srid, int other_srid) { +- AddToPROJ4SRSCache((PROJ4PortalCache *)cache, srid, other_srid) ; ++static int ++pjstrs_has_entry(const PjStrs *strs) ++{ ++ if ((strs->proj4text && strlen(strs->proj4text)) || ++ (strs->epsgtext && strlen(strs->epsgtext)) || ++ (strs->srtext && strlen(strs->srtext))) ++ return 1; ++ else ++ return 0; + } + ++static void ++pjstrs_pfree(PjStrs *strs) ++{ ++ if (strs->proj4text) ++ pfree(strs->proj4text); ++ if (strs->epsgtext) ++ pfree(strs->epsgtext); ++ if (strs->srtext) ++ pfree(strs->srtext); ++} ++ ++#if POSTGIS_PROJ_VERSION >= 60 ++static char* ++pgstrs_get_entry(const PjStrs *strs, int n) ++{ ++ switch (n) ++ { ++ case 0: ++ return strs->epsgtext; ++ case 1: ++ return strs->srtext; ++ case 2: ++ return strs->proj4text; ++ default: ++ return NULL; ++ } ++} ++#endif ++ ++/* ++* Utility function for GML reader that still ++* needs proj4text access ++*/ ++char * ++GetProj4String(int srid) ++{ ++ PjStrs strs; ++ char *proj4str; ++ memset(&strs, 0, sizeof(strs)); ++ strs = GetProjStringsSPI(srid); ++ proj4str = pstrdup(strs.proj4text); ++ pjstrs_pfree(&strs); ++ return proj4str; ++} + + /** +- * Add an entry to the local PROJ4 SRS cache. If we need to wrap around then ++ * Add an entry to the local PROJ SRS cache. If we need to wrap around then + * we must make sure the entry we choose to delete does not contain other_srid + * which is the definition for the other half of the transformation. + */ + static void +-AddToPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid, int other_srid) ++AddToPROJSRSCache(PROJPortalCache *PROJCache, int srid_from, int srid_to) + { + MemoryContext PJMemoryContext; +- projPJ projection = NULL; +- char *proj_str = NULL; ++ ++ PjStrs from_strs, to_strs; ++ char *pj_from_str, *pj_to_str; + + /* + ** Turn the SRID number into a proj4 string, by reading from spatial_ref_sys + ** or instantiating a magical value from a negative srid. + */ +- proj_str = GetProj4String(srid); +- if ( ! proj_str ) +- { +- elog(ERROR, "GetProj4String returned NULL for SRID (%d)", srid); +- } ++ from_strs = GetProjStrings(srid_from); ++ if (!pjstrs_has_entry(&from_strs)) ++ elog(ERROR, "got NULL for SRID (%d)", srid_from); ++ to_strs = GetProjStrings(srid_to); ++ if (!pjstrs_has_entry(&to_strs)) ++ elog(ERROR, "got NULL for SRID (%d)", srid_to); ++ ++#if POSTGIS_PROJ_VERSION < 60 ++ PJ* projection = malloc(sizeof(PJ)); ++ pj_from_str = from_strs.proj4text; ++ pj_to_str = to_strs.proj4text; ++ projection->pj_from = lwproj_from_string(pj_from_str); ++ projection->pj_to = lwproj_from_string(pj_to_str); + +- projection = lwproj_from_string(proj_str); +- if ( projection == NULL ) +- { +- char *pj_errstr = pj_strerrno(*pj_get_errno_ref()); +- if ( ! pj_errstr ) +- pj_errstr = ""; ++ if (!projection->pj_from) ++ elog(ERROR, ++ "could not form projection from 'srid=%d' to 'srid=%d'", ++ srid_from, srid_to); + ++ if (!projection->pj_to) ++ elog(ERROR, ++ "could not form projection from 'srid=%d' to 'srid=%d'", ++ srid_from, srid_to); ++#else ++ PJ* projection = NULL; ++ /* Try combinations of ESPG/SRTEXT/PROJ4TEXT until we find */ ++ /* one that gives us a usable transform. Note that we prefer */ ++ /* EPSG numbers over SRTEXT and SRTEXT over PROJ4TEXT */ ++ /* (3 entries * 3 entries = 9 combos) */ ++ uint32_t i; ++ for (i = 0; i < 9; i++) ++ { ++ pj_from_str = pgstrs_get_entry(&from_strs, i / 3); ++ pj_to_str = pgstrs_get_entry(&to_strs, i % 3); ++ if (!(pj_from_str && pj_to_str)) ++ continue; ++ projection = proj_create_crs_to_crs(NULL, pj_from_str, pj_to_str, NULL); ++ if (projection && !proj_errno(projection)) ++ break; ++ } ++ if (!projection) ++ { + elog(ERROR, +- "AddToPROJ4SRSCache: could not parse proj4 string '%s' %s", +- proj_str, pj_errstr); ++ "could not form projection from 'srid=%d' to 'srid=%d'", ++ srid_from, srid_to); + } ++#endif + + /* + * If the cache is already full then find the first entry +- * that doesn't contain other_srid and use this as the +- * subsequent value of PROJ4SRSCacheCount ++ * that doesn't contain our srids and use this as the ++ * subsequent value of PROJSRSCacheCount + */ +- if (PROJ4Cache->PROJ4SRSCacheCount == PROJ4_CACHE_ITEMS) ++ if (PROJCache->PROJSRSCacheCount == PROJ_CACHE_ITEMS) + { + bool found = false; +- int i; +- +- for (i = 0; i < PROJ4_CACHE_ITEMS; i++) ++ uint32_t i; ++ for (i = 0; i < PROJ_CACHE_ITEMS; i++) + { +- if (PROJ4Cache->PROJ4SRSCache[i].srid != other_srid && found == false) ++ if (found == false && ++ (PROJCache->PROJSRSCache[i].srid_from != srid_from || ++ PROJCache->PROJSRSCache[i].srid_to != srid_to)) + { +- POSTGIS_DEBUGF(3, "choosing to remove item from query cache with SRID %d and index %d", PROJ4Cache->PROJ4SRSCache[i].srid, i); +- +- DeleteFromPROJ4SRSCache(PROJ4Cache, PROJ4Cache->PROJ4SRSCache[i].srid); +- PROJ4Cache->PROJ4SRSCacheCount = i; ++ POSTGIS_DEBUGF(3, "choosing to remove item from query cache with SRIDs %d => %d and index %d", ++ PROJCache->PROJSRSCache[i].srid_from, ++ PROJCache->PROJSRSCache[i].srid_to, ++ i); ++ ++ DeleteFromPROJSRSCache(PROJCache, ++ PROJCache->PROJSRSCache[i].srid_from, ++ PROJCache->PROJSRSCache[i].srid_to); + ++ PROJCache->PROJSRSCacheCount = i; + found = true; + } + } +@@ -539,16 +716,21 @@ AddToPROJ4SRSCache(PROJ4PortalCache *PRO + * Now create a memory context for this projection and + * store it in the backend hash + */ +- POSTGIS_DEBUGF(3, "adding SRID %d with proj4text \"%s\" to query cache at index %d", srid, proj_str, PROJ4Cache->PROJ4SRSCacheCount); ++ POSTGIS_DEBUGF(3, "adding transform %d => %d aka \"%s\" => \"%s\" to query cache at index %d", ++ srid_from, srid_to, pj_from_str, pj_to_str, PROJCache->PROJSRSCacheCount); ++ ++ /* Free the projection strings */ ++ pjstrs_pfree(&from_strs); ++ pjstrs_pfree(&to_strs); + + #if POSTGIS_PGSQL_VERSION < 96 + PJMemoryContext = MemoryContextCreate(T_AllocSetContext, 8192, +- &PROJ4SRSCacheContextMethods, +- PROJ4Cache->PROJ4SRSCacheContext, +- "PostGIS PROJ4 PJ Memory Context"); ++ &PROJSRSCacheContextMethods, ++ PROJCache->PROJSRSCacheContext, ++ "PostGIS PROJ PJ Memory Context"); + #else +- PJMemoryContext = AllocSetContextCreate(PROJ4Cache->PROJ4SRSCacheContext, +- "PostGIS PROJ4 PJ Memory Context", ++ PJMemoryContext = AllocSetContextCreate(PROJCache->PROJSRSCacheContext, ++ "PostGIS PROJ PJ Memory Context", + ALLOCSET_SMALL_SIZES); + + /* PgSQL comments suggest allocating callback in the context */ +@@ -557,7 +739,7 @@ AddToPROJ4SRSCache(PROJ4PortalCache *PRO + { + MemoryContextCallback *callback = MemoryContextAlloc(PJMemoryContext, sizeof(MemoryContextCallback)); + callback->arg = (void*)PJMemoryContext; +- callback->func = PROJ4SRSCacheDelete; ++ callback->func = PROJSRSCacheDelete; + MemoryContextRegisterResetCallback(PJMemoryContext, callback); + } + #endif +@@ -574,43 +756,37 @@ AddToPROJ4SRSCache(PROJ4PortalCache *PRO + + AddPJHashEntry(PJMemoryContext, projection); + +- PROJ4Cache->PROJ4SRSCache[PROJ4Cache->PROJ4SRSCacheCount].srid = srid; +- PROJ4Cache->PROJ4SRSCache[PROJ4Cache->PROJ4SRSCacheCount].projection = projection; +- PROJ4Cache->PROJ4SRSCache[PROJ4Cache->PROJ4SRSCacheCount].projection_mcxt = PJMemoryContext; +- PROJ4Cache->PROJ4SRSCacheCount++; +- +- /* Free the projection string */ +- pfree(proj_str); +- +-} +- +-void DeleteFromPROJ4Cache(Proj4Cache cache, int srid) { +- DeleteFromPROJ4SRSCache((PROJ4PortalCache *)cache, srid) ; ++ PROJCache->PROJSRSCache[PROJCache->PROJSRSCacheCount].srid_from = srid_from; ++ PROJCache->PROJSRSCache[PROJCache->PROJSRSCacheCount].srid_to = srid_to; ++ PROJCache->PROJSRSCache[PROJCache->PROJSRSCacheCount].projection = projection; ++ PROJCache->PROJSRSCache[PROJCache->PROJSRSCacheCount].projection_mcxt = PJMemoryContext; ++ PROJCache->PROJSRSCacheCount++; + } + + +-static void DeleteFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid) ++static void ++DeleteFromPROJSRSCache(PROJPortalCache *PROJCache, int srid_from, int srid_to) + { + /* + * Delete the SRID entry from the cache + */ +- +- int i; +- +- for (i = 0; i < PROJ4_CACHE_ITEMS; i++) ++ uint32_t i; ++ for (i = 0; i < PROJ_CACHE_ITEMS; i++) + { +- if (PROJ4Cache->PROJ4SRSCache[i].srid == srid) ++ if (PROJCache->PROJSRSCache[i].srid_from == srid_from && ++ PROJCache->PROJSRSCache[i].srid_to == srid_to) + { +- POSTGIS_DEBUGF(3, "removing query cache entry with SRID %d at index %d", srid, i); ++ POSTGIS_DEBUGF(3, "removing query cache entry with SRIDs %d => %d at index %d", srid_from, srid_to, i); + + /* +- * Zero out the entries and free the PROJ4 handle ++ * Zero out the entries and free the PROJ handle + * by deleting the memory context + */ +- MemoryContextDelete(PROJ4Cache->PROJ4SRSCache[i].projection_mcxt); +- PROJ4Cache->PROJ4SRSCache[i].projection = NULL; +- PROJ4Cache->PROJ4SRSCache[i].projection_mcxt = NULL; +- PROJ4Cache->PROJ4SRSCache[i].srid = SRID_UNKNOWN; ++ MemoryContextDelete(PROJCache->PROJSRSCache[i].projection_mcxt); ++ PROJCache->PROJSRSCache[i].projection = NULL; ++ PROJCache->PROJSRSCache[i].projection_mcxt = NULL; ++ PROJCache->PROJSRSCache[i].srid_from = SRID_UNKNOWN; ++ PROJCache->PROJSRSCache[i].srid_to = SRID_UNKNOWN; + } + } + } +@@ -628,13 +804,13 @@ static void DeleteFromPROJ4SRSCache(PROJ + * since the method of determining the current installation + * path are different on older PostgreSQL versions. + */ +-void SetPROJ4LibPath(void) ++void SetPROJLibPath(void) + { + char *path; + char *share_path; + const char **proj_lib_path; + +- if (!IsPROJ4LibPathSet) { ++ if (!IsPROJLibPathSet) { + + /* + * Get the sharepath and append /contrib/postgis/proj to form a suitable +@@ -649,91 +825,74 @@ void SetPROJ4LibPath(void) + *proj_lib_path = path; + + snprintf(path, MAXPGPATH - 1, "%s/contrib/postgis-%s.%s/proj", share_path, POSTGIS_MAJOR_VERSION, POSTGIS_MINOR_VERSION); +- ++#if POSTGIS_PROJ_VERSION < 60 + /* Set the search path for PROJ.4 */ + pj_set_searchpath(1, proj_lib_path); +- ++#else ++ /* Set the search path for PROJ */ ++ proj_context_set_search_paths(NULL, 1, proj_lib_path); ++#endif + /* Ensure we only do this once... */ +- IsPROJ4LibPathSet = true; ++ IsPROJLibPathSet = true; + } + } + +-Proj4Cache GetPROJ4Cache(FunctionCallInfo fcinfo) { +- return (Proj4Cache)GetPROJ4SRSCache(fcinfo); +-} + + int +-GetProjectionsUsingFCInfo(FunctionCallInfo fcinfo, int srid1, int srid2, projPJ *pj1, projPJ *pj2) ++GetPJUsingFCInfo(FunctionCallInfo fcinfo, int srid_from, int srid_to, PJ** pj) + { +- Proj4Cache *proj_cache = NULL; ++ PROJPortalCache *proj_cache = NULL; + + /* Set the search path if we haven't already */ +- SetPROJ4LibPath(); ++ SetPROJLibPath(); + + /* Look up the spatial_ref_sys schema if we haven't already */ +- postgis_initialize_cache(fcinfo); ++ SetSpatialRefSysSchema(fcinfo); + + /* get or initialize the cache for this round */ +- proj_cache = GetPROJ4Cache(fcinfo); +- if ( !proj_cache ) ++ proj_cache = GetPROJSRSCache(fcinfo); ++ if (!proj_cache) + return LW_FAILURE; + + /* Add the output srid to the cache if it's not already there */ +- if (!IsInPROJ4Cache(proj_cache, srid1)) +- AddToPROJ4Cache(proj_cache, srid1, srid2); +- +- /* Add the input srid to the cache if it's not already there */ +- if (!IsInPROJ4Cache(proj_cache, srid2)) +- AddToPROJ4Cache(proj_cache, srid2, srid1); ++ if (!IsInPROJSRSCache(proj_cache, srid_from, srid_to)) ++ AddToPROJSRSCache(proj_cache, srid_from, srid_to); + + /* Get the projections */ +- *pj1 = GetProjectionFromPROJ4Cache(proj_cache, srid1); +- *pj2 = GetProjectionFromPROJ4Cache(proj_cache, srid2); ++ *pj = GetProjectionFromPROJCache(proj_cache, srid_from, srid_to); + + return LW_SUCCESS; + } + +-int +-spheroid_init_from_srid(FunctionCallInfo fcinfo, int srid, SPHEROID *s) +-{ +- projPJ pj1, pj2; +-#if POSTGIS_PROJ_VERSION >= 48 +- double major_axis, minor_axis, eccentricity_squared; +-#endif +- +- if ( GetProjectionsUsingFCInfo(fcinfo, srid, srid, &pj1, &pj2) == LW_FAILURE) +- return LW_FAILURE; + +- if ( ! pj_is_latlong(pj1) ) +- return LW_FAILURE; +- +-#if POSTGIS_PROJ_VERSION >= 48 +- /* For newer versions of Proj we can pull the spheroid paramaeters and initialize */ +- /* using them */ +- pj_get_spheroid_defn(pj1, &major_axis, &eccentricity_squared); +- minor_axis = major_axis * sqrt(1-eccentricity_squared); +- spheroid_init(s, major_axis, minor_axis); ++static int ++proj_pj_is_latlong(const PJ* pj) ++{ ++#if POSTGIS_PROJ_VERSION < 60 ++ return pj_is_latlong(pj->pj_from); + #else +- /* For old versions of Proj we cannot lookup the spheroid parameters from the API */ +- /* So we use the WGS84 parameters (boo!) */ +- spheroid_init(s, WGS84_MAJOR_AXIS, WGS84_MINOR_AXIS); ++ PJ_TYPE pj_type = proj_get_type(proj_get_source_crs(NULL, pj)); ++ return (pj_type == PJ_TYPE_GEOGRAPHIC_2D_CRS) || ++ (pj_type == PJ_TYPE_GEOGRAPHIC_3D_CRS); + #endif +- +- return LW_SUCCESS; + } + +-void srid_is_latlong(FunctionCallInfo fcinfo, int srid) ++static int ++srid_is_latlong(FunctionCallInfo fcinfo, int srid) + { +- projPJ pj1; +- projPJ pj2; +- +- if ( srid == SRID_DEFAULT || srid == SRID_UNKNOWN ) +- return; ++ PJ* pj; ++ if ( GetPJUsingFCInfo(fcinfo, srid, srid, &pj) == LW_FAILURE) ++ return LW_FALSE; ++ return proj_pj_is_latlong(pj); ++} + +- if ( GetProjectionsUsingFCInfo(fcinfo, srid, srid, &pj1, &pj2) == LW_FAILURE) ++void ++srid_check_latlong(FunctionCallInfo fcinfo, int srid) ++{ ++ if (srid == SRID_DEFAULT || srid == SRID_UNKNOWN) + return; + +- if ( pj_is_latlong(pj1) ) ++ if (srid_is_latlong(fcinfo, srid)) + return; + + ereport(ERROR, ( +@@ -741,14 +900,10 @@ void srid_is_latlong(FunctionCallInfo fc + errmsg("Only lon/lat coordinate systems are supported in geography."))); + } + +- +-srs_precision srid_axis_precision(FunctionCallInfo fcinfo, int srid, int precision) ++srs_precision ++srid_axis_precision(FunctionCallInfo fcinfo, int srid, int precision) + { +- projPJ pj1; +- projPJ pj2; +- + srs_precision sp; +- + sp.precision_xy = precision; + sp.precision_z = precision; + sp.precision_m = precision; +@@ -756,10 +911,7 @@ srs_precision srid_axis_precision(Functi + if ( srid == SRID_UNKNOWN ) + return sp; + +- if ( GetProjectionsUsingFCInfo(fcinfo, srid, srid, &pj1, &pj2) == LW_FAILURE) +- return sp; +- +- if ( pj_is_latlong(pj1) ) ++ if ( srid_is_latlong(fcinfo, srid) ) + { + sp.precision_xy += 5; + return sp; +@@ -767,3 +919,59 @@ srs_precision srid_axis_precision(Functi + + return sp; + } ++ ++int ++spheroid_init_from_srid(FunctionCallInfo fcinfo, int srid, SPHEROID *s) ++{ ++ PJ* pj; ++#if POSTGIS_PROJ_VERSION >= 60 ++ double out_semi_major_metre, out_semi_minor_metre, out_inv_flattening; ++ int out_is_semi_minor_computed; ++ PJ *pj_ellps, *pj_crs; ++#elif POSTGIS_PROJ_VERSION >= 48 ++ double major_axis, minor_axis, eccentricity_squared; ++#endif ++ ++ if ( GetPJUsingFCInfo(fcinfo, srid, srid, &pj) == LW_FAILURE) ++ return LW_FAILURE; ++ ++#if POSTGIS_PROJ_VERSION >= 60 ++ if (!proj_pj_is_latlong(pj)) ++ return LW_FAILURE; ++ pj_crs = proj_get_source_crs(NULL, pj); ++ if (!pj_crs) ++ { ++ lwerror("%s: proj_get_source_crs returned NULL", __func__); ++ } ++ pj_ellps = proj_get_ellipsoid(NULL, pj_crs); ++ if (!pj_ellps) ++ { ++ proj_destroy(pj_crs); ++ lwerror("%s: proj_get_ellipsoid returned NULL", __func__); ++ } ++ proj_ellipsoid_get_parameters(NULL, pj_ellps, ++ &out_semi_major_metre, &out_semi_minor_metre, ++ &out_is_semi_minor_computed, &out_inv_flattening); ++ proj_destroy(pj_ellps); ++ proj_destroy(pj_crs); ++ spheroid_init(s, out_semi_major_metre, out_semi_minor_metre); ++ ++#elif POSTGIS_PROJ_VERSION >= 48 ++ if (!pj_is_latlong(pj->pj_from)) ++ return LW_FAILURE; ++ /* For newer versions of Proj we can pull the spheroid paramaeters and initialize */ ++ /* using them */ ++ pj_get_spheroid_defn(pj->pj_from, &major_axis, &eccentricity_squared); ++ minor_axis = major_axis * sqrt(1-eccentricity_squared); ++ spheroid_init(s, major_axis, minor_axis); ++ ++#else ++ if (!pj_is_latlong(pj->pj_from)) ++ return LW_FAILURE; ++ /* For old versions of Proj we cannot lookup the spheroid parameters from the API */ ++ /* So we use the WGS84 parameters (boo!) */ ++ spheroid_init(s, WGS84_MAJOR_AXIS, WGS84_MINOR_AXIS); ++#endif ++ ++ return LW_SUCCESS; ++} +diff -rupN postgis-2.5.5/libpgcommon/lwgeom_transform.h postgis-2.5.5-new/libpgcommon/lwgeom_transform.h +--- postgis-2.5.5/libpgcommon/lwgeom_transform.h 2020-08-15 20:43:43.000000000 +0200 ++++ postgis-2.5.5-new/libpgcommon/lwgeom_transform.h 2022-08-06 11:48:23.739708197 +0200 +@@ -10,9 +10,10 @@ + **********************************************************************/ + + #include "postgres.h" +-#include "liblwgeom.h" ++#include "liblwgeom_internal.h" + #include "lwgeom_pg.h" + ++ + typedef struct srs_precision + { + int precision_xy; +@@ -20,23 +21,19 @@ typedef struct srs_precision + int precision_m; + } srs_precision; + +-char* GetProj4StringSPI(int srid); +-void SetPROJ4LibPath(void) ; ++char * GetProj4String(int srid); + + /** + * Opaque type to use in the projection cache API. + */ +-typedef void *Proj4Cache ; ++typedef void *ProjCache ; + +-void SetPROJ4LibPath(void); +-Proj4Cache GetPROJ4Cache(FunctionCallInfo fcinfo) ; +-bool IsInPROJ4Cache(Proj4Cache cache, int srid) ; +-void AddToPROJ4Cache(Proj4Cache cache, int srid, int other_srid); +-void DeleteFromPROJ4Cache(Proj4Cache cache, int srid) ; +-projPJ GetProjectionFromPROJ4Cache(Proj4Cache cache, int srid); +-int GetProjectionsUsingFCInfo(FunctionCallInfo fcinfo, int srid1, int srid2, projPJ *pj1, projPJ *pj2); ++void SetPROJLibPath(void); ++bool IsInPROJCache(ProjCache cache, int srid_from, int srid_to); ++PJ* GetPJFromPROJCache(ProjCache cache, int srid_from, int srid_to); ++int GetPJUsingFCInfo(FunctionCallInfo fcinfo, int srid_from, int srid_to, PJ** pj); + int spheroid_init_from_srid(FunctionCallInfo fcinfo, int srid, SPHEROID *s); +-void srid_is_latlong(FunctionCallInfo fcinfo, int srid); ++void srid_check_latlong(FunctionCallInfo fcinfo, int srid); + srs_precision srid_axis_precision(FunctionCallInfo fcinfo, int srid, int precision); + + /** +diff -rupN postgis-2.5.5/macros/ac_proj4_version.m4 postgis-2.5.5-new/macros/ac_proj4_version.m4 +--- postgis-2.5.5/macros/ac_proj4_version.m4 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/macros/ac_proj4_version.m4 2022-08-06 11:48:23.740708197 +0200 +@@ -14,29 +14,53 @@ dnl Return the PROJ.4 version number + dnl + + AC_DEFUN([AC_PROJ_VERSION], [ +- AC_RUN_IFELSE( +- [AC_LANG_PROGRAM([ +- #ifdef HAVE_STDINT_H +- #include +- #endif +- #define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 1 +- #include "proj_api.h" +- ], +- [ +- FILE *fp; + +- fp = fopen("conftest.out", "w"); +- fprintf(fp, "%d\n", PJ_VERSION); +- fclose(fp)]) +- ], +- [ +- dnl The program ran successfully, so return the version number in the form MAJORMINOR +- $1=`cat conftest.out | sed 's/\([[0-9]]\)\([[0-9]]\)\([[0-9]]\)/\1\2/'` +- ], +- [ +- dnl The program failed so return an empty variable +- $1="" +- ] +- ) ++ AC_CHECK_HEADER([proj.h], [ ++ dnl Proj >= 6 include and version string ++ AC_RUN_IFELSE([ ++ AC_LANG_PROGRAM([ ++ #ifdef HAVE_STDINT_H ++ #include ++ #endif ++ #include "proj.h" ++ ],[ ++ FILE *fp; ++ int vernum; ++ ++ fp = fopen("conftest.out", "w"); ++ vernum = (100 * PROJ_VERSION_MAJOR) + (10 * PROJ_VERSION_MINOR) + PROJ_VERSION_PATCH; ++ fprintf(fp, "%d\n", vernum); ++ fclose(fp); ++ ]) ++ ],[ ++ dnl The program ran successfully, so return the version number in the form MAJORMINOR ++ $1=`cat conftest.out | sed 's/\([[0-9]]\)\([[0-9]]\)\([[0-9]]\)/\1\2/'` ++ ],[ ++ dnl The program failed so return an empty variable ++ $1="" ++ ]) ++ ],[ ++ dnl Proj < 6 include and version string ++ AC_RUN_IFELSE( ++ [AC_LANG_PROGRAM([ ++ #ifdef HAVE_STDINT_H ++ #include ++ #endif ++ #include "proj_api.h" ++ ],[ ++ FILE *fp; ++ ++ fp = fopen("conftest.out", "w"); ++ fprintf(fp, "%d\n", PJ_VERSION); ++ fclose(fp); ++ ]) ++ ],[ ++ dnl The program ran successfully, so return the version number in the form MAJORMINOR ++ $1=`cat conftest.out | sed 's/\([[0-9]]\)\([[0-9]]\)\([[0-9]]\)/\1\2/'` ++ ],[ ++ dnl The program failed so return an empty variable ++ $1="" ++ ]) ++ ]) + ]) + +diff -rupN postgis-2.5.5/postgis/geography_inout.c postgis-2.5.5-new/postgis/geography_inout.c +--- postgis-2.5.5/postgis/geography_inout.c 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/postgis/geography_inout.c 2022-08-06 11:48:23.740708197 +0200 +@@ -172,7 +172,7 @@ Datum geography_in(PG_FUNCTION_ARGS) + } + + /* Error on any SRID != default */ +- srid_is_latlong(fcinfo, lwgeom->srid); ++ srid_check_latlong(fcinfo, lwgeom->srid); + + /* Convert to gserialized */ + g_ser = gserialized_geography_from_lwgeom(lwgeom, geog_typmod); +@@ -568,7 +568,7 @@ Datum geography_from_text(PG_FUNCTION_AR + PG_PARSER_ERROR(lwg_parser_result); + + /* Error on any SRID != default */ +- srid_is_latlong(fcinfo, lwg_parser_result.geom->srid); ++ srid_check_latlong(fcinfo, lwg_parser_result.geom->srid); + + /* Clean up string */ + pfree(wkt); +@@ -596,7 +596,7 @@ Datum geography_from_binary(PG_FUNCTION_ + lwpgerror("Unable to parse WKB"); + + /* Error on any SRID != default */ +- srid_is_latlong(fcinfo, lwgeom->srid); ++ srid_check_latlong(fcinfo, lwgeom->srid); + + gser = gserialized_geography_from_lwgeom(lwgeom, -1); + lwgeom_free(lwgeom); +@@ -622,7 +622,7 @@ Datum geography_from_geometry(PG_FUNCTIO + } + + /* Error on any SRID != default */ +- srid_is_latlong(fcinfo, lwgeom->srid); ++ srid_check_latlong(fcinfo, lwgeom->srid); + + /* Force the geometry to have valid geodetic coordinate range. */ + lwgeom_nudge_geodetic(lwgeom); +@@ -686,7 +686,7 @@ Datum geography_recv(PG_FUNCTION_ARGS) + lwgeom = lwgeom_from_wkb((uint8_t*)buf->data, buf->len, LW_PARSER_CHECK_ALL); + + /* Error on any SRID != default */ +- srid_is_latlong(fcinfo, lwgeom->srid); ++ srid_check_latlong(fcinfo, lwgeom->srid); + + g_ser = gserialized_geography_from_lwgeom(lwgeom, geog_typmod); + +diff -rupN postgis-2.5.5/postgis/geography_measurement.c postgis-2.5.5-new/postgis/geography_measurement.c +--- postgis-2.5.5/postgis/geography_measurement.c 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/postgis/geography_measurement.c 2022-08-06 11:48:23.741708197 +0200 +@@ -40,7 +40,7 @@ + #include "geography_measurement_trees.h" /* For circ_tree caching */ + #include "lwgeom_transform.h" /* For SRID functions */ + +-#if PROJ_GEODESIC ++#ifdef PROJ_GEODESIC + /* round to 10 nm precision */ + #define INVMINDIST 1.0e8 + #else +@@ -532,7 +532,7 @@ Datum geography_area(PG_FUNCTION_ARGS) + else + lwgeom_calculate_gbox_geodetic(lwgeom, &gbox); + +-#if ! PROJ_GEODESIC ++#ifndef PROJ_GEODESIC + /* Test for cases that are currently not handled by spheroid code */ + if ( use_spheroid ) + { +@@ -543,7 +543,7 @@ Datum geography_area(PG_FUNCTION_ARGS) + if ( gbox.zmax > 0.0 && gbox.zmin < 0.0 ) + use_spheroid = LW_FALSE; + } +-#endif /* if ! PROJ_GEODESIC */ ++#endif /* ifndef PROJ_GEODESIC */ + + /* User requests spherical calculation, turn our spheroid into a sphere */ + if ( ! use_spheroid ) +diff -rupN postgis-2.5.5/postgis/gserialized_gist_2d.c postgis-2.5.5-new/postgis/gserialized_gist_2d.c +--- postgis-2.5.5/postgis/gserialized_gist_2d.c 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/postgis/gserialized_gist_2d.c 2022-08-06 11:48:23.742708197 +0200 +@@ -60,6 +60,7 @@ + #endif + + #include /* For FLT_MAX */ ++#include + + /* + ** When is a node split not so good? If more than 90% of the entries +diff -rupN postgis-2.5.5/postgis/gserialized_gist_nd.c postgis-2.5.5-new/postgis/gserialized_gist_nd.c +--- postgis-2.5.5/postgis/gserialized_gist_nd.c 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/postgis/gserialized_gist_nd.c 2022-08-06 11:48:23.743708197 +0200 +@@ -52,6 +52,7 @@ + #include "geography.h" + + #include ++#include + + + /* Fall back to older finite() if necessary */ +diff -rupN postgis-2.5.5/postgis/gserialized_spgist_2d.c postgis-2.5.5-new/postgis/gserialized_spgist_2d.c +--- postgis-2.5.5/postgis/gserialized_spgist_2d.c 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/postgis/gserialized_spgist_2d.c 2022-08-06 11:48:23.744708197 +0200 +@@ -81,6 +81,7 @@ + #include "lwgeom_pg.h" /* For debugging macros. */ + #include /* For utility functions. */ + #include /* For debugging macros. */ ++#include + + /* + ** SP-GiST 2D index function prototypes +diff -rupN postgis-2.5.5/postgis/gserialized_typmod.c postgis-2.5.5-new/postgis/gserialized_typmod.c +--- postgis-2.5.5/postgis/gserialized_typmod.c 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/postgis/gserialized_typmod.c 2022-08-06 11:48:23.744708197 +0200 +@@ -295,7 +295,7 @@ Datum geography_typmod_in(PG_FUNCTION_AR + int32 typmod = gserialized_typmod_in(arr, LW_TRUE); + int srid = TYPMOD_GET_SRID(typmod); + /* Check the SRID is legal (geographic coordinates) */ +- srid_is_latlong(fcinfo, srid); ++ srid_check_latlong(fcinfo, srid); + + PG_RETURN_INT32(typmod); + } +diff -rupN postgis-2.5.5/postgis/lwgeom_in_gml.c postgis-2.5.5-new/postgis/lwgeom_in_gml.c +--- postgis-2.5.5/postgis/lwgeom_in_gml.c 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/postgis/lwgeom_in_gml.c 2022-08-06 11:48:23.745708197 +0200 +@@ -297,36 +297,68 @@ static xmlNodePtr get_xlink_node(xmlNode + } + + ++ + /** +- * Use Proj4 to reproject a given POINTARRAY ++ * Use Proj to reproject a given POINTARRAY + */ ++ ++#if POSTGIS_PROJ_VERSION < 60 ++ + static POINTARRAY* gml_reproject_pa(POINTARRAY *pa, int srid_in, int srid_out) + { +- projPJ in_pj, out_pj; ++ PJ pj; + char *text_in, *text_out; + + if (srid_in == SRID_UNKNOWN) return pa; /* nothing to do */ + if (srid_out == SRID_UNKNOWN) gml_lwpgerror("invalid GML representation", 3); + +- text_in = GetProj4StringSPI(srid_in); +- text_out = GetProj4StringSPI(srid_out); ++ text_in = GetProj4String(srid_in); ++ text_out = GetProj4String(srid_out); + +- in_pj = lwproj_from_string(text_in); +- out_pj = lwproj_from_string(text_out); ++ pj.pj_from = lwproj_from_string(text_in); ++ pj.pj_to = lwproj_from_string(text_out); + + lwfree(text_in); + lwfree(text_out); + +- if ( ptarray_transform(pa, in_pj, out_pj) == LW_FAILURE ) ++ if ( ptarray_transform(pa, &pj) == LW_FAILURE ) + { + elog(ERROR, "gml_reproject_pa: reprojection failed"); + } + +- pj_free(in_pj); +- pj_free(out_pj); ++ pj_free(pj.pj_from); ++ pj_free(pj.pj_to); ++ ++ return pa; ++} ++#else ++/* ++ * TODO: rework GML projection handling to skip the spatial_ref_sys ++ * lookups, and use the Proj 6+ EPSG catalogue and built-in SRID ++ * lookups directly. Drop this ugly hack. ++ */ ++static POINTARRAY* gml_reproject_pa(POINTARRAY *pa, int srid_in, int srid_out) ++{ ++ PJ *pj; ++ char text_in[32]; ++ char text_out[32]; ++ ++ if (srid_in == SRID_UNKNOWN) return pa; /* nothing to do */ ++ if (srid_out == SRID_UNKNOWN) gml_lwpgerror("invalid GML representation", 3); ++ ++ snprintf(text_in, 32, "EPSG:%d", srid_in); ++ snprintf(text_out, 32, "EPSG:%d", srid_out); ++ pj = proj_create_crs_to_crs(NULL, text_in, text_out, NULL); ++ ++ if (ptarray_transform(pa, pj) == LW_FAILURE) ++ { ++ elog(ERROR, "gml_reproject_pa: reprojection failed"); ++ } ++ proj_destroy(pj); + + return pa; + } ++#endif /* POSTGIS_PROJ_VERSION */ + + + /** +diff -rupN postgis-2.5.5/postgis/lwgeom_spheroid.c postgis-2.5.5-new/postgis/lwgeom_spheroid.c +--- postgis-2.5.5/postgis/lwgeom_spheroid.c 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/postgis/lwgeom_spheroid.c 2022-08-06 11:48:23.745708197 +0200 +@@ -440,7 +440,7 @@ Datum LWGEOM_length_ellipsoid_linestring + * (if deltaX is 1 degrees, then that distance represents 1/360 of a circle of radius S.) + * + * +- * Parts taken from PROJ4 - geodetic_to_geocentric() (for calculating Rn) ++ * Parts taken from PROJ - geodetic_to_geocentric() (for calculating Rn) + * + * remember that lat1/long1/lat2/long2 are comming in a *RADIANS* not degrees. + * +diff -rupN postgis-2.5.5/postgis/lwgeom_transform.c postgis-2.5.5-new/postgis/lwgeom_transform.c +--- postgis-2.5.5/postgis/lwgeom_transform.c 2020-08-15 20:43:44.000000000 +0200 ++++ postgis-2.5.5-new/postgis/lwgeom_transform.c 2022-08-06 11:48:23.746708197 +0200 +@@ -47,23 +47,23 @@ Datum postgis_proj_version(PG_FUNCTION_A + PG_FUNCTION_INFO_V1(transform); + Datum transform(PG_FUNCTION_ARGS) + { +- GSERIALIZED *geom; +- GSERIALIZED *result=NULL; +- LWGEOM *lwgeom; +- projPJ input_pj, output_pj; +- int32 output_srid, input_srid; ++ GSERIALIZED* geom; ++ GSERIALIZED* result=NULL; ++ LWGEOM* lwgeom; ++ PJ* pj; ++ int32 srid_to, srid_from; + +- output_srid = PG_GETARG_INT32(1); +- if (output_srid == SRID_UNKNOWN) ++ srid_to = PG_GETARG_INT32(1); ++ if (srid_to == SRID_UNKNOWN) + { + elog(ERROR, "%d is an invalid target SRID", SRID_UNKNOWN); + PG_RETURN_NULL(); + } + + geom = PG_GETARG_GSERIALIZED_P_COPY(0); +- input_srid = gserialized_get_srid(geom); ++ srid_from = gserialized_get_srid(geom); + +- if ( input_srid == SRID_UNKNOWN ) ++ if ( srid_from == SRID_UNKNOWN ) + { + PG_FREE_IF_COPY(geom, 0); + elog(ERROR, "Input geometry has unknown (%d) SRID", SRID_UNKNOWN); +@@ -71,10 +71,10 @@ Datum transform(PG_FUNCTION_ARGS) + } + + /* Input SRID and output SRID are equal, noop */ +- if ( input_srid == output_srid ) ++ if ( srid_from == srid_to ) + PG_RETURN_POINTER(geom); + +- if ( GetProjectionsUsingFCInfo(fcinfo, input_srid, output_srid, &input_pj, &output_pj) == LW_FAILURE ) ++ if ( GetPJUsingFCInfo(fcinfo, srid_from, srid_to, &pj) == LW_FAILURE ) + { + PG_FREE_IF_COPY(geom, 0); + elog(ERROR, "Failure reading projections from spatial_ref_sys."); +@@ -83,8 +83,8 @@ Datum transform(PG_FUNCTION_ARGS) + + /* now we have a geometry, and input/output PJ structs. */ + lwgeom = lwgeom_from_gserialized(geom); +- lwgeom_transform(lwgeom, input_pj, output_pj); +- lwgeom->srid = output_srid; ++ lwgeom_transform(lwgeom, pj); ++ lwgeom->srid = srid_to; + + /* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */ + if ( lwgeom->bbox ) +@@ -110,96 +110,57 @@ Datum transform(PG_FUNCTION_ARGS) + PG_FUNCTION_INFO_V1(transform_geom); + Datum transform_geom(PG_FUNCTION_ARGS) + { +- GSERIALIZED *geom; +- GSERIALIZED *result=NULL; +- LWGEOM *lwgeom; +- projPJ input_pj, output_pj; +- char *input_proj4, *output_proj4; +- text *input_proj4_text; +- text *output_proj4_text; +- int32 result_srid ; +- char *pj_errstr; ++ GSERIALIZED *gser, *gser_result=NULL; ++ LWGEOM *geom; ++ char *input_srs, *output_srs; ++ int32 result_srid; ++ int rv; + +- result_srid = PG_GETARG_INT32(3); +- geom = PG_GETARG_GSERIALIZED_P_COPY(0); ++ /* Take a copy, since we will be altering the coordinates */ ++ gser = PG_GETARG_GSERIALIZED_P_COPY(0); + + /* Set the search path if we haven't already */ +- SetPROJ4LibPath(); +- +- /* Read the arguments */ +- input_proj4_text = (PG_GETARG_TEXT_P(1)); +- output_proj4_text = (PG_GETARG_TEXT_P(2)); ++ SetPROJLibPath(); + + /* Convert from text to cstring for libproj */ +- input_proj4 = text_to_cstring(input_proj4_text); +- output_proj4 = text_to_cstring(output_proj4_text); +- +- /* make input and output projection objects */ +- input_pj = lwproj_from_string(input_proj4); +- if ( input_pj == NULL ) +- { +- pj_errstr = pj_strerrno(*pj_get_errno_ref()); +- if ( ! pj_errstr ) pj_errstr = ""; +- +- /* we need this for error reporting */ +- /* pfree(input_proj4); */ +- pfree(output_proj4); +- pfree(geom); +- +- elog(ERROR, +- "transform_geom: could not parse proj4 string '%s' %s", +- input_proj4, pj_errstr); +- PG_RETURN_NULL(); +- } +- pfree(input_proj4); ++ input_srs = text_to_cstring(PG_GETARG_TEXT_P(1)); ++ output_srs = text_to_cstring(PG_GETARG_TEXT_P(2)); ++ result_srid = PG_GETARG_INT32(3); + +- output_pj = lwproj_from_string(output_proj4); ++ /* now we have a geometry, and input/output PJ structs. */ ++ geom = lwgeom_from_gserialized(gser); ++ rv = lwgeom_transform_from_str(geom, input_srs, output_srs); ++ pfree(input_srs); ++ pfree(output_srs); + +- if ( output_pj == NULL ) ++ if (rv == LW_FAILURE) + { +- pj_errstr = pj_strerrno(*pj_get_errno_ref()); +- if ( ! pj_errstr ) pj_errstr = ""; +- +- /* we need this for error reporting */ +- /* pfree(output_proj4); */ +- pj_free(input_pj); +- pfree(geom); +- +- elog(ERROR, +- "transform_geom: couldn't parse proj4 output string: '%s': %s", +- output_proj4, pj_errstr); ++ elog(ERROR, "coordinate transformation failed"); + PG_RETURN_NULL(); + } +- pfree(output_proj4); +- +- /* now we have a geometry, and input/output PJ structs. */ +- lwgeom = lwgeom_from_gserialized(geom); +- lwgeom_transform(lwgeom, input_pj, output_pj); +- lwgeom->srid = result_srid; +- +- /* clean up */ +- pj_free(input_pj); +- pj_free(output_pj); + + /* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */ +- if ( lwgeom->bbox ) +- { +- lwgeom_refresh_bbox(lwgeom); +- } ++ geom->srid = result_srid; ++ if (geom->bbox) ++ lwgeom_refresh_bbox(geom); ++ ++ gser_result = geometry_serialize(geom); ++ lwgeom_free(geom); ++ PG_FREE_IF_COPY(gser, 0); + +- result = geometry_serialize(lwgeom); +- +- lwgeom_free(lwgeom); +- PG_FREE_IF_COPY(geom, 0); +- +- PG_RETURN_POINTER(result); /* new geometry */ ++ PG_RETURN_POINTER(gser_result); /* new geometry */ + } + + + PG_FUNCTION_INFO_V1(postgis_proj_version); + Datum postgis_proj_version(PG_FUNCTION_ARGS) + { ++#if POSTGIS_PROJ_VERSION < 60 + const char *ver = pj_get_release(); + text *result = cstring_to_text(ver); ++#else ++ PJ_INFO pji = proj_info(); ++ text *result = cstring_to_text(pji.version); ++#endif + PG_RETURN_POINTER(result); + } diff --git a/postgresql16-postgis.spec b/postgresql16-postgis.spec new file mode 100644 index 0000000..cd941ed --- /dev/null +++ b/postgresql16-postgis.spec @@ -0,0 +1,1040 @@ +%{!?postgresql_default:%global postgresql_default 1} + +%global sname postgis +%global pgversion 16 + +%global __requires_exclude ^perl\\(Pg\\)$ + +%{!?javabuild:%global javabuild 0} +%{!?utils:%global utils 1} +%{!?gcj_support:%global gcj_support 0} +%{!?upgrade:%global upgrade 1} +%{!?upgrade_prev:%global upgrade_prev 0} +%{!?runselftest:%global runselftest 1} +%{!?llvmjit:%global llvmjit 0} + +%global majorversion 3.5 +%global soversion 3 +%global prevmajorversion 2.5 +%global prevversion %{prevmajorversion}.5 +%global so_files postgis postgis_topology rtpostgis +%global configure_opts --disable-rpath --enable-raster + +%global __provides_exclude_from %{_libdir}/pgsql + +Name: postgresql%{pgversion}-%{sname} +Version: 3.5.3 +Release: 3%{?dist} +Summary: Geographic Information Systems Extensions to PostgreSQL +License: GPL-2.0-or-later + +URL: https://www.postgis.net +Source0: https://download.osgeo.org/%{sname}/source/%{sname}-%{version}.tar.gz +Source2: https://download.osgeo.org/%{sname}/docs/%{sname}-%{version}-en.pdf +%if %upgrade_prev +Source3: https://download.osgeo.org/%{sname}/source/%{sname}-%{prevversion}.tar.gz + +# Add proj8 compatibility to postgis-2.x (needed for upgrade package) +Patch1: postgis2-proj8.patch +Patch2: postgis-c99.patch +Patch3: postgis-c99-2.patch +%endif + +%if %?postgresql_default +%global pkgname %{sname} +%package -n %{pkgname} +Summary: Geographic Information Systems Extensions to PostgreSQL +%else +%global pkgname %name +%endif + +%if 0%{?fedora} +BuildRequires: SFCGAL-devel +BuildRequires: gtk2-devel +%endif + +BuildRequires: make +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: byacc +BuildRequires: clang +BuildRequires: desktop-file-utils +BuildRequires: docbook-dtds +BuildRequires: flex +BuildRequires: gcc-c++ +BuildRequires: gdal-devel >= 1.10.0 +BuildRequires: geos-devel >= 3.7.1 +BuildRequires: json-c-devel +BuildRequires: libtool +BuildRequires: libxml2-devel +BuildRequires: libxslt +BuildRequires: llvm +BuildRequires: pcre2-devel +BuildRequires: perl-generators +BuildRequires: proj-devel >= 5.2.0 +BuildRequires: protobuf-c-devel + +BuildRequires: postgresql%{pgversion}-server-devel + +%if %upgrade +BuildRequires: postgresql%{pgversion}-upgrade-devel +%endif + +%if %runselftest +BuildRequires: postgresql-test-rpm-macros +%endif + +%if %llvmjit +Requires: clang-devel llvm-devel +%endif + + +%if %?postgresql_default +%define postgresqlXX_if_default() %{expand:\ +Provides: postgresql%{pgversion}-%{sname}%{?1:-%{1}} = %precise_version\ +Provides: postgresql%{pgversion}-%{sname}%{?1:-%{1}}%{?_isa} = %precise_version\ +Obsoletes: postgresql%{pgversion}-%{sname}%{?1:-%{1}}\ +} +%else +%define postgresqlXX_if_default() %{nil} +%endif + +%define conflict_with_other_streams() %{expand:\ +Provides: %{sname}%{?1:-%{1}}-any\ +Conflicts: %{sname}%{?1:-%{1}}-any\ +} + +%define virtual_conflicts_and_provides() %{expand:\ +%conflict_with_other_streams %{**}\ +%postgresqlXX_if_default %{**}\ +} + +%global precise_version %{?epoch:%epoch:}%version-%release + +Provides: %{pkgname}%{?_isa} = %precise_version +Provides: %{pkgname} = %precise_version + +%virtual_conflicts_and_provides + +%description +PostGIS adds support for geographic objects to the PostgreSQL object-relational +database. In effect, PostGIS "spatially enables" the PostgreSQL server, +allowing it to be used as a backend spatial database for geographic information +systems (GIS), much like ESRI's SDE or Oracle's Spatial extension. PostGIS +follows the OpenGIS "Simple Features Specification for SQL" and has been +certified as compliant with the "Types and Functions" profile. + +%description -n %{pkgname} +PostGIS adds support for geographic objects to the PostgreSQL object-relational +database. In effect, PostGIS "spatially enables" the PostgreSQL server, +allowing it to be used as a backend spatial database for geographic information +systems (GIS), much like ESRI's SDE or Oracle's Spatial extension. PostGIS +follows the OpenGIS "Simple Features Specification for SQL" and has been +certified as compliant with the "Types and Functions" profile. + +%if %llvmjit +%package -n %{pkgname}-llvmjit +Summary: Just-in-time compilation support for PostGIS +Requires: %{name}%{?_isa} = %{version}-%{release} + +%virtual_conflicts_and_provides llvmjit + +%description -n %{pkgname}-llvmjit +Just-in-time compilation support for PostGIS. +%endif + +%package -n %{pkgname}-docs +Summary: Extra documentation for PostGIS + +%virtual_conflicts_and_provides docs + +%description -n %{pkgname}-docs +The postgis-docs package includes PDF documentation of PostGIS. + + +%if %javabuild +%package -n %{pkgname}-jdbc +Summary: The JDBC driver for PostGIS +# Automatically converted from old format: LGPLv2+ - review is highly recommended. +License: LicenseRef-Callaway-LGPLv2+ +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: postgresql-jdbc +BuildRequires: ant >= 0:1.6.2 +BuildRequires: java-devel +BuildRequires: junit >= 0:3.7 +BuildRequires: postgresql-jdbc + +%if %{gcj_support} +BuildRequires: gcc-java +BuildRequires: java-1.5.0-gcj-devel +Requires(post): %{_bindir}/rebuild-gcj-db +Requires(postun): %{_bindir}/rebuild-gcj-db +%endif + +%virtual_conflicts_and_provides jdbc + +%description -n %{pkgname}-jdbc +The postgis-jdbc package provides the essential jdbc driver for PostGIS. +%endif + + +%if %utils +%package -n %{pkgname}-utils +Summary: The utils for PostGIS +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: perl-DBD-Pg + +%virtual_conflicts_and_provides utils + +%description -n %{pkgname}-utils +The postgis-utils package provides the utilities for PostGIS. +%endif + + +%if %upgrade +%package -n %{pkgname}-upgrade +Summary: Support for upgrading Postgis +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: postgresql-upgrade +Provides: bundled(postgis) = %prevversion + +%virtual_conflicts_and_provides upgrade + +%description -n %{pkgname}-upgrade +%if %upgrade_prev +The postgis-upgrade package contains the previous version of Postgis as well as +the current version of Postgis built against the previous version of PostgreSQL +necessary for correct dump of schema from previous version of PostgreSQL. +%else +The postgis-upgrade package contains the current version of Postgis built against +the previous version of PostgreSQL necessary for correct dump of schema from previous +version of PostgreSQL. +%endif +%endif + +%if 0%{?fedora} +%package -n %{pkgname}-gui +Summary: The shp2pgsql-gui utility for PostGIS +Requires: %{name}%{?_isa} = %{version}-%{release} + +%virtual_conflicts_and_provides gui + +%description -n %{pkgname}-gui +The gui package provides shp2pgsql-gui for PostGIS. +%endif + +%package -n %{pkgname}-client +Summary: The CLI clients for PostGIS +Requires: %{name}%{?_isa} = %{version}-%{release} + +%virtual_conflicts_and_provides client + +%description -n %{pkgname}-client +The client package provides shp2pgsql, raster2pgsql and pgsql2shp for PostGIS. + +%prep +%if %upgrade_prev +%setup -q -n %{sname}-%{version} -a 3 +%else +%setup -q -n %{sname}-%{version} +%endif + +%if %upgrade +( +tar xf %{SOURCE0} + +%if %upgrade_prev +cd %{sname}-%{prevversion} +%patch -P 1 -p1 +%patch -P 2 -p2 +%patch -P 3 -p1 +./autogen.sh +%endif +) +%endif +cp -p %{SOURCE2} . + + +%build +%configure %configure_opts --with-pgconfig=%{_bindir}/pg_server_config \ +%if %llvmjit + --with-llvm \ +%endif +%if 0%{?fedora} + --with-sfcgal \ + --with-gui +%endif + +sed -i 's| -fstack-clash-protection | |' postgis/Makefile +sed -i 's| -fstack-clash-protection | |' raster/rt_pg/Makefile +sed -i 's| -fstack-clash-protection | |' topology/Makefile +sed -i 's| -fstack-clash-protection | |' extensions/address_standardizer/Makefile +sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool +sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool +%make_build + +%if %javabuild +export BUILDXML_DIR=%{_builddir}/%{sname}-%{version}/java/jdbc +JDBC_VERSION_RPM=`rpm -ql postgresql-jdbc| grep 'jdbc2.jar$'|awk -F '/' '{print $5}'` +sed 's/postgresql.jar/'${JDBC_VERSION_RPM}'/g' $BUILDXML_DIR/build.xml > $BUILDXML_DIR/build.xml.new +mv -f $BUILDXML_DIR/build.xml.new $BUILDXML_DIR/build.xml +pushd java/jdbc +ant +popd +%endif + +%if %utils +%make_build -C utils +%endif + +%if %upgrade +( +cd %{sname}-%{version} + +# Build current Postgis version against the previous PostgreSQL version. We need only the so names. +# We intentionally don't use %%configure here since there is too many +# pre-defined directories, and not everything from postgis-%%prevversion +# directory respects the `pg_config` output (liblwgeom especially). +./configure %configure_opts \ + --with-pgconfig=%postgresql_upgrade_prefix/bin/pg_config \ + --bindir=%postgresql_upgrade_prefix/bin \ + --libdir=%postgresql_upgrade_prefix/lib \ + --includedir=%postgresql_upgrade_prefix/include \ + --datadir=%postgresql_upgrade_prefix/share \ + --mandir=%postgresql_upgrade_prefix/share/man +sed -i 's| -fstack-clash-protection | |' postgis/Makefile +sed -i 's| -fstack-clash-protection | |' raster/rt_pg/Makefile +sed -i 's| -fstack-clash-protection | |' topology/Makefile +sed -i 's| -fstack-clash-protection | |' extensions/address_standardizer/Makefile +%make_build +) + +%if %upgrade_prev +( +cd %{sname}-%{prevversion} + +# Build previous Postgis version against the current PostgreSQL version. We need only the so names. +%configure %configure_opts +sed -i 's| -fstack-clash-protection | |' postgis/Makefile +sed -i 's| -fstack-clash-protection | |' raster/rt_pg/Makefile +sed -i 's| -fstack-clash-protection | |' topology/Makefile +sed -i 's| -fstack-clash-protection | |' extensions/address_standardizer/Makefile +%make_build +mkdir ../compat-build +for so in %so_files; do + find -name $so.so -exec cp {} ../compat-build/$so-%{prevmajorversion}.so \; + find -name $so-%{prevmajorversion}.so -exec cp -t ../compat-build/ {} + +done + +# Full build of previous Postgis version against previous PostgreSQL version +# We intentionally don't use %%configure here since there is too many +# pre-defined directories, and not everything from postgis-%%prevversion +# directory respects the `pg_config` output (liblwgeom especially). +./configure %configure_opts \ + --with-pgconfig=%postgresql_upgrade_prefix/bin/pg_config \ + --libdir=%postgresql_upgrade_prefix/lib \ + --includedir=%postgresql_upgrade_prefix/include +sed -i 's| -fstack-clash-protection | |' postgis/Makefile +sed -i 's| -fstack-clash-protection | |' raster/rt_pg/Makefile +sed -i 's| -fstack-clash-protection | |' topology/Makefile +sed -i 's| -fstack-clash-protection | |' extensions/address_standardizer/Makefile +%make_build +) +%endif +%endif + + +%install +%make_install +%make_install -C utils +%make_install -C extensions + +%if %upgrade +(cd %{sname}-%{version} && %make_install) +%if %upgrade_prev +(cd %{sname}-%{prevversion} && %make_install) +%endif + +# drop unused stuff from upgrade-only installation +/bin/rm -rf %buildroot%postgresql_upgrade_prefix/bin +/bin/rm -rf %buildroot%postgresql_upgrade_prefix/lib/lib* +/bin/rm -rf %buildroot%postgresql_upgrade_prefix/share + +# Manually install compat-build binary. +%if %upgrade_prev +for so in %so_files; do +%{__install} -m 644 compat-build/$so-%{prevmajorversion}.so %{buildroot}/%{_libdir}/pgsql +done +%endif +%endif + +rm -f %{buildroot}%{_datadir}/*.sql + +%if %javabuild +install -d %{buildroot}%{_javadir} +install -m 755 java/jdbc/%{sname}-%{version}.jar %{buildroot}%{_javadir}/%{sname}.jar +%if %{gcj_support} +aot-compile-rpm +%endif +strip %{buildroot}/%{_libdir}/gcj/%{sname}/*.jar.so +%endif + +%if %utils +install -d %{buildroot}%{_datadir}/%{sname} +install -m 755 utils/*.pl %{buildroot}%{_datadir}/%{sname} +%endif + +find %buildroot \( -name '*.la' -or -name '*.a' \) -delete + + +%check +%if 0%{?fedora} +desktop-file-validate %{buildroot}/%{_datadir}/applications/shp2pgsql-gui.desktop +%endif +%if %runselftest +%postgresql_tests_run +export PGIS_REG_TMPDIR=`mktemp -d` +if ! LD_LIBRARY_PATH=%{buildroot}%_libdir make check %{_smp_mflags} ; then + for file in $(find $PGIS_REG_TMPDIR -name '*_diff'); do + echo "== $file ==" + cat "$file" + done +fi +%endif + + +%if %javabuild +%if %gcj_support +%post jdbc -p %{_bindir}/rebuild-gcj-db +%postun jdbc -p %{_bindir}/rebuild-gcj-db +%endif +%endif + + +%files -n %{pkgname} +%license COPYING +%doc CREDITS NEWS TODO README.%{sname} loader/README.* doc/%{sname}.xml doc/ZMSgeoms.txt + +%{_libdir}/pgsql/%{sname}-%{soversion}.so +%{_datadir}/pgsql/contrib/postgis-%{majorversion}/*.sql +%{_datadir}/pgsql/extension/address_standardizer*.sql +%{_datadir}/pgsql/extension/address_standardizer*.control +%{_datadir}/pgsql/extension/postgis-*.sql +%{_datadir}/pgsql/extension/postgis_raster*.sql +%if 0%{?fedora} +%{_datadir}/pgsql/extension/postgis_sfcgal*.sql +%endif +%{_datadir}/pgsql/extension/postgis_topology*.sql +%{_datadir}/pgsql/extension/postgis.control +%{_datadir}/pgsql/extension/postgis_raster.control +%if 0%{?fedora} +%{_datadir}/pgsql/extension/postgis_sfcgal.control +%endif +%{_datadir}/pgsql/extension/postgis_topology.control +%{_datadir}/pgsql/extension/postgis_tiger_geocoder*.sql +%{_datadir}/pgsql/extension/postgis_tiger_geocoder.control +%{_datadir}/postgis/create_unpackaged.pl +%{_datadir}/postgis/create_skip_signatures.pl +%{_datadir}/postgis/create_spatial_ref_sys_config_dump.pl +%{_datadir}/postgis/create_uninstall.pl +%{_datadir}/postgis/repo_revision.pl +%{_libdir}/pgsql/address_standardizer-%{soversion}.so +%{_libdir}/pgsql/postgis_raster-%{soversion}.so +%if 0%{?fedora} +%{_libdir}/pgsql/postgis_sfcgal-%{soversion}.so +%endif +%{_libdir}/pgsql/postgis_topology-%{soversion}.so + +%files -n %{pkgname}-client +%{_bindir}/postgis +%{_bindir}/postgis_restore +%{_bindir}/pgsql2shp +%{_bindir}/raster2pgsql +%{_bindir}/shp2pgsql +%{_bindir}/pgtopo_export +%{_bindir}/pgtopo_import +%{_mandir}/man1/pgsql2shp.1* +%{_mandir}/man1/pgtopo_export.1* +%{_mandir}/man1/pgtopo_import.1* +%{_mandir}/man1/postgis.1* +%{_mandir}/man1/postgis_restore.1* +%{_mandir}/man1/shp2pgsql.1* + +%if 0%{?fedora} +%files -n %{pkgname}-gui +%{_bindir}/shp2pgsql-gui +%{_datadir}/applications/shp2pgsql-gui.desktop +%{_datadir}/icons/hicolor/*/apps/shp2pgsql-gui.png +%endif + + +%if %llvmjit +%files -n %{pkgname}-llvmjit +%{_libdir}/pgsql/bitcode/address_standardizer-* +%{_libdir}/pgsql/bitcode/postgis-* +%{_libdir}/pgsql/bitcode/postgis_raster-* +%if 0%{?fedora} +%{_libdir}/pgsql/bitcode/postgis_sfcgal-* +%endif +%{_libdir}/pgsql/bitcode/postgis_topology-* +%endif + + +%if %javabuild +%files -n %{pkgname}-jdbc +%license java/jdbc/COPYING_LGPL +%doc java/jdbc/README +%{_javadir}/%{sname}.jar +%if %{gcj_support} +%dir %{_libdir}/gcj/%{sname} +%{_libdir}/gcj/%{sname}/*.jar.so +%{_libdir}/gcj/%{sname}/*.jar.db +%endif +%endif + + +%if %upgrade +%files -n %{pkgname}-upgrade +%postgresql_upgrade_prefix/* +%if %upgrade_prev +%{_libdir}/pgsql/*-%{prevmajorversion}.so +%endif +%endif + + +%if %utils +%files -n %{pkgname}-utils +%doc utils/README +%dir %{_datadir}/%{sname}/ +%doc %{_datadir}/doc/pgsql/extension/README.address_standardizer +%{_datadir}/%{sname}/test_estimation.pl +%{_datadir}/%{sname}/profile_intersects.pl +%{_datadir}/%{sname}/test_joinestimation.pl +%{_datadir}/%{sname}/create_extension_unpackage.pl +%{_datadir}/%{sname}/%{sname}_restore.pl +%{_datadir}/%{sname}/read_scripts_version.pl +%{_datadir}/%{sname}/test_geography_estimation.pl +%{_datadir}/%{sname}/test_geography_joinestimation.pl +%{_datadir}/%{sname}/create_or_replace_to_create.pl +%{_datadir}/%{sname}/create_upgrade.pl +%endif + + +%files -n %{pkgname}-docs +%doc postgis*.pdf + + +%changelog +* Tue Jul 29 2025 Sandro Mani - 3.5.3-3 +- Rebuild (gdal) + +* Fri Jul 25 2025 Fedora Release Engineering - 3.5.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + +* Thu May 29 2025 Sandro Mani - 3.5.3-1 +- Update to 3.5.3 + +* Fri Feb 07 2025 Sandro Mani - 3.5.2-2 +- Rebuild (SFCGAL) + +* Sun Jan 19 2025 Sandro Mani - 3.5.2-1 +- Update to 3.5.2 + +* Sat Jan 18 2025 Fedora Release Engineering - 3.5.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + +* Sun Dec 22 2024 Sandro Mani - 3.5.1-1 +- Update to 3.5.1 + +* Sat Nov 09 2024 Sandro Mani - 3.5.0-3 +- Rebuild (GDAL) + +* Fri Nov 08 2024 Sandro Mani - 3.5.0-2 +- Rebuild (gdal) + +* Sun Sep 29 2024 Sandro Mani - 3.5.0-1 +- Update to 3.5.0 + +* Thu Sep 05 2024 Sandro Mani - 3.4.3-1 +- Update to 3.4.3 + +* Wed Sep 04 2024 Miroslav Suchý - 3.4.2-4 +- convert license to SPDX + +* Fri Jul 19 2024 Fedora Release Engineering - 3.4.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Mon May 13 2024 Sandro Mani - 3.4.2-2 +- Rebuild (gdal) + +* Sat Feb 10 2024 Sandro Mani - 3.4.2-1 +- Update to 3.4.2 + +* Thu Jan 25 2024 Fedora Release Engineering - 3.4.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Sun Jan 21 2024 Fedora Release Engineering - 3.4.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Mon Dec 18 2023 Sandro Mani - 3.4.1-2 +- Re-enable upgrade package for previous postgres version only + +* Tue Nov 21 2023 Sandro Mani - 3.4.1-1 +- Update to 3.4.1 + +* Wed Nov 15 2023 Sandro Mani - 3.4.0-2 +- Rebuild (gdal) + +* Thu Aug 17 2023 Sandro Mani - 3.4.0-1 +- Update to 3.4.0 + +* Sat Jul 29 2023 Sandro Mani - 3.3.4-1 +- Update to 3.3.4 + +* Fri Jul 21 2023 Fedora Release Engineering - 3.3.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Tue May 30 2023 Sandro Mani - 3.3.3-1 +- Update to 3.3.3 + +* Thu May 11 2023 Sandro Mani - 3.3.2-5 +- Rebuild (gdal) + +* Sun Apr 09 2023 Florian Weimer - 3.3.2-4 +- C99 compatibility fixes + +* Fri Jan 20 2023 Fedora Release Engineering - 3.3.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + +* Wed Nov 16 2022 Ondřej Sloup - 3.3.2-2 +- Rebuild for new PostgreSQL 15 + +* Mon Nov 14 2022 Sandro Mani - 3.3.2-1 +- Update to 3.3.2 + +* Sat Nov 12 2022 Sandro Mani - 3.3.1-2 +- Rebuild (gdal) + +* Sat Sep 10 2022 Sandro Mani - 3.3.1-1 +- Update to 3.3.1 + +* Tue Aug 30 2022 Sandro Mani - 3.3.0-1 +- Update to 3.3.0 + +* Sat Aug 06 2022 Sandro Mani - 3.2.2-1 +- Update to 3.2.2 +- Re-enable upgrade subpackages + +* Fri Jul 22 2022 Fedora Release Engineering - 3.2.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + +* Fri May 20 2022 Sandro Mani - 3.2.1-3 +- Rebuild for gdal-3.5.0 and/or openjpeg-2.5.0 + +* Thu Mar 10 2022 Sandro Mani - 3.2.1-2 +- Rebuild for proj-9.0.0 + +* Mon Feb 14 2022 Sandro Mani - 3.2.1-1 +- Update to 3.2.1 + +* Fri Jan 21 2022 Fedora Release Engineering - 3.2.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + +* Tue Jan 11 2022 Sandro Mani - 3.2.0-2 +- Rebuild (postgresql-14) + +* Sat Dec 18 2021 Sandro Mani - 3.2.0-1 +- Update to 3.2.0 + +* Thu Nov 11 2021 Sandro Mani - 3.1.4-5 +- Rebuild (gdal) + +* Sat Nov 06 2021 Adrian Reber - 3.1.4-4 +- Rebuilt for protobuf 3.19.0 + +* Tue Oct 26 2021 Adrian Reber - 3.1.4-3 +- Rebuilt for protobuf 3.18.1 + +* Thu Oct 21 2021 Sandro Mani - 3.1.4-2 +- Rebuild (geos) + +* Sat Sep 04 2021 Sandro Mani - 3.1.4-1 +- Update to 3.1.4 + +* Fri Jul 23 2021 Fedora Release Engineering - 3.1.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + +* Sat Jul 10 2021 Björn Esser - 3.1.3-2 +- Rebuild for versioned symbols in json-c + +* Mon Jul 05 2021 Sandro Mani - 3.1.3-1 +- Update to 3.1.3 + +* Mon Jul 5 2021 Basil Eric Rabi - 3.1.2-2 +- Build with SFCGAL + +* Mon May 24 2021 Sandro Mani - 3.1.2-1 +- Update to 3.1.2 + +* Fri May 07 2021 Sandro Mani - 3.1.1-8 +- Rebuild (gdal) + +* Tue Mar 23 2021 Sandro Mani - 3.1.1-7 +- Bump + +* Sun Mar 07 2021 Sandro Mani - 3.1.1-6 +- Rebuild (proj) +- Disable upgrade packages for now (not compatible with proj8) + +* Mon Feb 22 2021 Michael Scherer - 3.1.1-5 +- split various utilities subpackages, to not pull gtk in the main rpm + +* Sat Feb 13 2021 Sandro Mani - 3.1.1-4 +- Rebuild (geos) + +* Tue Feb 09 2021 Sandro Mani - 3.1.1-3 +- Also ship current version of Postgis against previous version of PostgreSQL in + postgis-upgrade + +* Mon Feb 08 2021 Pavel Raiskup - 3.1.1-2 +- rebuild for libpq ABI fix rhbz#1908268 + +* Fri Jan 29 2021 Sandro Mani - 3.1.1-1 +- Update to 3.1.1 + +* Wed Jan 27 2021 Fedora Release Engineering - 3.1.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Wed Jan 13 16:41:55 CET 2021 Adrian Reber - 3.1.0-2 +- Rebuilt for protobuf 3.14 + +* Sat Dec 19 2020 Sandro Mani - 3.1.0-1 +- Update to 3.1.0 + +* Mon Nov 23 2020 Sandro Mani - 3.0.3-1 +- Update to 3.0.3 + +* Wed Nov 11 2020 Sandro Mani - 3.0.2-3 +- Rebuild (proj, gdal) +- Cleanup spec + +* Thu Oct 08 2020 Jeff Law - 3.0.2-2 +- Re-enable LTO + +* Mon Aug 17 2020 Sandro Mani - 3.0.2-1 +- Update to 3.0.2 + +* Sat Aug 01 2020 Fedora Release Engineering - 3.0.1-10 +- Second attempt - Rebuilt for + https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue Jul 28 2020 Fedora Release Engineering - 3.0.1-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Sat Jul 11 2020 Jiri Vanek - 3.0.1-8 +- Rebuilt for JDK-11, see https://fedoraproject.org/wiki/Changes/Java11 + +* Thu May 21 2020 Sandro Mani - 3.0.1-7 +- Rebuild (gdal) + +* Mon May 04 2020 Sandro Mani - 3.0.1-6 +- Pass --with-pgconfig=%%{_bindir}/pg_server_config + +* Sun May 03 2020 Sandro Mani - 3.0.1-5 +- Move postgis-upgrade to 2.5.4 + +* Wed Apr 22 2020 Björn Esser - 3.0.1-4 +- Re-enable selftests + +* Tue Apr 21 2020 Björn Esser - 3.0.1-3 +- Rebuild (json-c) +- Disable selftests, as they seem to be flaky + +* Tue Mar 03 2020 Sandro Mani - 3.0.1-2 +- Rebuild (gdal) + +* Mon Mar 02 2020 Sandro Mani - 3.0.1-1 +- Update to 3.0.1 + +* Sun Feb 16 2020 Devrim Gündüz - 3.0.0-1 +- Update to 3.0.0 + +* Thu Jan 30 2020 Fedora Release Engineering - 2.5.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Wed Sep 4 2019 Devrim Gündüz - 2.5.3-1 +- Update to 2.5.3 +- Update prev version to 2.4.8 + +* Fri Jul 26 2019 Fedora Release Engineering - 2.5.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Mon Feb 4 2019 Devrim Gündüz - 2.5.1-1 +- Update to 2.5.1 + +* Sat Feb 02 2019 Fedora Release Engineering - 2.5.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Mon Oct 22 2018 Petr Kubat - 2.5.0-1 +- update to 2.5.0, per NEWS file: + https://svn.osgeo.org/postgis/tags/2.5.0/NEWS + +* Wed Sep 05 2018 Pavel Raiskup - 2.4.3-6 +- rebuild against postgresql-server-devel (rhbz#1618698) + +* Fri Jul 13 2018 Fedora Release Engineering - 2.4.3-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Fri Apr 13 2018 Pavel Raiskup - 2.4.3-4 +- postgresql.spec moved testing macros to postgresql-test-rpm-macros + +* Tue Mar 06 2018 Björn Esser - 2.4.3-3 +- Rebuilt for libjson-c.so.4 (json-c v0.13.1) + +* Fri Feb 09 2018 Fedora Release Engineering - 2.4.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Thu Jan 18 2018 Pavel Raiskup - 2.4.3-1 +- rebase to latest upstream release (rhbz#1513788) + +* Fri Dec 15 2017 Björn Esser - 2.4.1-4 +- Add patch for changes in json-c >= 0.13 + +* Sun Dec 10 2017 Björn Esser - 2.4.1-3 +- Rebuilt for libjson-c.so.3 + +* Thu Oct 26 2017 Pavel Raiskup - 2.4.1-2 +- upgrade: drop not-used /bin directory and liblwgeom (rhbz#1055293) +- upgrade: confess that we bundle postgis = prevversion + +* Mon Oct 23 2017 Pavel Raiskup - 2.4.1-1 +- update to 2.4.1, per NEWS file: + https://svn.osgeo.org/postgis/tags/2.4.1/NEWS + +* Wed Oct 18 2017 Pavel Raiskup - 2.4.0-2 +- build against json-c again (rhbz#1484031) +- post/postun set for jdbc sub-package (rhbz#979685) + +* Tue Oct 17 2017 Pavel Raiskup - 2.4.0-1 +- install desktop files into /usr/share/applications +- optimize build without %%upgrade +- drop explicit requires on libraries (resolved by implicit lib*.so*()) +- enable build testsuite +- disable hardening on f26 (all arches) and on s390x (all distros) + +* Tue Oct 10 2017 Pavel Raiskup - 2.4.0-1 +- provide postgis-upgrade package (rhbz#1475177) + +* Mon Oct 09 2017 Pavel Raiskup - 2.4.0-1 +- update to 2.4.0, per upstream release notes + https://postgis.net/2017/09/30/postgis-2.4.0/ + +* Thu Aug 03 2017 Fedora Release Engineering - 2.3.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 2.3.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Sun Jul 2 2017 Devrim Gündüz - 2.3.3-1 +- Update to 2.3.3, per changes described at + http://postgis.net/2017/07/01/postgis-2.3.3/ + rhbz #1467032 + +* Sat Feb 11 2017 Fedora Release Engineering - 2.3.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Wed Jan 25 2017 Devrim Gündüz - 2.3.2-1 +- Update to 2.3.2, per changes described at + http://postgis.net/2017/01/31/postgis-2.3.2/ + rhbz#1418136 + +* Wed Jan 25 2017 Devrim Gündüz - 2.3.1-2 +- Rebuild against Proj 4.9.3 + +* Wed Nov 30 2016 Devrim Gündüz - 2.3.1-1 +- Update to 2.3.1, per changes described at + http://postgis.net/2016/11/28/postgis-2.3.1 +- Update previous version to 2.2.4 +- Fix a few rpmlint warnings. + +* Mon Oct 10 2016 Pavel Raiskup - 2.3.0-3 +- bump: build in rawhide hit too early + +* Fri Oct 07 2016 Petr Kubat - 2.3.0-2 +- Rebuild for PostgreSQL 9.6.0 + +* Tue Sep 27 2016 Jozef Mlich - 2.3.0-1 +- Update to 2.3.0, per changes described at + http://postgis.net/2016/09/26/postgis-2.3.0/ + +* Fri Mar 25 2016 Devrim Gündüz - 2.2.2-1 +- Update to 2.2.2, per changes described at + http://postgis.net/2016/03/22/postgis-2.2.2 + +* Mon Feb 15 2016 Pavel Raiskup - 2.2.1-3 +- install address_standardizer module (rhbz#1307872) + +* Thu Feb 04 2016 Fedora Release Engineering - 2.2.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Fri Jan 08 2016 Jozef Mlich - 2.2.1-1 +- Rebuild to 2.2.1, per changes described at: + http://svn.osgeo.org/postgis/tags/2.2.1/NEWS + +* Sun Aug 30 2015 Peter Robinson 2.1.8-2 +- Rebuild again for GDAL 2.0 + +* Tue Jul 28 2015 Devrim Gündüz - 2.1.8-1 +- Update to 2.1.8, per changes described at: + http://svn.osgeo.org/postgis/tags/2.1.8/NEWS +- Rebuilt for GDAL 2.0 + +* Thu Jun 18 2015 Fedora Release Engineering - 2.1.7-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Apr 1 2015 Devrim Gündüz - 2.1.7-1 +- Update to 2.1.7, per changes described at: + http://svn.osgeo.org/postgis/tags/2.1.7/NEWS + +* Fri Mar 27 2015 Devrim Gündüz - 2.1.6-1 +- Update to 2.1.6, per changes described at: + http://postgis.net/2015/03/20/postgis-2.1.6 + +* Wed Mar 11 2015 Devrim Gündüz - 2.1.5-3 +- Rebuild for Proj 4.9.1 +- Add patch to fix FTBFS -- patch by Sandro Mani + +* Thu Jan 08 2015 Jozef Mlich - 2.1.5-2 +- disable json-c/geojson just for upgrade part of postgis + +* Mon Dec 22 2014 Devrim Gündüz - 2.1.5-1 +- Update to 2.1.5, per changes described at: + http://postgis.net/2014/12/18/postgis-2.1.5 and + http://postgis.net/2014/09/10/postgis-2.1.4 + +* Mon Aug 18 2014 Jozef Mlich - 2.1.3-5 +- Dropped json-c because it is not building anymore + Resolves: #1129292 + +* Sun Aug 17 2014 Fedora Release Engineering - 2.1.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Thu Jun 26 2014 Jozef Mlich - 2.1.3-3 +- Removing static libraries + Resolves: #979179 + +* Mon Jun 09 2014 Jozef Mlich - 2.1.3-2 +- removing sinjdoc from BuildRequires as it is not available + in rawhide anymore + +* Mon Jun 09 2014 Jozef Mlich - 2.1.3-1 +- Rebase to 2.1.3 and 2.0.6 (security bugfixes, feature bugfixes) + see http://svn.osgeo.org/postgis/tags/2.1.3/NEWS +- json_c turned on +- installation of .so file of previous version moved into install section + +* Sat Jun 07 2014 Fedora Release Engineering - 2.1.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Thu Jan 23 2014 Devrim Gündüz - 2.1.1-2 +- Install postgis-2.0.so file, by compiling it from 2.0 sources + Fixes bz #1055293. + +* Thu Dec 12 2013 Devrim Gündüz - 2.1.1-1 +- Update to 2.1.1 + +* Fri Oct 25 2013 Dan Horák - 2.1.0-2 +- fix build on non-x86 64-bit arches + +* Thu Sep 12 2013 Devrim Gündüz - 2.1.0-1 +- Update to 2.1.0, per changes described at: + http://svn.osgeo.org/postgis/tags/2.1.0/NEWS + +* Tue Aug 27 2013 Orion Poplawski - 2.0.3-4 +- Rebuild for gdal 1.10.0 + +* Sun Aug 04 2013 Fedora Release Engineering - 2.0.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Wed Jul 17 2013 Petr Pisar - 2.0.3-2 +- Perl 5.18 rebuild + +* Wed Mar 6 2013 Devrim GÜNDÜZ - 2.0.3-1 +- Update to 2.0.3, and build against GeOS 3.3.8. +- Update all URLs. + +* Fri Jan 25 2013 Devrim GÜNDÜZ - 2.0.2-2 +- Rebuilt against geos 3.3.7. +- Apply changes for PostgreSQL 9.2 and extensions. + +* Wed Jan 16 2013 Devrim GÜNDÜZ - 2.0.2-1 +- Update to 2.0.2, for various changes described at: + http://www.postgis.org/news/20121203/ + +* Tue Nov 13 2012 Devrim GÜNDÜZ - 2.0.1-1 +- Update to 2.0.1, so it works against PostgreSQL 9.2, + which also fixes #872710. +- Add deps for gdal. +- Don't build JDBC portions. I have already disabled it in + upstream packaging 8 months ago. + +* Sat Jul 21 2012 Fedora Release Engineering - 1.5.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Sat Jan 14 2012 Fedora Release Engineering - 1.5.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Oct 4 2011 Devrim GÜNDÜZ - 1.5.3-2 +- Provide postgis.jar instead of provide postgis-1.5.2.jar, + per #714856 + +* Tue Oct 4 2011 Devrim GÜNDÜZ - 1.5.3-1 +- Update to 1.5.3 + +* Tue Apr 19 2011 Devrim GÜNDÜZ - 1.5.2-1 +- Update to 1.5.2 + +* Sun Apr 03 2011 Nils Philippsen - 1.5.1-3 +- cope with PostgreSQL 9.0 build environment +- require pgsql version used for building + +* Wed Feb 09 2011 Fedora Release Engineering - 1.5.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Thu Mar 11 2010 Devrim GÜNDÜZ - 1.5.1-1 +- Update to 1.5.1 + +* Tue Jan 12 2010 Devrim GÜNDÜZ - 1.5.0-1 +- Update to 1.5.0 +- Trim changelog a bit. + +* Wed Jan 6 2010 Devrim GÜNDÜZ - 1.4.1-2 +- Add shp2pgsql-{cli-gui} among installed files. + +* Sun Dec 20 2009 Devrim GÜNDÜZ - 1.4.1-1 +- Update to 1.4.1 + +* Thu Dec 03 2009 Devrim GÜNDÜZ - 1.4.1-rc2_1.2 +- Fix spec per rawhide report. + +* Tue Dec 01 2009 Devrim GÜNDÜZ - 1.4.1-rc2_1.1 +- Update spec for rc2 changes. + +* Mon Nov 30 2009 Devrim GUNDUZ - 1.4.1rc2-1 +- Update to 1.4.1rc2 + +* Mon Nov 23 2009 Devrim GUNDUZ - 1.4.1rc1-1 +- Update to 1.4.1rc1 + +* Sun Nov 22 2009 Devrim GÜNDÜZ - 1.4.0-2 +- Fix spec, per bz #536860 + +* Mon Jul 27 2009 Devrim GUNDUZ - 1.4.0-1 +- Update to 1.4.0 + +* Sun Jul 26 2009 Fedora Release Engineering - 1.4.0rc1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 6 2009 Devrim GUNDUZ - 1.4.0rc1-1 +- Update to 1.4.0rc1 +- Fix spec for 1.4 diff --git a/sources b/sources new file mode 100644 index 0000000..4921b68 --- /dev/null +++ b/sources @@ -0,0 +1,2 @@ +SHA512 (postgis-3.5.3-en.pdf) = 69e162ea657a3bce2fb139ebeb9bd212ac646cb83027345eab9677609160a365d3ecdaa2995eb494054fc4667016a069afdbdbbd1cc56ff407fac05fd8306fa0 +SHA512 (postgis-3.5.3.tar.gz) = c27f57f0dbf3938648fe16dcaaff28530de6a51c13c481cb78163a51a292f3d77620485cd31e79cd01be675b5dca97129c50c562f68d6d864c822ea7359d754f