| // SPDX-License-Identifier: LGPL-2.1-or-later |
| // Copyright (c) 2012-2014 Monty Program Ab |
| // Copyright (c) 2015-2021 MariaDB Corporation Ab |
| |
| package org.mariadb.jdbc.integration.codec; |
| |
| import static org.junit.jupiter.api.Assertions.*; |
| |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.sql.*; |
| import org.junit.jupiter.api.AfterAll; |
| import org.junit.jupiter.api.Assumptions; |
| import org.junit.jupiter.api.BeforeAll; |
| import org.junit.jupiter.api.Test; |
| import org.mariadb.jdbc.Statement; |
| import org.mariadb.jdbc.client.result.CompleteResult; |
| import org.mariadb.jdbc.type.*; |
| import org.mariadb.jdbc.util.constants.Capabilities; |
| |
| public class MultiPolygonCodecTest extends CommonCodecTest { |
| public static org.mariadb.jdbc.Connection geoConn; |
| private final MultiPolygon ls1 = |
| new MultiPolygon( |
| new Polygon[] { |
| new Polygon( |
| new LineString[] { |
| new LineString( |
| new Point[] { |
| new Point(1, 1), |
| new Point(1, 5), |
| new Point(4, 9), |
| new Point(6, 9), |
| new Point(9, 3), |
| new Point(7, 2), |
| new Point(1, 1) |
| }, |
| false), |
| }), |
| new Polygon( |
| new LineString[] { |
| new LineString( |
| new Point[] { |
| new Point(0, 0), |
| new Point(50, 0), |
| new Point(50, 50), |
| new Point(0, 50), |
| new Point(0, 0) |
| }, |
| false), |
| new LineString( |
| new Point[] { |
| new Point(10, 10), |
| new Point(20, 10), |
| new Point(20, 20), |
| new Point(10, 20), |
| new Point(10, 10) |
| }, |
| false) |
| }) |
| }); |
| private final MultiPolygon ls2 = |
| new MultiPolygon( |
| new Polygon[] { |
| new Polygon( |
| new LineString[] { |
| new LineString( |
| new Point[] { |
| new Point(1, 1), |
| new Point(1, 8), |
| new Point(4, 9), |
| new Point(6, 9), |
| new Point(9, 3), |
| new Point(7, 2), |
| new Point(1, 1) |
| }, |
| false), |
| }) |
| }); |
| |
| private final MultiPolygon ls3 = |
| new MultiPolygon( |
| new Polygon[] { |
| new Polygon( |
| new LineString[] { |
| new LineString( |
| new Point[] { |
| new Point(0, 0), |
| new Point(50, 0), |
| new Point(50, 50), |
| new Point(0, 50), |
| new Point(0, 0) |
| }, |
| false), |
| new LineString( |
| new Point[] { |
| new Point(10, 10), |
| new Point(20, 10), |
| new Point(20, 20), |
| new Point(10, 20), |
| new Point(10, 10) |
| }, |
| false) |
| }) |
| }); |
| |
| @AfterAll |
| public static void drop() throws SQLException { |
| Statement stmt = sharedConn.createStatement(); |
| stmt.execute("DROP TABLE IF EXISTS MultiPolygonCodec"); |
| stmt.execute("DROP TABLE IF EXISTS MultiPolygonCodec2"); |
| if (geoConn != null) geoConn.close(); |
| } |
| |
| @BeforeAll |
| public static void beforeAll2() throws Exception { |
| drop(); |
| // xpand doesn't recognized MultiPolygon |
| Assumptions.assumeFalse(isXpand()); |
| |
| Statement stmt = sharedConn.createStatement(); |
| stmt.execute( |
| "CREATE TABLE MultiPolygonCodec (t1 MultiPolygon, t2 MultiPolygon, t3 MultiPolygon, t4" |
| + " MultiPolygon)"); |
| stmt.execute( |
| "INSERT INTO MultiPolygonCodec VALUES (ST_MPolyFromText('MULTIPOLYGON(((1 1, 1 5,4 9,6 9,9" |
| + " 3,7 2, 1 1)), ((0 0, 50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10 20,10 10)))')," |
| + " ST_MPolyFromText('MULTIPOLYGON(((1 1, 1 8,4 9,6 9,9 3,7 2, 1 1)))')," |
| + " ST_MPolyFromText('MULTIPOLYGON(((0 0, 50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10" |
| + " 20,10 10)))'), null)"); |
| stmt.execute( |
| "CREATE TABLE MultiPolygonCodec2 (id int not null primary key auto_increment, t1" |
| + " MultiPolygon)"); |
| stmt.execute("FLUSH TABLES"); |
| |
| String binUrl = |
| mDefUrl + (mDefUrl.indexOf("?") > 0 ? "&" : "?") + "geometryDefaultType=default"; |
| geoConn = (org.mariadb.jdbc.Connection) DriverManager.getConnection(binUrl); |
| } |
| |
| private ResultSet get() throws SQLException { |
| Statement stmt = sharedConn.createStatement(); |
| stmt.execute("START TRANSACTION"); // if MAXSCALE ensure using WRITER |
| ResultSet rs = |
| stmt.executeQuery( |
| "select t1 as t1alias, t2 as t2alias, t3 as t3alias, t4 as t4alias from" |
| + " MultiPolygonCodec"); |
| assertTrue(rs.next()); |
| sharedConn.commit(); |
| return rs; |
| } |
| |
| private CompleteResult getPrepare(org.mariadb.jdbc.Connection con) throws SQLException { |
| java.sql.Statement stmt = con.createStatement(); |
| stmt.execute("START TRANSACTION"); // if MAXSCALE ensure using WRITER |
| PreparedStatement preparedStatement = |
| con.prepareStatement( |
| "select t1 as t1alias, t2 as t2alias, t3 as t3alias, t4 as t4alias from" |
| + " MultiPolygonCodec WHERE 1 > ?"); |
| preparedStatement.closeOnCompletion(); |
| preparedStatement.setInt(1, 0); |
| CompleteResult rs = (CompleteResult) preparedStatement.executeQuery(); |
| assertTrue(rs.next()); |
| con.commit(); |
| return rs; |
| } |
| |
| @Test |
| public void getObject() throws Exception { |
| getObject(get(), false); |
| } |
| |
| @Test |
| public void getObjectPrepare() throws Exception { |
| getObject(getPrepare(sharedConn), false); |
| getObject(getPrepare(sharedConnBinary), false); |
| getObject(getPrepare(geoConn), true); |
| } |
| |
| public void getObject(ResultSet rs, boolean defaultGeo) throws SQLException { |
| if (defaultGeo && hasCapability(Capabilities.EXTENDED_TYPE_INFO)) { |
| assertEquals(ls1, rs.getObject(1)); |
| assertFalse(rs.wasNull()); |
| assertEquals(ls2, rs.getObject(2)); |
| assertFalse(rs.wasNull()); |
| assertEquals(ls3, rs.getObject(3)); |
| assertFalse(rs.wasNull()); |
| assertNull(rs.getObject(4)); |
| assertTrue(rs.wasNull()); |
| } else { |
| assertEquals(ls1, rs.getObject(1, MultiPolygon.class)); |
| assertFalse(rs.wasNull()); |
| assertEquals(ls2, rs.getObject(2, MultiPolygon.class)); |
| assertFalse(rs.wasNull()); |
| assertEquals(ls3, rs.getObject(3, MultiPolygon.class)); |
| assertFalse(rs.wasNull()); |
| assertNull(rs.getObject(4)); |
| assertTrue(rs.wasNull()); |
| } |
| } |
| |
| @Test |
| public void getObjectType() throws Exception { |
| getObjectType(get()); |
| } |
| |
| @Test |
| public void getObjectTypePrepare() throws Exception { |
| getObjectType(getPrepare(sharedConn)); |
| getObjectType(getPrepare(sharedConnBinary)); |
| } |
| |
| private static int toDigit(char hexChar) { |
| int digit = Character.digit(hexChar, 16); |
| if (digit == -1) { |
| throw new IllegalArgumentException("Invalid Hexadecimal Character: " + hexChar); |
| } |
| return digit; |
| } |
| |
| public static byte hexToByte(String hexString) { |
| int firstDigit = toDigit(hexString.charAt(0)); |
| int secondDigit = toDigit(hexString.charAt(1)); |
| return (byte) ((firstDigit << 4) + secondDigit); |
| } |
| |
| public static byte[] decodeHexString(String hexString) { |
| if (hexString.length() % 2 == 1) { |
| throw new IllegalArgumentException("Invalid hexadecimal String supplied."); |
| } |
| |
| byte[] bytes = new byte[hexString.length() / 2]; |
| for (int i = 0; i < hexString.length(); i += 2) { |
| bytes[i / 2] = hexToByte(hexString.substring(i, i + 2)); |
| } |
| return bytes; |
| } |
| |
| public void getObjectType(ResultSet rs) throws Exception { |
| testErrObject(rs, Integer.class, 1); |
| testErrObject(rs, String.class, 1); |
| testErrObject(rs, Long.class, 1); |
| testErrObject(rs, Short.class, 1); |
| testErrObject(rs, BigDecimal.class, 1); |
| testErrObject(rs, BigInteger.class, 1); |
| testErrObject(rs, Double.class, 1); |
| testErrObject(rs, Float.class, 1); |
| testErrObject(rs, Byte.class, 1); |
| String hexa = |
| "0000000001060000000200000001030000000100000007000000000000000000F03F000000000000F03F000000000000F03F00000000000014400000000000001040000000000000224000000000000018400000000000002240000000000000224000000000000008400000000000001C400000000000000040000000000000F03F000000000000F03F010300000002000000050000000000000000000000000000000000000000000000000049400000000000000000000000000000494000000000000049400000000000000000000000000000494000000000000000000000000000000000050000000000000000002440000000000000244000000000000034400000000000002440000000000000344000000000000034400000000000002440000000000000344000000000000024400000000000002440"; |
| testArrObject(rs, decodeHexString(hexa), 1); |
| |
| testErrObject(rs, Boolean.class, 1); |
| testErrObject(rs, Clob.class, 1); |
| testErrObject(rs, NClob.class, 1); |
| testErrObject(rs, InputStream.class, 1); |
| testErrObject(rs, Reader.class, 1); |
| testErrObject(rs, java.util.Date.class, 1); |
| } |
| |
| @Test |
| public void getMetaData() throws SQLException { |
| getMetaData(sharedConn, false); |
| try (org.mariadb.jdbc.Connection con = createCon("geometryDefaultType=default")) { |
| getMetaData(con, true); |
| } |
| } |
| |
| private void getMetaData(org.mariadb.jdbc.Connection con, boolean geoDefault) |
| throws SQLException { |
| ResultSet rs = getPrepare(con); |
| ResultSetMetaData meta = rs.getMetaData(); |
| if (hasCapability(Capabilities.EXTENDED_TYPE_INFO)) { |
| assertEquals("MULTIPOLYGON", meta.getColumnTypeName(1)); |
| } else { |
| assertEquals("GEOMETRY", meta.getColumnTypeName(1)); |
| } |
| assertEquals(sharedConn.getCatalog(), meta.getCatalogName(1)); |
| assertEquals( |
| geoDefault |
| ? (hasCapability(Capabilities.EXTENDED_TYPE_INFO) |
| ? MultiPolygon.class.getName() |
| : GeometryCollection.class.getName()) |
| : "byte[]", |
| meta.getColumnClassName(1)); |
| assertEquals("t1alias", meta.getColumnLabel(1)); |
| assertEquals("t1", meta.getColumnName(1)); |
| assertEquals(Types.VARBINARY, meta.getColumnType(1)); |
| assertEquals(4, meta.getColumnCount()); |
| assertEquals(0, meta.getScale(1)); |
| assertEquals("", meta.getSchemaName(1)); |
| } |
| |
| @Test |
| public void sendParam() throws Exception { |
| sendParam(sharedConn); |
| sendParam(sharedConnBinary); |
| } |
| |
| private void sendParam(Connection con) throws Exception { |
| java.sql.Statement stmt = con.createStatement(); |
| stmt.execute("TRUNCATE TABLE MultiPolygonCodec2"); |
| stmt.execute("START TRANSACTION"); // if MAXSCALE ensure using WRITER |
| try (PreparedStatement prep = |
| con.prepareStatement("INSERT INTO MultiPolygonCodec2(t1) VALUES (?)")) { |
| prep.setObject(1, ls1); |
| prep.execute(); |
| prep.setObject(1, (MultiPolygon) null); |
| prep.execute(); |
| |
| prep.setObject(1, ls2); |
| prep.addBatch(); |
| prep.setObject(1, ls1); |
| prep.addBatch(); |
| prep.executeBatch(); |
| } |
| |
| ResultSet rs = |
| con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE) |
| .executeQuery("SELECT * FROM MultiPolygonCodec2"); |
| assertTrue(rs.next()); |
| assertEquals(ls1, rs.getObject(2, MultiPolygon.class)); |
| rs.updateNull(2); |
| rs.updateRow(); |
| assertNull(rs.getObject(2, MultiPolygon.class)); |
| |
| assertTrue(rs.next()); |
| assertNull(rs.getObject(2, MultiPolygon.class)); |
| rs.updateObject(2, ls2); |
| rs.updateRow(); |
| assertEquals(ls2, rs.getObject(2, MultiPolygon.class)); |
| assertTrue(rs.next()); |
| |
| assertEquals(ls2, rs.getObject(2, MultiPolygon.class)); |
| assertTrue(rs.next()); |
| assertEquals(ls1, rs.getObject(2, MultiPolygon.class)); |
| con.commit(); |
| } |
| |
| @Test |
| public void equal() { |
| assertEquals(ls1, ls1); |
| MultiPolygon testPoly = |
| new MultiPolygon( |
| new Polygon[] { |
| new Polygon( |
| new LineString[] { |
| new LineString( |
| new Point[] { |
| new Point(1, 1), |
| new Point(1, 5), |
| new Point(4, 9), |
| new Point(6, 9), |
| new Point(9, 3), |
| new Point(7, 2), |
| new Point(1, 1) |
| }, |
| false), |
| }), |
| new Polygon( |
| new LineString[] { |
| new LineString( |
| new Point[] { |
| new Point(0, 0), |
| new Point(50, 0), |
| new Point(50, 50), |
| new Point(0, 50), |
| new Point(0, 0) |
| }, |
| false), |
| new LineString( |
| new Point[] { |
| new Point(10, 10), |
| new Point(20, 10), |
| new Point(20, 20), |
| new Point(10, 20), |
| new Point(10, 10) |
| }, |
| false) |
| }) |
| }); |
| assertEquals(testPoly, ls1); |
| assertEquals(testPoly.hashCode(), ls1.hashCode()); |
| assertFalse(ls1.equals(null)); |
| assertFalse(ls1.equals("")); |
| assertNotEquals( |
| new MultiPolygon( |
| new Polygon[] { |
| new Polygon( |
| new LineString[] { |
| new LineString( |
| new Point[] { |
| new Point(1, 1), |
| new Point(1, 5), |
| new Point(4, 9), |
| new Point(6, 9), |
| new Point(9, 3), |
| new Point(7, 2), |
| new Point(1, 1) |
| }, |
| false), |
| }), |
| new Polygon( |
| new LineString[] { |
| new LineString( |
| new Point[] { |
| new Point(0, 0), |
| new Point(50, 0), |
| new Point(50, 50), |
| new Point(0, 50), |
| new Point(0, 0) |
| }, |
| false), |
| new LineString( |
| new Point[] { |
| new Point(10, 10), |
| new Point(20, 10), |
| new Point(20, 20), |
| new Point(10, 20), |
| new Point(10, 15) |
| }, |
| false) |
| }) |
| }), |
| ls1); |
| } |
| } |