From a77061a59f18201e2c1e29e94e09b3fb90eba14b Mon Sep 17 00:00:00 2001 From: Phillip Ross Date: Sun, 29 Mar 2020 15:51:58 -0400 Subject: [PATCH] PGgeo-PGgeometry-PGgeography class hierarchy (#80) https://github.com/postgis/postgis-java/issues/55 - Renamed test in postgis-geometry test suite - Introduced new JDBC PGobject extensions class hierarchy which now allows jdbc queries to return geometry or geography data with specific types which callers can use to differentiate which data type was queried - Cleanup and better documentation for DriverWrapper - Renamed AutoRegistrationTest to DatatypesAutoRegistration to better reflect what is being tested - Added geography as one of the castTypes in the EmptyGeometriesTest class - Added instantiation test for PGgeography to DatatypesTest class - Added GeographyDatatypeTest to verify new PGgeo/PGgeometry/PGgeography class hierarchy - Added PGgeography to driverconfig.properties --- .../main/java/org/postgis/DriverWrapper.java | 147 ++++++---- jdbc/src/main/java/org/postgis/PGgeo.java | 133 +++++++++ .../main/java/org/postgis/PGgeography.java | 77 ++++++ .../main/java/org/postgis/PGgeographyLW.java | 84 ++++++ .../src/main/java/org/postgis/PGgeometry.java | 81 +++--- .../main/java/org/postgis/PGgeometryLW.java | 66 +++-- .../org/postgresql/driverconfig.properties | 1 + .../org/postgis/AutoRegistrationTest.java | 121 -------- .../DatatypesAutoRegistrationTest.java | 144 ++++++++++ .../test/java/org/postgis/DatatypesTest.java | 9 + .../java/org/postgis/EmptyGeometriesTest.java | 5 +- .../org/postgis/GeographyDatatypeTest.java | 260 ++++++++++++++++++ .../src/test/resources-filtered/testng-it.xml | 3 +- .../src/test/resources/testng.xml | 2 +- 14 files changed, 887 insertions(+), 246 deletions(-) create mode 100644 jdbc/src/main/java/org/postgis/PGgeo.java create mode 100644 jdbc/src/main/java/org/postgis/PGgeography.java create mode 100644 jdbc/src/main/java/org/postgis/PGgeographyLW.java delete mode 100644 jdbc/src/test/java/org/postgis/AutoRegistrationTest.java create mode 100644 jdbc/src/test/java/org/postgis/DatatypesAutoRegistrationTest.java create mode 100644 jdbc/src/test/java/org/postgis/GeographyDatatypeTest.java diff --git a/jdbc/src/main/java/org/postgis/DriverWrapper.java b/jdbc/src/main/java/org/postgis/DriverWrapper.java index cab2552..2a04f65 100644 --- a/jdbc/src/main/java/org/postgis/DriverWrapper.java +++ b/jdbc/src/main/java/org/postgis/DriverWrapper.java @@ -1,12 +1,4 @@ /* - * DriverWrapper.java - * - * PostGIS extension for PostgreSQL JDBC driver - Wrapper utility class - * - * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com - * - * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com - * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -20,14 +12,17 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com */ package org.postgis; + import java.sql.Connection; import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; @@ -35,6 +30,7 @@ import org.postgresql.Driver; import org.postgresql.PGConnection; + /** * DriverWrapper * @@ -73,6 +69,7 @@ */ public class DriverWrapper extends Driver { + /** The static logger instance. */ protected static final Logger logger = Logger.getLogger("org.postgis.DriverWrapper"); public static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; @@ -84,6 +81,17 @@ public class DriverWrapper extends Driver { protected TypesAdder typesAdder; + + static { + try { + // Try to register ourself to the DriverManager + java.sql.DriverManager.registerDriver(new DriverWrapper()); + } catch (SQLException e) { + logger.log(Level.WARNING, "Error registering PostGIS Wrapper Driver", e); + } + } + + /** * Default constructor. * @@ -101,7 +109,8 @@ public DriverWrapper() throws SQLException { } } - protected static TypesAdder getTypesAdder(Driver d) throws SQLException { + + protected static TypesAdder getTypesAdder(final Driver d) throws SQLException { if (d.getMajorVersion() == 7) { if (d.getMinorVersion() >= 3) { if (ta74 == null) { @@ -122,7 +131,8 @@ protected static TypesAdder getTypesAdder(Driver d) throws SQLException { } } - private static TypesAdder loadTypesAdder(String version) throws SQLException { + + private static TypesAdder loadTypesAdder(final String version) throws SQLException { try { Class klass = Class.forName("org.postgis.DriverWrapper$TypesAdder" + version); return (TypesAdder) klass.newInstance(); @@ -131,20 +141,13 @@ private static TypesAdder loadTypesAdder(String version) throws SQLException { } } - static { - try { - // Try to register ourself to the DriverManager - java.sql.DriverManager.registerDriver(new DriverWrapper()); - } catch (SQLException e) { - logger.log(Level.WARNING, "Error registering PostGIS Wrapper Driver", e); - } - } /** - * Creates a postgresql connection, and then adds the PostGIS data types to - * it calling addpgtypes() + * Creates a postgresql connection, and then adds the PostGIS data types to it calling addpgtypes(). + * + * A side-effect of this method is that the specified url parameter may be be changed * - * @param url the URL of the database to connect to + * @param url the URL of the database to connect to (may be changed as a side-effect of this method) * @param info a list of arbitrary tag/value pairs as connection arguments * @return a connection to the URL or null if it isnt us * @exception SQLException if a database access error occurs @@ -152,13 +155,14 @@ private static TypesAdder loadTypesAdder(String version) throws SQLException { * @see java.sql.Driver#connect * @see org.postgresql.Driver */ - public java.sql.Connection connect(String url, Properties info) throws SQLException { + public java.sql.Connection connect(String url, final Properties info) throws SQLException { url = mangleURL(url); Connection result = super.connect(url, info); typesAdder.addGT(result, useLW(result)); return result; } + /** * Do we have HexWKB as well known text representation - to be overridden by * subclasses. @@ -166,18 +170,21 @@ public java.sql.Connection connect(String url, Properties info) throws SQLExcept * @param result Connection to check * @return true if using EWKB, false otherwise */ - protected boolean useLW(Connection result) { + protected boolean useLW(final Connection result) { if (result == null) { throw new IllegalArgumentException("null is no valid parameter"); } return false; } + /** * Check whether the driver thinks he can handle the given URL. + * + * A side-effect of this method is that the specified url parameter may be be changed * * @see java.sql.Driver#acceptsURL - * @param url the URL of the driver + * @param url the URL of the driver (may be changed as a side-effect of this method) * @return true if this driver accepts the given URL */ public boolean acceptsURL(String url) { @@ -189,6 +196,7 @@ public boolean acceptsURL(String url) { return super.acceptsURL(url); } + /** * Returns our own CVS version plus postgres Version * @@ -198,6 +206,7 @@ public static String getVersion() { return "PostGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); } + /* * Here follows the addGISTypes() stuff. This is a little tricky because the * pgjdbc people had several, partially incompatible API changes during 7.2 @@ -214,30 +223,33 @@ public static String getVersion() { * @throws SQLException when a SQLException occurs * */ - public static void addGISTypes(PGConnection pgconn) throws SQLException { + public static void addGISTypes(final PGConnection pgconn) throws SQLException { loadTypesAdder("74").addGT((Connection) pgconn, false); } + /** * adds the JTS/PostGIS Data types to a PG 8.0+ Connection. * * @param pgconn The PGConnection object to add the types to * @throws SQLException when a SQLException occurs */ - public static void addGISTypes80(PGConnection pgconn) throws SQLException { + public static void addGISTypes80(final PGConnection pgconn) throws SQLException { loadTypesAdder("80").addGT((Connection) pgconn, false); } + /** * adds the JTS/PostGIS Data types to a PG 7.2 Connection. * * @param pgconn The PGConnection object to add the types to * @throws SQLException when a SQLException occurs */ - public static void addGISTypes72(org.postgresql.PGConnection pgconn) throws SQLException { + public static void addGISTypes72(final org.postgresql.PGConnection pgconn) throws SQLException { loadTypesAdder("72").addGT((Connection) pgconn, false); } + /** * Mangles the PostGIS URL to return the original PostGreSQL URL * @@ -245,7 +257,7 @@ public static void addGISTypes72(org.postgresql.PGConnection pgconn) throws SQLE * @return "mangled" string * @throws SQLException when a SQLException occurs */ - protected String mangleURL(String url) throws SQLException { + protected String mangleURL(final String url) throws SQLException { String myProgo = getProtoString(); if (url.startsWith(myProgo)) { return POSTGRES_PROTOCOL + url.substring(myProgo.length()); @@ -254,13 +266,15 @@ protected String mangleURL(String url) throws SQLException { } } + protected String getProtoString() { return POSTGIS_PROTOCOL; } + /** Base class for the three typewrapper implementations */ protected abstract static class TypesAdder { - public final void addGT(java.sql.Connection conn, boolean lw) throws SQLException { + public final void addGT(final java.sql.Connection conn, final boolean lw) throws SQLException { if (lw) { addBinaryGeometries(conn); } else { @@ -269,68 +283,88 @@ public final void addGT(java.sql.Connection conn, boolean lw) throws SQLExceptio addBoxen(conn); } - public abstract void addGeometries(Connection conn) throws SQLException; + public abstract void addGeometries(final Connection conn) throws SQLException; - public abstract void addBoxen(Connection conn) throws SQLException; + public abstract void addBoxen(final Connection conn) throws SQLException; - public abstract void addBinaryGeometries(Connection conn) throws SQLException; + public abstract void addBinaryGeometries(final Connection conn) throws SQLException; } + /** addGISTypes for V7.3 and V7.4 pgjdbc */ protected static final class TypesAdder74 extends TypesAdder { - public void addGeometries(Connection conn) throws SQLException { + + /** {@inheritDoc} */ + @Override + public void addGeometries(final Connection conn) throws SQLException { PGConnection pgconn = (PGConnection) conn; pgconn.addDataType("geometry", org.postgis.PGgeometry.class); pgconn.addDataType("public.geometry", org.postgis.PGgeometry.class); pgconn.addDataType("\"public\".\"geometry\"", org.postgis.PGgeometry.class); - pgconn.addDataType("geography", org.postgis.PGgeometry.class); - pgconn.addDataType("public.geography", org.postgis.PGgeometry.class); - pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeometry.class); + pgconn.addDataType("geography", org.postgis.PGgeography.class); + pgconn.addDataType("public.geography", org.postgis.PGgeography.class); + pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeography.class); } - public void addBoxen(Connection conn) throws SQLException { + /** {@inheritDoc} */ + @Override + public void addBoxen(final Connection conn) throws SQLException { PGConnection pgconn = (PGConnection) conn; pgconn.addDataType("box3d", org.postgis.PGbox3d.class); pgconn.addDataType("box2d", org.postgis.PGbox2d.class); } - public void addBinaryGeometries(Connection conn) throws SQLException { + /** {@inheritDoc} */ + @Override + public void addBinaryGeometries(final Connection conn) throws SQLException { PGConnection pgconn = (PGConnection) conn; pgconn.addDataType("geometry", org.postgis.PGgeometryLW.class); - pgconn.addDataType("geography", org.postgis.PGgeometryLW.class); + pgconn.addDataType("geography", org.postgis.PGgeographyLW.class); } } + /** addGISTypes for V7.2 pgjdbc */ protected static class TypesAdder72 extends TypesAdder { - public void addGeometries(Connection conn) throws SQLException { + + /** {@inheritDoc} */ + @Override + public void addGeometries(final Connection conn) throws SQLException { org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn; pgconn.addDataType("geometry", org.postgis.PGgeometry.class); pgconn.addDataType("public.geometry", org.postgis.PGgeometry.class); pgconn.addDataType("\"public\".\"geometry\"", org.postgis.PGgeometry.class); - pgconn.addDataType("geography", org.postgis.PGgeometry.class); - pgconn.addDataType("public.geography", org.postgis.PGgeometry.class); - pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeometry.class); + pgconn.addDataType("geography", org.postgis.PGgeography.class); + pgconn.addDataType("public.geography", org.postgis.PGgeography.class); + pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeography.class); } - public void addBoxen(Connection conn) throws SQLException { + /** {@inheritDoc} */ + @Override + public void addBoxen(final Connection conn) throws SQLException { org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn; pgconn.addDataType("box3d", org.postgis.PGbox3d.class); pgconn.addDataType("box2d", org.postgis.PGbox2d.class); } - public void addBinaryGeometries(Connection conn) throws SQLException { + /** {@inheritDoc} */ + @Override + public void addBinaryGeometries(final Connection conn) throws SQLException { org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn; pgconn.addDataType("geometry", org.postgis.PGgeometryLW.class); - pgconn.addDataType("geography", org.postgis.PGgeometryLW.class); + pgconn.addDataType("geography", org.postgis.PGgeographyLW.class); } } + /** addGISTypes for V8.0 (and hopefully newer) pgjdbc */ protected static class TypesAdder80 extends TypesAdder { - public void addGeometries(Connection conn) throws SQLException { + + /** {@inheritDoc} */ + @Override + public void addGeometries(final Connection conn) throws SQLException { PGConnection pgconn = (PGConnection) conn; pgconn.addDataType("geometry", org.postgis.PGgeometry.class); pgconn.addDataType("public.geometry", org.postgis.PGgeometry.class); @@ -341,20 +375,29 @@ public void addGeometries(Connection conn) throws SQLException { pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeometry.class); } - public void addBoxen(Connection conn) throws SQLException { + /** {@inheritDoc} */ + @Override + public void addBoxen(final Connection conn) throws SQLException { PGConnection pgconn = (PGConnection) conn; pgconn.addDataType("box3d", org.postgis.PGbox3d.class); pgconn.addDataType("box2d", org.postgis.PGbox2d.class); } - public void addBinaryGeometries(Connection conn) throws SQLException { + /** {@inheritDoc} */ + @Override + public void addBinaryGeometries(final Connection conn) throws SQLException { PGConnection pgconn = (PGConnection) conn; pgconn.addDataType("geometry", org.postgis.PGgeometryLW.class); - pgconn.addDataType("geography", org.postgis.PGgeometryLW.class); + pgconn.addDataType("geography", org.postgis.PGgeographyLW.class); } } + + /** {@inheritDoc} */ + @Override public Logger getParentLogger() { throw new UnsupportedOperationException("Not supported yet."); } + + } diff --git a/jdbc/src/main/java/org/postgis/PGgeo.java b/jdbc/src/main/java/org/postgis/PGgeo.java new file mode 100644 index 0000000..e1a2ac3 --- /dev/null +++ b/jdbc/src/main/java/org/postgis/PGgeo.java @@ -0,0 +1,133 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * (C) 2004 Paul Ramsey, pramsey@refractions.net + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com + */ + +package org.postgis; + + +import org.postgis.binary.BinaryParser; +import org.postgresql.util.PGobject; + +import java.sql.SQLException; + + +/** + * A PostgreSQL JDBC PGobject extension data type modeling a "geo" type. + * + * This class serves as a common superclass for classes such as PGgeometry and PGgeography which model + * more specific type semantics. + * + * @author Phillip Ross + */ +public class PGgeo extends PGobject { + + private static final long serialVersionUID = -3181366908975582090L; + + /** The encapsulated geometry. */ + Geometry geometry; + + + /** Instantiate with default state. */ + protected PGgeo() { + } + + + /** + * Instantiate with the specified state. + * + * @param geometry the geometry to instantiate with + */ + public PGgeo(final Geometry geometry) { + this(); + this.geometry = geometry; + } + + + /** + * Instantiate with the specified state. + * + * @param value the value to instantiate with + */ + public PGgeo(final String value) throws SQLException { + this(); + setValue(value); + } + + + /** {@inheritDoc} */ + @Override + public String getValue() { + return geometry.toString(); + } + + + /** {@inheritDoc} */ + @Override + public void setValue(final String value) throws SQLException { + geometry = GeometryBuilder.geomFromString(value, new BinaryParser()); + } + + + /** + * Get the encapsulated geometry. + * + * @return the encapsulated geomtery + */ + public Geometry getGeometry() { + return geometry; + } + + + /** + * Set the encapsulated geometry. + * + * @param geometry the encapsulated geometry + */ + public void setGeometry(final Geometry geometry) { + this.geometry = geometry; + } + + + /** + * Get the type of the encapsulated geometry. + * + * @return the type of the encapsulated geometry + */ + public int getGeoType() { + return geometry.type; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + return geometry.toString(); + } + + + /** {@inheritDoc} */ + @Override + public Object clone() { + return new PGgeo(geometry); + } + + +} diff --git a/jdbc/src/main/java/org/postgis/PGgeography.java b/jdbc/src/main/java/org/postgis/PGgeography.java new file mode 100644 index 0000000..30f5647 --- /dev/null +++ b/jdbc/src/main/java/org/postgis/PGgeography.java @@ -0,0 +1,77 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * (C) 2004 Paul Ramsey, pramsey@refractions.net + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com + */ + +package org.postgis; + + +import java.sql.SQLException; + + +/** + * A PostgreSQL JDBC PGobject extension data type modeling the geography type. + * + * @author Phillip Ross + */ +public class PGgeography extends PGgeo { + + private static final long serialVersionUID = 3796853960196603896L; + + + /** Instantiate with default state. */ + public PGgeography() { + super(); + setType("geography"); + } + + + /** + * Instantiate with the specified state. + * + * @param geometry the geometry to instantiate with + */ + public PGgeography(final Geometry geometry) { + this(); + this.geometry = geometry; + setType("geography"); + } + + + /** + * Instantiate with the specified state. + * + * @param value the value to instantiate with + */ + public PGgeography(final String value) throws SQLException { + this(); + setValue(value); + setType("geography"); + } + + + /** {@inheritDoc} */ + @Override + public Object clone() { + return new PGgeography(geometry); + } + + +} diff --git a/jdbc/src/main/java/org/postgis/PGgeographyLW.java b/jdbc/src/main/java/org/postgis/PGgeographyLW.java new file mode 100644 index 0000000..a64b7d4 --- /dev/null +++ b/jdbc/src/main/java/org/postgis/PGgeographyLW.java @@ -0,0 +1,84 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com + */ + +package org.postgis; + + +import org.postgis.binary.BinaryWriter; + +import java.sql.SQLException; + + +/** + * A PostgreSQL JDBC PGobject extension data type modeling the geography type. + * + * The hex-encoded EWKB format is used to communicate with the backend, which is much more efficient, + * but only works with Lwgeom enabled PostGIS (1.0.0 and up). + * + * @author Phillip Ross + */ +public class PGgeographyLW extends PGgeography { + + private static final long serialVersionUID = 7717856818804158022L; + + /** The binary writer to be used for serializing geometry to a PGobject value. */ + BinaryWriter bw = new BinaryWriter(); + + + /** Instantiate with default state. */ + public PGgeographyLW() { + super(); + } + + /** + * Instantiate with the specified state. + * + * @param geometry the geometry to instantiate with + */ + public PGgeographyLW(final Geometry geometry) { + super(geometry); + } + + + /** + * Instantiate with the specified state. + * + * @param value the value to instantiate with + */ + public PGgeographyLW(final String value) throws SQLException { + super(value); + } + + + /** {@inheritDoc} */ + @Override + public String getValue() { + return bw.writeHexed(geometry); + } + + + /** {@inheritDoc} */ + @Override + public Object clone() { + return new PGgeographyLW(geometry); + } + + +} diff --git a/jdbc/src/main/java/org/postgis/PGgeometry.java b/jdbc/src/main/java/org/postgis/PGgeometry.java index 8f80450..acd96ca 100644 --- a/jdbc/src/main/java/org/postgis/PGgeometry.java +++ b/jdbc/src/main/java/org/postgis/PGgeometry.java @@ -1,14 +1,4 @@ /* - * PGgeometry.java - * - * PostGIS extension for PostgreSQL JDBC driver - PGobject Geometry Wrapper - * - * (C) 2004 Paul Ramsey, pramsey@refractions.net - * - * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com - * - * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com - * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -23,62 +13,63 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + * (C) 2004 Paul Ramsey, pramsey@refractions.net + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com */ package org.postgis; -import org.postgis.binary.BinaryParser; -import org.postgresql.util.PGobject; - import java.sql.SQLException; -public class PGgeometry extends PGobject { - /* JDK 1.5 Serialization */ - private static final long serialVersionUID = 0x100; +/** + * A PostgreSQL JDBC PGobject extension data type modeling the geometry type. + * + * @author Phillip Ross + */ +public class PGgeometry extends PGgeo { + + private static final long serialVersionUID = 4116907189503026815L; - Geometry geom; + /** Instantiate with default state. */ public PGgeometry() { - this.setType("geometry"); + super(); + setType("geometry"); } - public PGgeometry(Geometry geom) { - this(); - this.geom = geom; - } - public PGgeometry(String value) throws SQLException { - this(); - setValue(value); + /** + * Instantiate with the specified state. + * + * @param geometry the geometry to instantiate with + */ + public PGgeometry(final Geometry geometry) { + super(geometry); + setType("geometry"); } - public void setValue(String value) throws SQLException { - geom = GeometryBuilder.geomFromString(value, new BinaryParser()); - } - public Geometry getGeometry() { - return geom; + /** + * Instantiate with the specified state. + * + * @param value the value to instantiate with + */ + public PGgeometry(final String value) throws SQLException { + super(value); + setType("geometry"); } - public void setGeometry(Geometry newgeom) { - this.geom = newgeom; - } - public int getGeoType() { - return geom.type; - } - - public String toString() { - return geom.toString(); + /** {@inheritDoc} */ + @Override + public Object clone() { + return new PGgeometry(geometry); } - public String getValue() { - return geom.toString(); - } - public Object clone() { - return new PGgeometry(geom); - } } diff --git a/jdbc/src/main/java/org/postgis/PGgeometryLW.java b/jdbc/src/main/java/org/postgis/PGgeometryLW.java index 72b3e0e..b66c9fc 100644 --- a/jdbc/src/main/java/org/postgis/PGgeometryLW.java +++ b/jdbc/src/main/java/org/postgis/PGgeometryLW.java @@ -1,12 +1,4 @@ /* - * PGgeometryLW.java - * - * PostGIS extension for PostgreSQL JDBC driver - PGobject LWGeometry Wrapper - * - * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com - * - * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com - * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -20,48 +12,74 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com */ package org.postgis; + import org.postgis.binary.BinaryWriter; import java.sql.SQLException; + /** - * This is a subclas of PGgeometry that uses hex encoded EWKB to communicate - * with the backend, which is much more efficient, but only works with Lwgeom - * enabled PostGIS (1.0.0 and up). + * A PostgreSQL JDBC PGobject extension data type modeling the geometry type. + * + * The hex-encoded EWKB format is used to communicate with the backend, which is much more efficient, + * but only works with Lwgeom enabled PostGIS (1.0.0 and up). + * + * @author Phillip Ross */ - public class PGgeometryLW extends PGgeometry { - /* JDK 1.5 Serialization */ - private static final long serialVersionUID = 0x100; - + + private static final long serialVersionUID = -7774502289413094862L; + + /** The binary writer to be used for serializing geometry to a PGobject value. */ BinaryWriter bw = new BinaryWriter(); + + /** Instantiate with default state. */ public PGgeometryLW() { super(); } - public PGgeometryLW(Geometry geom) { - super(geom); + + /** + * Instantiate with the specified state. + * + * @param geometry the geometry to instantiate with + */ + public PGgeometryLW(final Geometry geometry) { + super(geometry); } - public PGgeometryLW(String value) throws SQLException { + + /** + * Instantiate with the specified state. + * + * @param value the value to instantiate with + */ + public PGgeometryLW(final String value) throws SQLException { super(value); } - public String toString() { - return geom.toString(); - } + /** {@inheritDoc} */ + @Override public String getValue() { - return bw.writeHexed(geom); + return bw.writeHexed(geometry); } + + /** {@inheritDoc} */ + @Override public Object clone() { - return new PGgeometryLW(geom); + return new PGgeometryLW(geometry); } + + } diff --git a/jdbc/src/main/resources/org/postgresql/driverconfig.properties b/jdbc/src/main/resources/org/postgresql/driverconfig.properties index 1e744c1..62ee9e7 100644 --- a/jdbc/src/main/resources/org/postgresql/driverconfig.properties +++ b/jdbc/src/main/resources/org/postgresql/driverconfig.properties @@ -4,5 +4,6 @@ # datatype.geometry=org.postgis.PGgeometry +datatype.geography=org.postgis.PGgeography datatype.box3d=org.postgis.PGbox3d datatype.box2d=org.postgis.PGbox2d diff --git a/jdbc/src/test/java/org/postgis/AutoRegistrationTest.java b/jdbc/src/test/java/org/postgis/AutoRegistrationTest.java deleted file mode 100644 index 8278ebb..0000000 --- a/jdbc/src/test/java/org/postgis/AutoRegistrationTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * AutoRegistrationTest.java - * - * PostGIS extension for PostgreSQL JDBC driver - example and test classes - * - * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -package org.postgis; - - -import net.postgis.tools.testutils.TestContainerController; -import org.postgresql.Driver; -import org.postgresql.util.PGobject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.ITestContext; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import java.sql.*; - - -/** - * This test program tests whether the autoregistration of PostGIS data type within the postgresql jdbc driver was - * successful. It also checks for PostGIS version to know whether box2d is available. - */ -public class AutoRegistrationTest { - - private static final Logger logger = LoggerFactory.getLogger(AutoRegistrationTest.class); - - private Connection connection; - - @Test - public void testAutoRegistration(ITestContext ctx) throws Exception { - logger.debug("Driver version: {}", Driver.getVersion()); - int major = new Driver().getMajorVersion(); - Assert.assertTrue(major >= 8, "postgresql driver " + major + ".X is too old, it does not support auto-registration"); - - Statement statement = connection.createStatement(); - int postgisServerMajor = getPostgisMajor(statement); - logger.debug("PostGIS Version: " + postgisServerMajor); - Assert.assertNotEquals(postgisServerMajor, 0, "Could not get PostGIS version. Is PostGIS really installed in the database?"); - - // Test geometries - ResultSet resultSet = statement.executeQuery("SELECT 'POINT(1 2)'::geometry"); - resultSet.next(); - PGobject result = (PGobject) resultSet.getObject(1); - Assert.assertTrue(result instanceof PGgeometry); - - // Test box3d - resultSet = statement.executeQuery("SELECT 'BOX3D(1 2 3, 4 5 6)'::box3d"); - resultSet.next(); - result = (PGobject) resultSet.getObject(1); - Assert.assertTrue(result instanceof PGbox3d); - - // Test box2d if appropriate - if (postgisServerMajor < 1) { - logger.info("PostGIS version is too old, skipping box2ed test"); - } else { - resultSet = statement.executeQuery("SELECT 'BOX(1 2,3 4)'::box2d"); - resultSet.next(); - result = (PGobject) resultSet.getObject(1); - Assert.assertTrue(result instanceof PGbox2d); - } - } - - - public static int getPostgisMajor(Statement statement) throws SQLException { - ResultSet resultSet = statement.executeQuery("SELECT postgis_version()"); - resultSet.next(); - String version = resultSet.getString(1); - if (version == null) { - throw new SQLException("postgis_version returned NULL!"); - } - version = version.trim(); - int idx = version.indexOf('.'); - return Integer.parseInt(version.substring(0, idx)); - } - - - @BeforeClass - public void initJdbcConnection(ITestContext ctx) throws Exception { - final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); - Assert.assertNotNull(jdbcUrlSuffix); - final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; - final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); - Assert.assertNotNull(jdbcUsername); - final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); - Assert.assertNotNull(jdbcPassword); - connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); - } - - - @AfterClass - public void shutdown() throws Exception { - logger.debug("shutting down"); - if (connection != null) { - connection.close(); - } - } - - -} \ No newline at end of file diff --git a/jdbc/src/test/java/org/postgis/DatatypesAutoRegistrationTest.java b/jdbc/src/test/java/org/postgis/DatatypesAutoRegistrationTest.java new file mode 100644 index 0000000..7f5d4ff --- /dev/null +++ b/jdbc/src/test/java/org/postgis/DatatypesAutoRegistrationTest.java @@ -0,0 +1,144 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com + */ + +package org.postgis; + + +import net.postgis.tools.testutils.TestContainerController; +import org.postgis.util.VersionUtil; +import org.postgresql.Driver; +import org.postgresql.util.PGobject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.ITestContext; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + + +/** + * This test program tests whether the auto-registration of PostGIS data types within the postgresql jdbc driver was + * successful. It also checks for PostGIS version to know whether box2d is available. + */ +public class DatatypesAutoRegistrationTest { + + /** The static logger instance. */ + private static final Logger logger = LoggerFactory.getLogger(DatatypesAutoRegistrationTest.class); + + /** The JDBC Connection to be used for tests. */ + private Connection connection; + + + /** + * Initializes a new JDBC Connection. + * + * @param ctx the test context + * @throws Exception when an exception occurs + */ + @BeforeMethod + public void initJdbcConnection(ITestContext ctx) throws Exception { + logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); + final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); + Assert.assertNotNull(jdbcUrlSuffix); + final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; + final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); + Assert.assertNotNull(jdbcUsername); + final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); + Assert.assertNotNull(jdbcPassword); + connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); + } + + + /** + * Un-allocates the JDBC connection. + * + * @throws Exception when an exception occurs + */ + @AfterMethod + public void shutdown() throws Exception { + logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); + logger.debug("shutting down"); + if (connection != null) { + connection.close(); + } + } + + + @Test + public void testAutoRegistration() throws Exception { + logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); + Driver driver = new Driver(); + int driverMajorVersion = driver.getMajorVersion(); + int driverMinorVersion = driver.getMinorVersion(); + logger.debug("Driver version: {}.{}", driverMajorVersion, driverMinorVersion); + if (driverMajorVersion < 8) { + logger.info( + "postgresql driver {}.{} is too old, it does not support auto-registration", + driverMajorVersion, driverMinorVersion + ); + } else { + int postgisServerMajor = Integer.parseInt(VersionUtil.retrievePostGISServerMajorVersion(connection)); + logger.debug("PostGIS Version: " + postgisServerMajor); + Assert.assertNotEquals( + postgisServerMajor, + 0, + "Could not get PostGIS version. Is PostGIS really installed in the database?" + ); + Statement statement = connection.createStatement(); + + // Test geometries + ResultSet resultSet = statement.executeQuery("SELECT 'POINT(1 2)'::geometry"); + resultSet.next(); + PGobject result = (PGobject) resultSet.getObject(1); + Assert.assertTrue(result instanceof PGgeometry); + + // Test geography + resultSet = statement.executeQuery("SELECT 'POINT(1 2)'::geography"); + resultSet.next(); + Object geographyRawObject = resultSet.getObject(1); + result = (PGobject) resultSet.getObject(1); + Assert.assertTrue(result instanceof PGgeography); + + // Test box3d + resultSet = statement.executeQuery("SELECT 'BOX3D(1 2 3, 4 5 6)'::box3d"); + resultSet.next(); + result = (PGobject) resultSet.getObject(1); + Assert.assertTrue(result instanceof PGbox3d); + + // Test box2d if appropriate + if (postgisServerMajor < 1) { + logger.info("PostGIS version is too old, skipping box2ed test"); + } else { + resultSet = statement.executeQuery("SELECT 'BOX(1 2,3 4)'::box2d"); + resultSet.next(); + result = (PGobject) resultSet.getObject(1); + Assert.assertTrue(result instanceof PGbox2d); + } + } + } + + +} diff --git a/jdbc/src/test/java/org/postgis/DatatypesTest.java b/jdbc/src/test/java/org/postgis/DatatypesTest.java index 4bc8090..284f4f0 100644 --- a/jdbc/src/test/java/org/postgis/DatatypesTest.java +++ b/jdbc/src/test/java/org/postgis/DatatypesTest.java @@ -51,4 +51,13 @@ public void testPGgeometry() throws SQLException { } + @Test + public void testPGgeography() throws SQLException { + logger.trace("void testPGgeography()"); + logger.info(mlng_str); + PGgeography pgf = new PGgeography(mlng_str); + logger.info(pgf.toString()); + } + + } \ No newline at end of file diff --git a/jdbc/src/test/java/org/postgis/EmptyGeometriesTest.java b/jdbc/src/test/java/org/postgis/EmptyGeometriesTest.java index ef7efbb..a321a94 100644 --- a/jdbc/src/test/java/org/postgis/EmptyGeometriesTest.java +++ b/jdbc/src/test/java/org/postgis/EmptyGeometriesTest.java @@ -65,7 +65,8 @@ public class EmptyGeometriesTest { public static final String[] castTypes = new String[] { "bytea", "text", - "geometry" + "geometry", + "geography" }; private Connection connection = null; @@ -83,7 +84,7 @@ public void testSqlStatements() throws SQLException { ResultSet resultSet = preparedStatement.executeQuery() ) { resultSet.next(); - for (int i = 1; i <= 3; i++) { + for (int i = 1; i <= castTypes.length; i++) { Object resultSetObject = resultSet.getObject(i); logger.debug("returned resultSetObject {} => (class=[{}]) {}", i, resultSetObject.getClass().getName(), resultSetObject); } diff --git a/jdbc/src/test/java/org/postgis/GeographyDatatypeTest.java b/jdbc/src/test/java/org/postgis/GeographyDatatypeTest.java new file mode 100644 index 0000000..58ead35 --- /dev/null +++ b/jdbc/src/test/java/org/postgis/GeographyDatatypeTest.java @@ -0,0 +1,260 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com + */ + +package org.postgis; + + +import net.postgis.tools.testutils.TestContainerController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.ITestContext; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.UUID; + + +/** + * Integration tests for PGgeography. + * + * @author Phillip Ross + */ +public class GeographyDatatypeTest { + + /** The static logger instance. */ + private static final Logger logger = LoggerFactory.getLogger(GeographyDatatypeTest.class); + + /** The jdbc url prefix containing the jdbc protocol to be used for tests. */ + private static final String JDBC_URL_PROTOCOL_PREFIX = "jdbc:postgresql"; + + /** The jdbc url prefix containing the jdbc lightweight protocol to be used for tests. */ + private static final String JDBC_URL_LW_PROTOCOL_PREFIX = "jdbc:postgresql_lwgis"; + + /** The prefix for database tables used in the tests. */ + private static final String DATABASE_TABLE_NAME_PREFIX = "jdbc_test"; + + /** Test geometries dataset. */ + public static final String[] testGeometries = new String[] { + "POINT(10 10)", // 2D + "POINT(10 10 0)", // 3D with 3rd coordinate set to 0 + "POINT(10 10 20)", // 3D + "POINT(1e100 1.2345e-100 -2e-5)", // 3D with scientific notation + "POINTM(10 10 20)", // 2D + Measures + "POINT(10 10 20 30)", // 3D + Measures + "MULTIPOINT(11 12, 20 20)", // broken format, see http://lists.jump-project.org/pipermail/jts-devel/2006-April/001572.html + "MULTIPOINT(11 12 13, 20 20 20)", // broken format + "MULTIPOINTM(11 12 13, 20 20 20)", // broken format + "MULTIPOINT(11 12 13 14,20 20 20 20)", // broken format + "MULTIPOINT((11 12), (20 20))", // OGC conforming format + "MULTIPOINT((11 12 13), (20 20 20))", + "MULTIPOINTM((11 12 13), (20 20 20))", + "MULTIPOINT((11 12 13 14),(20 20 20 20))", + "LINESTRING(10 10,20 20,50 50,34 34)", + "LINESTRING(10 10 20,20 20 20,50 50 50,34 34 34)", + "LINESTRINGM(10 10 20,20 20 20,50 50 50,34 34 34)", + "LINESTRING(10 10 20 20,20 20 20 20,50 50 50 50,34 34 34 50)", + "POLYGON((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))", + "POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", + "POLYGONM((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", + "POLYGON((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))", + "MULTIPOLYGON(((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)),((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)))", + "MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", + "MULTIPOLYGONM(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", + "MULTIPOLYGON(((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)),((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)))", + "MULTILINESTRING((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))", + "MULTILINESTRING((10 10 5,20 10 5,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", + "MULTILINESTRINGM((10 10 7,20 10 7,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", + "MULTILINESTRING((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))", + "GEOMETRYCOLLECTION(POINT(10 10),POINT(20 20))", + "GEOMETRYCOLLECTION(POINT(10 10 20),POINT(20 20 20))", + "GEOMETRYCOLLECTION(POINT(10 10 20 7),POINT(20 20 20 7))", + "GEOMETRYCOLLECTION(LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34))", + "GEOMETRYCOLLECTION(POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", + "GEOMETRYCOLLECTION(MULTIPOINT(10 10 10, 20 20 20),MULTIPOINT(10 10 10, 20 20 20))", // Cannot be parsed by 0.X servers, broken format + "GEOMETRYCOLLECTION(MULTIPOINT((10 10 10), (20 20 20)),MULTIPOINT((10 10 10), (20 20 20)))", // Cannot be parsed by 0.X servers, OGC conformant + "GEOMETRYCOLLECTION(MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", // PostGIs 0.X "flattens" this geometry, so it is not equal after reparsing. + "GEOMETRYCOLLECTION(MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))))", // PostGIs 0.X "flattens" this geometry, so it is not equal after reparsing. + "GEOMETRYCOLLECTION(POINT(10 10 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", + "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT(10 10 10, 20 20 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", // Collections that contain both X and MultiX do not work on PostGIS 0.x, broken format + "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT((10 10 10), (20 20 20)),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", // Collections that contain both X and MultiX do not work on PostGIS 0.x, OGC conformant + "GEOMETRYCOLLECTION EMPTY", // new (correct) representation + "GEOMETRYCOLLECTIONM(POINTM(10 10 20),POINTM(20 20 20))" + }; + + /** The JDBC Connection to be used for tests. */ + private Connection connection = null; + + /** The JDBC Connection w/ lightweight protocol to be used for tests. */ + private Connection connectionLW = null; + + + /** + * Initializes a new JDBC Connection. + * + * @param ctx the test context + * @throws Exception when an exception occurs + */ + @BeforeMethod + public void initJdbcConnection(ITestContext ctx) throws Exception { + final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); + Assert.assertNotNull(jdbcUrlSuffix); + final String jdbcUrl = JDBC_URL_PROTOCOL_PREFIX + jdbcUrlSuffix; + final String jdbcUrlLW = JDBC_URL_LW_PROTOCOL_PREFIX + jdbcUrlSuffix; + final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); + Assert.assertNotNull(jdbcUsername); + final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); + Assert.assertNotNull(jdbcPassword); + Class.forName("org.postgis.DriverWrapperLW"); + connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); + connectionLW = DriverManager.getConnection(jdbcUrlLW, jdbcUsername, jdbcPassword); + } + + + /** + * Un-allocates the JDBC connection. + * + * @throws Exception when an exception occurs + */ + @AfterMethod + public void unallocateDatabaseResources() throws Exception { + if ((connection != null) && (!connection.isClosed())) { + connection.close(); + } + if ((connectionLW != null) && (!connectionLW.isClosed())) { + connection.close(); + } + } + + + /** + * Test inserting geometries into the database with prepared statements and querying back the results with + * both geometry/geography and standard/lightweight. + * + * @throws Exception when an exception occurs. + */ + @Test + public void testDatatypes() throws Exception { + + final String testTableName = DATABASE_TABLE_NAME_PREFIX + + "_" + + UUID.randomUUID() + .toString() + .replaceAll("-", ""); + + final String dropTableSQL = "drop table " + testTableName; + + final String createTableSQL = "create table " + testTableName + + " ( _id numeric," + + " geometry_value geometry, geometrylw_value geometry," + + " geography_value geography, geographylw_value geography)"; + final int idColumnIndex = 1; + final int geometryValueColumnIndex = 2; + final int geometrylwValueColumnIndex = 3; + final int geographyValueColumnIndex = 4; + final int geographylwValueColumnIndex = 5; + + final String insertSQL = "insert into " + testTableName + " ( " + + "_id, geometry_value, geometrylw_value, " + + "geography_value, geographylw_value) " + + "values ( ?, ?, ?, ?, ? )"; + + boolean tableExists = false; + DatabaseMetaData databaseMetaData = connection.getMetaData(); + try ( + ResultSet resultSet = databaseMetaData.getTables( + null, null, testTableName.toLowerCase(), new String[] { "TABLE" } + ) + ) { + while (resultSet.next()) { + tableExists = true; + } + } + + if (tableExists) { + logger.debug("Dropping pre-existing test table..."); + try (Statement statement = connection.createStatement()) { + statement.executeQuery(dropTableSQL); + } + } + + logger.debug("Creating test table..."); + try (Statement statement = connection.createStatement()) { + statement.execute(createTableSQL); + } + + + logger.debug("Inserting test geometries into table..."); + try (PreparedStatement preparedStatement = connection.prepareStatement(insertSQL)) { + for (int i = 0; i < testGeometries.length; i++) { + PGgeometry geometry = new PGgeometry(testGeometries[i]); + PGgeometryLW geometryLW = new PGgeometryLW(testGeometries[i]); + PGgeography geography = new PGgeography(testGeometries[i]); + PGgeographyLW geographyLW = new PGgeographyLW(testGeometries[i]); + + preparedStatement.setInt(idColumnIndex, i); + preparedStatement.setObject(geometryValueColumnIndex, geometry); + preparedStatement.setObject(geometrylwValueColumnIndex, geometryLW); + preparedStatement.setObject(geographyValueColumnIndex, geography); + preparedStatement.setObject(geographylwValueColumnIndex, geographyLW); + preparedStatement.executeUpdate(); + } + } + + logger.debug("Querying table with standard connection..."); + try ( + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "select _id, geometry_value, geometrylw_value, geography_value, geographylw_value from " + + testTableName + ) + ) { + while (resultSet.next()) { + Assert.assertEquals(resultSet.getObject(geometryValueColumnIndex).getClass(), PGgeometry.class); + Assert.assertEquals(resultSet.getObject(geometrylwValueColumnIndex).getClass(), PGgeometry.class); + Assert.assertEquals(resultSet.getObject(geographyValueColumnIndex).getClass(), PGgeography.class); + Assert.assertEquals(resultSet.getObject(geographylwValueColumnIndex).getClass(), PGgeography.class); + } + } + + logger.debug("Querying table with lightweight connection..."); + try ( + Statement statement = connectionLW.createStatement(); + ResultSet resultSet = statement.executeQuery( + "select _id, geometry_value, geometrylw_value, geography_value, geographylw_value from " + + testTableName + ) + ) { + while (resultSet.next()) { + Assert.assertEquals(resultSet.getObject(geometryValueColumnIndex).getClass(), PGgeometryLW.class); + Assert.assertEquals(resultSet.getObject(geometrylwValueColumnIndex).getClass(), PGgeometryLW.class); + Assert.assertEquals(resultSet.getObject(geographyValueColumnIndex).getClass(), PGgeographyLW.class); + Assert.assertEquals(resultSet.getObject(geographylwValueColumnIndex).getClass(), PGgeographyLW.class); + } + } + } + + +} \ No newline at end of file diff --git a/jdbc/src/test/resources-filtered/testng-it.xml b/jdbc/src/test/resources-filtered/testng-it.xml index 5097955..dae6101 100644 --- a/jdbc/src/test/resources-filtered/testng-it.xml +++ b/jdbc/src/test/resources-filtered/testng-it.xml @@ -11,9 +11,10 @@ - + + diff --git a/postgis-geometry/src/test/resources/testng.xml b/postgis-geometry/src/test/resources/testng.xml index 4a55e81..0169ee0 100644 --- a/postgis-geometry/src/test/resources/testng.xml +++ b/postgis-geometry/src/test/resources/testng.xml @@ -1,7 +1,7 @@ - +