From c290bfeffcdac02c7ea53b59e363f23cfdcc5062 Mon Sep 17 00:00:00 2001 From: Markus Lutum Date: Wed, 1 Jul 2020 11:18:43 +0200 Subject: [PATCH 01/30] Reproduce issue with polish chars and set maxFieldSize --- .../java/org/mariadb/jdbc/StringUTFTest.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/test/java/org/mariadb/jdbc/StringUTFTest.java diff --git a/src/test/java/org/mariadb/jdbc/StringUTFTest.java b/src/test/java/org/mariadb/jdbc/StringUTFTest.java new file mode 100644 index 000000000..53fb046c3 --- /dev/null +++ b/src/test/java/org/mariadb/jdbc/StringUTFTest.java @@ -0,0 +1,91 @@ +/* + * + * MariaDB Client for Java + * + * Copyright (c) 2012-2014 Monty Program Ab. + * Copyright (c) 2015-2020 MariaDB Corporation Ab. + * + * 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 Monty Program Ab info@montyprogram.com. + * + * This particular MariaDB Client for Java file is work + * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to + * the following copyright and notice provisions: + * + * Copyright (c) 2009-2011, Marcus Eriksson + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * Neither the name of the driver nor the names of its contributors may not be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package org.mariadb.jdbc; + +import static org.junit.Assert.*; + +import java.sql.*; +import org.junit.BeforeClass; +import org.junit.Test; + +public class StringUTFTest extends BaseTest { + + /** + * Initialization. + * + * @throws SQLException exception + */ + @BeforeClass() + public static void initClass() throws SQLException { + createTable( + "stringutftest", + "id int not null primary key auto_increment, stringutf varchar(40)", + "COLLATE='utf8_general_ci'"); + } + + @Test + public void testString() throws SQLException { + PreparedStatement ps = + sharedConnection.prepareStatement("insert into stringutftest values(null, ?)"); + ps.setString(1, "śćżźęąółń"); + ps.execute(); + Statement stmt = sharedConnection.createStatement(); + stmt.setMaxFieldSize(40); + ResultSet rs = stmt.executeQuery("select * from stringutftest"); + if (rs.next()) { + assertEquals("śćżźęąółń", rs.getString(2)); + } else { + fail("must have a result !"); + } + } +} From f2cfbaa66d60a2df1a126ba286058329a788367e Mon Sep 17 00:00:00 2001 From: Shahmir Noorani Date: Wed, 5 Aug 2020 16:54:14 -0500 Subject: [PATCH 02/30] Fix - setConfiguration not being called on classes that extend ConfigurableSocketFactory --- src/main/java/org/mariadb/jdbc/internal/util/Utils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/mariadb/jdbc/internal/util/Utils.java b/src/main/java/org/mariadb/jdbc/internal/util/Utils.java index 75d4240f6..9d35b1fab 100644 --- a/src/main/java/org/mariadb/jdbc/internal/util/Utils.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/Utils.java @@ -133,7 +133,7 @@ public static Socket standardSocket(Options options, String host) throws IOExcep if (socketFactoryClass != null) { Constructor constructor = socketFactoryClass.getConstructor(); socketFactory = constructor.newInstance(); - if (socketFactoryClass.isInstance(ConfigurableSocketFactory.class)) { + if (ConfigurableSocketFactory.class.isInstance(socketFactory)) { ((ConfigurableSocketFactory) socketFactory).setConfiguration(options, host); } return socketFactory.createSocket(); From e762851117ba9a9b4dae1b6d70463855ab8f78ba Mon Sep 17 00:00:00 2001 From: Qianqian Bu Date: Tue, 11 Aug 2020 16:08:21 +0800 Subject: [PATCH 03/30] for-CONJ-742-and-CONJ-807, add Driver.class.getClassLoader() can solve squirrel problem. But static introduce access denied --- .../jdbc/authentication/AuthenticationPluginLoader.java | 6 +++--- .../org/mariadb/jdbc/credential/CredentialPluginLoader.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/authentication/AuthenticationPluginLoader.java b/src/main/java/org/mariadb/jdbc/authentication/AuthenticationPluginLoader.java index f4b074d1b..823e523c0 100644 --- a/src/main/java/org/mariadb/jdbc/authentication/AuthenticationPluginLoader.java +++ b/src/main/java/org/mariadb/jdbc/authentication/AuthenticationPluginLoader.java @@ -28,9 +28,6 @@ public class AuthenticationPluginLoader { - private static ServiceLoader loader = - ServiceLoader.load(AuthenticationPlugin.class, Driver.class.getClassLoader()); - /** * Get authentication plugin from type String. Customs authentication plugin can be added * implementing AuthenticationPlugin and registering new type in resources services. @@ -44,6 +41,9 @@ public static AuthenticationPlugin get(String type) throws SQLException { return null; } + ServiceLoader loader = + ServiceLoader.load(AuthenticationPlugin.class, Driver.class.getClassLoader()); + for (AuthenticationPlugin implClass : loader) { if (type.equals(implClass.type())) { return implClass; diff --git a/src/main/java/org/mariadb/jdbc/credential/CredentialPluginLoader.java b/src/main/java/org/mariadb/jdbc/credential/CredentialPluginLoader.java index 42cbca23d..6dbb64217 100644 --- a/src/main/java/org/mariadb/jdbc/credential/CredentialPluginLoader.java +++ b/src/main/java/org/mariadb/jdbc/credential/CredentialPluginLoader.java @@ -31,9 +31,6 @@ */ public class CredentialPluginLoader { - private static ServiceLoader loader = - ServiceLoader.load(CredentialPlugin.class, Driver.class.getClassLoader()); - /** * Get current Identity plugin according to option `identityType`. * @@ -46,6 +43,9 @@ public static CredentialPlugin get(String type) throws SQLException { return null; } + ServiceLoader loader = + ServiceLoader.load(CredentialPlugin.class, Driver.class.getClassLoader()); + for (CredentialPlugin implClass : loader) { if (type.equals(implClass.type())) { return implClass; From 88189ffcbb01d63f1c0ba7d0ffe4605ad889ddd1 Mon Sep 17 00:00:00 2001 From: Markus Lutum Date: Wed, 1 Jul 2020 11:20:07 +0200 Subject: [PATCH 04/30] [CONJ-805] fix StringIndexOutOfBoundsException for >1 byte UTF8 characters and maxFieldSize set --- .../com/read/resultset/rowprotocol/TextRowProtocol.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java index 7e4c7c94b..b9142fdee 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java @@ -234,8 +234,7 @@ public String getInternalString(ColumnDefinition columnInfo, Calendar cal, TimeZ } if (maxFieldSize > 0) { - return new String(buf, pos, Math.min(maxFieldSize * 3, length), StandardCharsets.UTF_8) - .substring(0, Math.min(maxFieldSize, length)); + return new String(buf, pos, Math.min(maxFieldSize, length), StandardCharsets.UTF_8); } return new String(buf, pos, length, StandardCharsets.UTF_8); From e00a351d929624dfa2dd15b9d0a7a59ecd5f63bf Mon Sep 17 00:00:00 2001 From: rusher Date: Wed, 19 Aug 2020 10:27:09 +0200 Subject: [PATCH 05/30] [misc] SkySQL testing --- .travis/script.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis/script.sh b/.travis/script.sh index f120707b6..cecd472fc 100644 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -8,14 +8,15 @@ set -e ################################################################################################################### if [ -n "$SKYSQL" ] ; then - if [ -z "$SKYSQL_TEST_HOST" ] ; then + if [ -z "$SKYSQL_HOST" ] ; then echo "No SkySQL configuration found !" exit 0 - fi - testSingleHost=true - urlString="jdbc:mariadb://$SKYSQL_TEST_HOST:$SKYSQL_TEST_PORT/testj?user=$SKYSQL_TEST_USER&password=$SKYSQL_TEST_PASSWORD&enablePacketDebug=true&useSsl&serverSslCert=$SKYSQL_TEST_SSL_CA" + else + testSingleHost=true + urlString="jdbc:mariadb://$SKYSQL_HOST:$SKYSQL_PORT/testj?user=$SKYSQL_USER&password=$SKYSQL_PASSWORD&enablePacketDebug=true&useSsl&serverSslCert=$SKYSQL_SSL_CA" - cmd=( mvn clean test $ADDITIONNAL_VARIABLES -DjobId=${TRAVIS_JOB_ID} ) + cmd=( mvn clean test $ADDITIONNAL_VARIABLES -DjobId=${TRAVIS_JOB_ID} ) + fi else case "$TYPE" in From 25cae561add86eaf069298fb0fa1a3dfa4b56a1f Mon Sep 17 00:00:00 2001 From: rusher Date: Wed, 19 Aug 2020 11:16:10 +0200 Subject: [PATCH 06/30] [misc] suppress warning --- src/main/java/org/mariadb/jdbc/internal/io/LruTraceCache.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/mariadb/jdbc/internal/io/LruTraceCache.java b/src/main/java/org/mariadb/jdbc/internal/io/LruTraceCache.java index c2ae52c01..d59a23907 100644 --- a/src/main/java/org/mariadb/jdbc/internal/io/LruTraceCache.java +++ b/src/main/java/org/mariadb/jdbc/internal/io/LruTraceCache.java @@ -96,6 +96,7 @@ public synchronized String printStack() { boolean finished = false; while (!finished) { try { + @SuppressWarnings("unchecked") Map.Entry[] arr = entrySet().toArray((Map.Entry[]) new Map.Entry[0]); for (Map.Entry entry : arr) { From 87bf787d3f664c33dc87bd35aaff8848af0eb181 Mon Sep 17 00:00:00 2001 From: rusher Date: Wed, 19 Aug 2020 16:18:57 +0200 Subject: [PATCH 07/30] [CONJ-820] PreparedStatement.setObject doesn't support java.lang.Character type --- .../mariadb/jdbc/BasePrepareStatement.java | 7 +- .../jdbc/ServerPrepareStatementTest.java | 79 +++++++++++++++++++ 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java index 525133ccc..6de42de3b 100644 --- a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java +++ b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java @@ -965,11 +965,12 @@ private void setInternalObject( if (obj == null) { setNull(parameterIndex, Types.INTEGER); - } else if (obj instanceof String) { + } else if (obj instanceof String || obj instanceof Character) { if (targetSqlType == Types.BLOB) { - throw exceptionFactory.create("Cannot convert a String to a Blob"); + throw exceptionFactory.create(String.format("Cannot convert a %s to a Blob", obj instanceof String ? + "string" : "character")); } - String str = (String) obj; + String str = obj instanceof String ? (String) obj : ((Character) obj).toString(); try { switch (targetSqlType) { case Types.BIT: diff --git a/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java b/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java index 5e5ab9cdf..97429f9a6 100644 --- a/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java +++ b/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java @@ -666,6 +666,85 @@ public void blobTest() throws Throwable { } } + @Test + public void characterObjectSupport() throws Throwable { + Statement stmt = sharedConnection.createStatement(); + stmt.execute("CREATE TEMPORARY TABLE temp_character (v varchar(10) ) "); + + try (PreparedStatement ps = sharedConnection.prepareStatement("INSERT INTO temp_character(v) VALUES (?)")) { + ps.setObject(1, 'c', Types.CHAR); + ps.addBatch(); + ps.setObject(1, 'd', Types.VARCHAR); + ps.addBatch(); + ps.setObject(1, new Character('e'), Types.CHAR); + ps.addBatch(); + ps.setObject(1, new Character('f'), Types.VARCHAR); + ps.addBatch(); + ps.setObject(1, '1', Types.INTEGER); + ps.addBatch(); + ps.setObject(1, '2', Types.TINYINT); + ps.addBatch(); + ps.setObject(1, '3', Types.SMALLINT); + ps.addBatch(); + ps.setObject(1, '4', Types.DOUBLE); + ps.addBatch(); + ps.setObject(1, '5', Types.BIGINT); + ps.addBatch(); + ps.setObject(1, '6', Types.DECIMAL); + ps.addBatch(); + ps.setObject(1, '7', Types.NUMERIC); + ps.addBatch(); + ps.setObject(1, '0', Types.BOOLEAN); + ps.addBatch(); + ps.setObject(1, '1', Types.BOOLEAN); + ps.addBatch(); + ps.setObject(1, '2', Types.BOOLEAN); + ps.addBatch(); + ps.setObject(1, null, Types.CHAR); + ps.addBatch(); + try { + ps.setObject(1, '2', Types.BLOB); + fail(); + } catch (SQLException e) { + e.getMessage().contains("Cannot convert a character to a Blob"); + } + + ps.executeBatch(); + } + ResultSet rs = stmt.executeQuery("SELECT * FROM temp_character"); + assertTrue(rs.next()); + assertEquals("c", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("d", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("e", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("f", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("1", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("2", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("3", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("4.0", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("5", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("6", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("7", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("0", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("1", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("1", rs.getString(1)); + assertTrue(rs.next()); + assertNull(rs.getString(1)); + assertFalse(rs.next()); + } + @Test public void readerTest() throws Throwable { try (Connection connection = setConnection("&prepStmtCacheSize=10")) { From 3c8452e795313aa4b397a0846f1749afa834d893 Mon Sep 17 00:00:00 2001 From: rusher Date: Wed, 19 Aug 2020 16:40:25 +0200 Subject: [PATCH 08/30] [CONJ-817] DatabaseMetadata.getProcedures REMARKS and PROCEDURE_TYPE ordering correction --- .../org/mariadb/jdbc/MariaDbDatabaseMetaData.java | 11 ++++++++--- .../java/org/mariadb/jdbc/StoredProcedureTest.java | 6 ++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java index 9e1cee0cf..26a1054eb 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java @@ -1941,8 +1941,13 @@ public ResultSet getProcedures(String catalog, String schemaPattern, String proc throws SQLException { String sql = - "SELECT ROUTINE_SCHEMA PROCEDURE_CAT,NULL PROCEDURE_SCHEM, ROUTINE_NAME PROCEDURE_NAME," - + " NULL RESERVED1, NULL RESERVED2, NULL RESERVED3," + "SELECT ROUTINE_SCHEMA PROCEDURE_CAT," + + "NULL PROCEDURE_SCHEM, " + + "ROUTINE_NAME PROCEDURE_NAME," + + " NULL RESERVED1," + + " NULL RESERVED2," + + " NULL RESERVED3," + + " ROUTINE_COMMENT REMARKS," + " CASE ROUTINE_TYPE " + " WHEN 'FUNCTION' THEN " + procedureReturnsResult @@ -1951,7 +1956,7 @@ public ResultSet getProcedures(String catalog, String schemaPattern, String proc + " ELSE " + procedureResultUnknown + " END PROCEDURE_TYPE," - + " ROUTINE_COMMENT REMARKS, SPECIFIC_NAME " + + " SPECIFIC_NAME " + " FROM INFORMATION_SCHEMA.ROUTINES " + " WHERE " + catalogCond("ROUTINE_SCHEMA", catalog) diff --git a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java index 29fbcf010..d86d92c57 100644 --- a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java +++ b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java @@ -424,7 +424,7 @@ public void testMetaCatalogNoAccessToProcedureBodies() throws Exception { properties.put("user", "test_jdbc"); properties.put("password", "testJ@dc1"); - createProcedure("testMetaCatalog", "(x int, out y int)\nBEGIN\nSET y = 2;\n end\n"); + createProcedure("testMetaCatalog", "(x int, out y int) COMMENT 'my comment' \nBEGIN\nSET y = 2;\n end\n"); try (Connection connection = openConnection(connU, properties)) { CallableStatement callableStatement = connection.prepareCall("{call testMetaCatalog(?, ?)}"); @@ -458,7 +458,9 @@ public void testMetaCatalogNoAccessToProcedureBodies() throws Exception { // test without catalog resultSet = connection.getMetaData().getProcedures(null, null, "testMetaCatalog"); if (resultSet.next()) { - assertTrue("testMetaCatalog".equals(resultSet.getString(3))); + assertEquals("testMetaCatalog", resultSet.getString(3)); + assertEquals("my comment", resultSet.getString(7)); + assertEquals(DatabaseMetaData.procedureNoResult, resultSet.getInt(8)); assertFalse(resultSet.next()); } else { fail(); From a0b65b873dcf91ac6fbe1c262011d87fcd5044c5 Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 21 Aug 2020 14:38:46 +0200 Subject: [PATCH 09/30] [CONJ-817] ResultSet.insertRow improvement for default value handling - detailed error when inserting data with empty primary key for server before 10.4 - permits insert for empty primary key with default value for 10.5 server (value is retrieved using RETURNING) --- .../mariadb/jdbc/BasePrepareStatement.java | 5 +- .../AuthenticationPluginLoader.java | 2 +- .../read/resultset/UpdatableResultSet.java | 101 ++++++++++++------ .../jdbc/ServerPrepareStatementTest.java | 3 +- .../org/mariadb/jdbc/StoredProcedureTest.java | 3 +- .../org/mariadb/jdbc/UpdateResultSetTest.java | 47 +++++++- 6 files changed, 121 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java index 6de42de3b..e2efd198c 100644 --- a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java +++ b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java @@ -967,8 +967,9 @@ private void setInternalObject( setNull(parameterIndex, Types.INTEGER); } else if (obj instanceof String || obj instanceof Character) { if (targetSqlType == Types.BLOB) { - throw exceptionFactory.create(String.format("Cannot convert a %s to a Blob", obj instanceof String ? - "string" : "character")); + throw exceptionFactory.create( + String.format( + "Cannot convert a %s to a Blob", obj instanceof String ? "string" : "character")); } String str = obj instanceof String ? (String) obj : ((Character) obj).toString(); try { diff --git a/src/main/java/org/mariadb/jdbc/authentication/AuthenticationPluginLoader.java b/src/main/java/org/mariadb/jdbc/authentication/AuthenticationPluginLoader.java index 823e523c0..4154b3b6d 100644 --- a/src/main/java/org/mariadb/jdbc/authentication/AuthenticationPluginLoader.java +++ b/src/main/java/org/mariadb/jdbc/authentication/AuthenticationPluginLoader.java @@ -42,7 +42,7 @@ public static AuthenticationPlugin get(String type) throws SQLException { } ServiceLoader loader = - ServiceLoader.load(AuthenticationPlugin.class, Driver.class.getClassLoader()); + ServiceLoader.load(AuthenticationPlugin.class, Driver.class.getClassLoader()); for (AuthenticationPlugin implClass : loader) { if (type.equals(implClass.type())) { diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java index d24018ea2..59380771d 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java @@ -59,6 +59,8 @@ import java.sql.*; import java.time.*; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.TimeZone; import org.mariadb.jdbc.*; import org.mariadb.jdbc.internal.ColumnType; @@ -88,7 +90,6 @@ public class UpdatableResultSet extends SelectResultSet { private ParameterHolder[] parameterHolders; private MariaDbConnection connection; private PreparedStatement refreshPreparedStatement = null; - private ClientSidePreparedStatement insertPreparedStatement = null; private ClientSidePreparedStatement deletePreparedStatement = null; /** @@ -194,7 +195,7 @@ private void checkIfUpdatable(Results results) throws SQLException { // read SHOW COLUMNS informations String fieldName = rs.getString("Field"); boolean canBeNull = "YES".equals(rs.getString("Null")); - boolean hasDefault = rs.getString("Default") == null; + boolean hasDefault = rs.getString("Default") != null; String extra = rs.getString("Extra"); boolean generated = extra != null && !extra.isEmpty(); boolean autoIncrement = extra != null && "auto_increment".equals(extra); @@ -1046,48 +1047,74 @@ public void updateNCharacterStream(String columnLabel, Reader reader) throws SQL /** {inheritDoc}. */ public void insertRow() throws SQLException { if (state == STATE_INSERT) { - if (insertPreparedStatement == null) { - // Create query will all field with WHERE clause contain primary field. - // if field are not updated, value DEFAULT will be set - // (if field has no default, then insert will throw an exception that will be return to - // user) - StringBuilder insertSql = new StringBuilder("INSERT `" + database + "`.`" + table + "` ( "); - StringBuilder valueClause = new StringBuilder(); - - for (int pos = 0; pos < columnInformationLength; pos++) { - UpdatableColumnDefinition colInfo = getUpdatableColumns()[pos]; - - if (pos != 0) { - insertSql.append(","); - valueClause.append(", "); - } - - insertSql.append("`").append(colInfo.getOriginalName()).append("`"); - valueClause.append("?"); - } - insertSql.append(") VALUES (").append(valueClause).append(")"); - insertPreparedStatement = connection.clientPrepareStatement(insertSql.toString()); - } - int fieldsIndex = 0; boolean hasGeneratedPrimaryFields = false; int generatedSqlType = 0; + HashMap paramMap = new HashMap<>(); + + // Create query will all field with WHERE clause contain primary field. + // if field are not updated, value DEFAULT will be set + // (if field has no default, then insert will throw an exception that will be return to + // user) + StringBuilder insertSql = new StringBuilder("INSERT `" + database + "`.`" + table + "` ( "); + StringBuilder valueClause = new StringBuilder(); + int fieldsIndex = 0; + for (int pos = 0; pos < columnInformationLength; pos++) { + UpdatableColumnDefinition colInfo = getUpdatableColumns()[pos]; + + if (pos != 0) { + insertSql.append(","); + valueClause.append(", "); + } + + insertSql.append("`").append(colInfo.getOriginalName()).append("`"); + valueClause.append("?"); ParameterHolder value = parameterHolders[pos]; if (value != null) { - insertPreparedStatement.setParameter((fieldsIndex++) + 1, value); + paramMap.put((fieldsIndex++) + 1, value); } else { - UpdatableColumnDefinition colInfo = getUpdatableColumns()[pos]; - if (colInfo.isPrimary() && colInfo.isAutoIncrement()) { - hasGeneratedPrimaryFields = true; - generatedSqlType = colInfo.getColumnType().getSqlType(); + if (colInfo.isPrimary()) { + if (colInfo.isAutoIncrement() || colInfo.hasDefault()) { + if (colInfo.isAutoIncrement()) { + hasGeneratedPrimaryFields = true; + generatedSqlType = colInfo.getColumnType().getSqlType(); + } else if (!connection.isServerMariaDb() + || !connection.versionGreaterOrEqual(10, 5, 1)) { + // driver cannot know generated default value like uuid(). + // but for server 10.5+, will use RETURNING to know primary key + throw new SQLException( + String.format( + "Cannot call insertRow() not setting value for primary key %s " + + "with default value before server 10.5", + colInfo.getOriginalName())); + } + } else { + throw new SQLException( + String.format( + "Cannot call insertRow() not setting value for primary key %s", + colInfo.getOriginalName())); + } + paramMap.put((fieldsIndex++) + 1, new DefaultParameter()); + } else { + paramMap.put( + (fieldsIndex++) + 1, + colInfo.hasDefault() ? new DefaultParameter() : new NullParameter()); } - insertPreparedStatement.setParameter((fieldsIndex++) + 1, new DefaultParameter()); } } + insertSql.append(") VALUES (").append(valueClause).append(")"); + if (connection.isServerMariaDb() && connection.versionGreaterOrEqual(10, 5, 1)) { + insertSql.append(" RETURNING *"); + } + ClientSidePreparedStatement insertPreparedStatement = + connection.clientPrepareStatement(insertSql.toString()); - insertPreparedStatement.execute(); + for (Map.Entry entry : paramMap.entrySet()) { + insertPreparedStatement.setParameter(entry.getKey(), entry.getValue()); + } + ResultSet insertRs = insertPreparedStatement.executeQuery(); if (hasGeneratedPrimaryFields) { // primary is auto_increment (only one field) ResultSet rsKey = insertPreparedStatement.getGeneratedKeys(); @@ -1102,9 +1129,15 @@ public void insertRow() throws SQLException { addRowData(rs.getCurrentRowData()); } } - } else { - addRowData(refreshRawData()); + if (connection.isServerMariaDb() && connection.versionGreaterOrEqual(10, 5, 1)) { + if (insertRs.next()) { + byte[] rowByte = ((SelectResultSet) insertRs).getCurrentRowData(); + addRowData(rowByte); + } + } else { + addRowData(refreshRawData()); + } } Arrays.fill(parameterHolders, null); diff --git a/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java b/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java index 97429f9a6..fcf0dcd72 100644 --- a/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java +++ b/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java @@ -671,7 +671,8 @@ public void characterObjectSupport() throws Throwable { Statement stmt = sharedConnection.createStatement(); stmt.execute("CREATE TEMPORARY TABLE temp_character (v varchar(10) ) "); - try (PreparedStatement ps = sharedConnection.prepareStatement("INSERT INTO temp_character(v) VALUES (?)")) { + try (PreparedStatement ps = + sharedConnection.prepareStatement("INSERT INTO temp_character(v) VALUES (?)")) { ps.setObject(1, 'c', Types.CHAR); ps.addBatch(); ps.setObject(1, 'd', Types.VARCHAR); diff --git a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java index d86d92c57..227b65a79 100644 --- a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java +++ b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java @@ -424,7 +424,8 @@ public void testMetaCatalogNoAccessToProcedureBodies() throws Exception { properties.put("user", "test_jdbc"); properties.put("password", "testJ@dc1"); - createProcedure("testMetaCatalog", "(x int, out y int) COMMENT 'my comment' \nBEGIN\nSET y = 2;\n end\n"); + createProcedure( + "testMetaCatalog", "(x int, out y int) COMMENT 'my comment' \nBEGIN\nSET y = 2;\n end\n"); try (Connection connection = openConnection(connU, properties)) { CallableStatement callableStatement = connection.prepareCall("{call testMetaCatalog(?, ?)}"); diff --git a/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java b/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java index 7b4a88764..ca153822c 100644 --- a/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java +++ b/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java @@ -407,7 +407,8 @@ public void testPrimaryGenerated() throws Exception { } catch (SQLException sqle) { assertTrue( sqle.getMessage(), - sqle.getMessage().contains("Field 't1' doesn't have a default value")); + sqle.getMessage().contains("Field 't1' doesn't have a default value") + || sqle.getMessage().contains("Column 't1' cannot be null")); } rs.absolute(1); @@ -995,4 +996,48 @@ public void repeatedFieldUpdatable() throws SQLException { rs.getObject(3); } } + + @Test + public void updatableDefaultPrimaryField() throws SQLException { + Statement stmt = sharedConnection.createStatement(); + stmt.executeQuery("DROP TABLE IF EXISTS `testDefaultUUID`"); + stmt.execute( + "CREATE TABLE `testDefaultUUID` (" + + "`column1` varchar(40) NOT NULL DEFAULT uuid()," + + "`column2` varchar(100) DEFAULT NULL," + + " PRIMARY KEY (`column1`))"); + String sql = "SELECT t.* FROM testDefaultUUID t WHERE 1 = 2"; + try (PreparedStatement pstmt = + sharedConnection.prepareStatement( + sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE)) { + pstmt.execute(); + ResultSet rs = pstmt.getResultSet(); + rs.moveToInsertRow(); + rs.updateString("column2", "x"); + try { + rs.insertRow(); + if (!isMariadbServer() || !minVersion(10, 5, 3)) { + fail("Must have thrown exception"); + } + + assertEquals(36, rs.getString(1).length()); + assertEquals("x", rs.getString(2)); + } catch (SQLException e) { + if (isMariadbServer() && minVersion(10, 5, 3)) { + fail("Must have succeed"); + } + assertTrue( + e.getMessage() + .contains( + "Cannot call insertRow() not setting value for primary key column1 with " + + "default value before server 10.5")); + } + rs.moveToInsertRow(); + rs.updateString("column1", "de6f7774-e399-11ea-aa68-c8348e0fed44"); + rs.updateString("column2", "x"); + rs.insertRow(); + assertEquals("de6f7774-e399-11ea-aa68-c8348e0fed44", rs.getString(1)); + assertEquals("x", rs.getString(2)); + } + } } From 5a20980dcec2ce4d985a810a4c664d5281ed9ae3 Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 21 Aug 2020 16:27:25 +0200 Subject: [PATCH 10/30] [CONJ-820] test correction when using prepare --- src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java b/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java index fcf0dcd72..042f4dc83 100644 --- a/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java +++ b/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java @@ -728,7 +728,7 @@ public void characterObjectSupport() throws Throwable { assertTrue(rs.next()); assertEquals("3", rs.getString(1)); assertTrue(rs.next()); - assertEquals("4.0", rs.getString(1)); + assertEquals(sharedOptions().useServerPrepStmts ? "4.0" : "4", rs.getString(1)); assertTrue(rs.next()); assertEquals("5", rs.getString(1)); assertTrue(rs.next()); From 47d01e79cff6db89706892fde5e3bd9ef6701ac5 Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 21 Aug 2020 16:27:59 +0200 Subject: [PATCH 11/30] [misc] update appveyor server version to latest --- appveyor.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 5ce2394c2..021dafe09 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,27 +1,27 @@ version: '{build}' environment: matrix: - - DB: '10.2.31' + - DB: '10.2.33' APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 CMAKE_PARAM: 'Visual Studio 15 2017 Win64' JAVA_HOME: C:\Program Files\Java\jdk1.8.0 - - DB: '10.3.22' + - DB: '10.3.24' APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 CMAKE_PARAM: 'Visual Studio 15 2017 Win64' JAVA_HOME: C:\Program Files\Java\jdk1.8.0 - - DB: '10.4.12' + - DB: '10.4.14' APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 CMAKE_PARAM: 'Visual Studio 15 2017 Win64' JAVA_HOME: C:\Program Files\Java\jdk1.8.0 - - DB: '10.5.1' + - DB: '10.5.5' APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 CMAKE_PARAM: 'Visual Studio 15 2017 Win64' JAVA_HOME: C:\Program Files\Java\jdk1.8.0 - - DB: '10.1.44' + - DB: '10.1.46' APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 CMAKE_PARAM: 'Visual Studio 15 2017 Win64' JAVA_HOME: C:\Program Files\Java\jdk1.8.0 From ed706d53628d4abb317970db5a62a1fd8e88c6fa Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 21 Aug 2020 17:17:18 +0200 Subject: [PATCH 12/30] [CONJ-816] correct test using default UUID() to supported version --- src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java | 2 +- src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java b/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java index 042f4dc83..5dc95b81d 100644 --- a/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java +++ b/src/test/java/org/mariadb/jdbc/ServerPrepareStatementTest.java @@ -728,7 +728,7 @@ public void characterObjectSupport() throws Throwable { assertTrue(rs.next()); assertEquals("3", rs.getString(1)); assertTrue(rs.next()); - assertEquals(sharedOptions().useServerPrepStmts ? "4.0" : "4", rs.getString(1)); + assertEquals(sharedOptions().useServerPrepStmts ? "4" : "4.0", rs.getString(1)); assertTrue(rs.next()); assertEquals("5", rs.getString(1)); assertTrue(rs.next()); diff --git a/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java b/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java index ca153822c..93ce6024a 100644 --- a/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java +++ b/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java @@ -58,6 +58,8 @@ import java.io.IOException; import java.io.InputStream; import java.sql.*; + +import org.junit.Assume; import org.junit.Test; public class UpdateResultSetTest extends BaseTest { @@ -999,6 +1001,7 @@ public void repeatedFieldUpdatable() throws SQLException { @Test public void updatableDefaultPrimaryField() throws SQLException { + Assume.assumeTrue(isMariadbServer() && minVersion(10, 2)); Statement stmt = sharedConnection.createStatement(); stmt.executeQuery("DROP TABLE IF EXISTS `testDefaultUUID`"); stmt.execute( From 7363e257a163462653611fdc377df4a74155c292 Mon Sep 17 00:00:00 2001 From: rusher Date: Mon, 24 Aug 2020 18:04:44 +0200 Subject: [PATCH 13/30] [CONJ-814] DatabaseMetadata result-set PK_NAME now contains value * getCrossReference PK_NAME was always null. * getExportedKeys PK_NAME was always 'PRIMARY'. * getImportedKeys PK_NAME was always null. now return parent key name when available getCrossReference now permit patterns for parentTable and foreignTable parameters like many meta methods allows. --- .../mariadb/jdbc/MariaDbDatabaseMetaData.java | 85 +++-- .../mariadb/jdbc/DatabaseMetadataTest.java | 294 +++++++++++++----- .../org/mariadb/jdbc/UpdateResultSetTest.java | 1 - 3 files changed, 254 insertions(+), 126 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java index 26a1054eb..a764494aa 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java @@ -236,7 +236,7 @@ private static ResultSet getImportedKeys( ColumnType.VARCHAR, ColumnType.VARCHAR, ColumnType.NULL, ColumnType.VARCHAR, ColumnType.VARCHAR, ColumnType.SMALLINT, ColumnType.SMALLINT, ColumnType.SMALLINT, ColumnType.VARCHAR, - ColumnType.NULL, ColumnType.SMALLINT + ColumnType.VARCHAR, ColumnType.SMALLINT }; String[] parts = tableDef.split("\n"); @@ -280,23 +280,23 @@ private static ResultSet getImportedKeys( for (int i = 0; i < primaryKeyCols.size(); i++) { String[] row = new String[columnNames.length]; - row[0] = pkTable.schema; + row[0] = pkTable.schema; // PKTABLE_CAT if (row[0] == null) { row[0] = catalog; } - row[1] = null; - row[2] = pkTable.name; - row[3] = primaryKeyCols.get(i).name; - row[4] = catalog; - row[5] = null; - row[6] = tableName; - row[7] = foreignKeyCols.get(i).name; - row[8] = Integer.toString(i + 1); - row[9] = Integer.toString(onUpdateReferenceAction); - row[10] = Integer.toString(onDeleteReferenceAction); - row[11] = constraintName.name; - row[12] = null; - row[13] = Integer.toString(DatabaseMetaData.importedKeyNotDeferrable); + row[1] = null; // PKTABLE_SCHEM + row[2] = pkTable.name; // PKTABLE_NAME + row[3] = primaryKeyCols.get(i).name; // PKCOLUMN_NAME + row[4] = catalog; // FKTABLE_CAT + row[5] = null; // FKTABLE_SCHEM + row[6] = tableName; // FKTABLE_NAME + row[7] = foreignKeyCols.get(i).name; // FKCOLUMN_NAME + row[8] = Integer.toString(i + 1); // KEY_SEQ + row[9] = Integer.toString(onUpdateReferenceAction); // UPDATE_RULE + row[10] = Integer.toString(onDeleteReferenceAction); // DELETE_RULE + row[11] = constraintName.name; // FK_NAME + row[12] = null; // PK_NAME - unlike using information_schema, cannot know constraint name + row[13] = Integer.toString(DatabaseMetaData.importedKeyNotDeferrable); // DEFERRABILITY data.add(row); } } @@ -390,34 +390,26 @@ private static ResultSet getImportedKeys( public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { - String database = catalog; // We avoid using information schema queries by default, because this appears to be an expensive // query (CONJ-41). if (table == null) { throw new SQLException("'table' parameter in getImportedKeys cannot be null"); } - if (database == null && connection.nullCatalogMeansCurrent) { - /* Treat null catalog as current */ - return getImportedKeysUsingInformationSchema("", table); - } - - if (database == null) { - return getImportedKeysUsingInformationSchema(null, table); - } - - if (database.isEmpty()) { - database = connection.getCatalog(); - if (database == null || database.isEmpty()) { - return getImportedKeysUsingInformationSchema(database, table); + if (catalog == null || catalog.isEmpty()) { + if (connection.nullCatalogMeansCurrent) { + /* Treat null catalog as current */ + return getImportedKeysUsingInformationSchema("", table); + } else { + return getImportedKeysUsingInformationSchema(catalog, table); } } try { - return getImportedKeysUsingShowCreateTable(database, table); + return getImportedKeysUsingShowCreateTable(catalog, table); } catch (Exception e) { // Likely, parsing failed, try out I_S query. - return getImportedKeysUsingInformationSchema(database, table); + return getImportedKeysUsingInformationSchema(catalog, table); } } @@ -922,7 +914,7 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) + " WHEN 'SET DEFAULT' THEN 4" + " END DELETE_RULE," + " RC.CONSTRAINT_NAME FK_NAME," - + " 'PRIMARY' PK_NAME," + + " RC.UNIQUE_CONSTRAINT_NAME PK_NAME," + importedKeyNotDeferrable + " DEFERRABILITY" + " FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU" @@ -945,7 +937,7 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) * @return resultset * @throws SQLException exception */ - public ResultSet getImportedKeysUsingInformationSchema(String catalog, String table) + public ResultSet getImportedKeysUsingInformationSchema(final String catalog, String table) throws SQLException { if (table == null) { throw new SQLException("'table' parameter in getImportedKeys cannot be null"); @@ -969,7 +961,7 @@ public ResultSet getImportedKeysUsingInformationSchema(String catalog, String ta + " WHEN 'SET DEFAULT' THEN 4" + " END DELETE_RULE," + " RC.CONSTRAINT_NAME FK_NAME," - + " NULL PK_NAME," + + " RC.UNIQUE_CONSTRAINT_NAME PK_NAME," + importedKeyNotDeferrable + " DEFERRABILITY" + " FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU" @@ -994,7 +986,7 @@ public ResultSet getImportedKeysUsingInformationSchema(String catalog, String ta * @return resultset * @throws Exception exception */ - public ResultSet getImportedKeysUsingShowCreateTable(String catalog, String table) + public ResultSet getImportedKeysUsingShowCreateTable(final String catalog, String table) throws Exception { if (catalog == null || catalog.isEmpty()) { @@ -2541,15 +2533,14 @@ public ResultSet getVersionColumns(String catalog, String schema, String table) * @param parentSchema a schema name; must match the schema name as it is stored in the database; * "" retrieves those without a schema; null means drop schema name from the * selection criteria - * @param parentTable the name of the table that exports the key; must match the table name as it - * is stored in the database + * @param parentTable the name of the table that exports the key; pattern, or null (means any table) value * @param foreignCatalog a catalog name; must match the catalog name as it is stored in the * database; "" retrieves those without a catalog; null means drop catalog name * from the selection criteria * @param foreignSchema a schema name; must match the schema name as it is stored in the database; * "" retrieves those without a schema; null means drop schema name from the * selection criteria - * @param foreignTable the name of the table that imports the key; must match the table name as it + * @param foreignTable the name of the table that imports the key; pattern, or null (means any table) value * is stored in the database * @return ResultSet - each row is a foreign key column description * @throws SQLException if a database access error occurs @@ -2583,23 +2574,19 @@ public ResultSet getCrossReference( + " WHEN 'SET DEFAULT' THEN 4" + " END DELETE_RULE," + " RC.CONSTRAINT_NAME FK_NAME," - + " NULL PK_NAME," + + " RC.UNIQUE_CONSTRAINT_NAME PK_NAME," + importedKeyNotDeferrable - + " DEFERRABILITY" - + " FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU" + + " DEFERRABILITY " + + "FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU" + " INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC" + " ON KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA" - + " AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME" - + " WHERE " + + " AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME " + + "WHERE " + catalogCond("KCU.REFERENCED_TABLE_SCHEMA", parentCatalog) + " AND " + catalogCond("KCU.TABLE_SCHEMA", foreignCatalog) - + " AND " - + " KCU.REFERENCED_TABLE_NAME = " - + escapeQuote(parentTable) - + " AND " - + " KCU.TABLE_NAME = " - + escapeQuote(foreignTable) + + patternCond("KCU.REFERENCED_TABLE_NAME", parentTable) + + patternCond("KCU.TABLE_NAME", foreignTable) + " ORDER BY FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, KEY_SEQ"; return executeQuery(sql); diff --git a/src/test/java/org/mariadb/jdbc/DatabaseMetadataTest.java b/src/test/java/org/mariadb/jdbc/DatabaseMetadataTest.java index 767c43ae9..68d207107 100644 --- a/src/test/java/org/mariadb/jdbc/DatabaseMetadataTest.java +++ b/src/test/java/org/mariadb/jdbc/DatabaseMetadataTest.java @@ -55,10 +55,7 @@ import static org.junit.Assert.*; import java.sql.*; -import org.junit.Assume; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.*; public class DatabaseMetadataTest extends BaseTest { @@ -114,6 +111,31 @@ public static void initClass() throws SQLException { if (isMariadbServer() && minVersion(10, 3, 4)) { createTable("versionTable", "x INT", "WITH SYSTEM VERSIONING"); } + Statement stmt = sharedConnection.createStatement(); + stmt.execute("drop table if exists cross3"); + stmt.execute("drop table if exists cross2"); + stmt.execute("drop table if exists cross1"); + stmt.execute("create table cross1 (id int not null primary key, val varchar(20))"); + stmt.execute( + "create table cross2 (id int not null, id2 int not null, " + + "id_ref0 int, foreign key (id_ref0) references cross1(id), UNIQUE unik_name (id, id2))"); + stmt.execute( + "create table cross3 (id int not null primary key, " + + "id_ref1 int, id_ref2 int, foreign key fk_my_name (id_ref1, id_ref2) references cross2(id, id2) on " + + "update cascade)"); + } + + /** + * Initialisation. + * + * @throws SQLException exception + */ + @AfterClass + public static void afterClass() throws SQLException { + Statement stmt = sharedConnection.createStatement(); + stmt.execute("drop table if exists cross3"); + stmt.execute("drop table if exists cross2"); + stmt.execute("drop table if exists cross1"); } private static void checkType(String name, int actualType, String colName, int expectedType) { @@ -235,7 +257,7 @@ public void getImportedKeys() throws Exception { st.execute( "CREATE TABLE t1.product ( category INT NOT NULL, id INT NOT NULL, price DECIMAL," - + " PRIMARY KEY(category, id) ) ENGINE=INNODB"); + + " UNIQUE unik_name (category, id) ) ENGINE=INNODB"); st.execute("CREATE TABLE `cus``tomer` (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB"); @@ -261,26 +283,64 @@ Get result sets using either method and compare (ignore minor differences INT vs */ ResultSet rs1 = ((MariaDbDatabaseMetaData) sharedConnection.getMetaData()) - .getImportedKeysUsingShowCreateTable("testj", "product_order"); + .getImportedKeysUsingShowCreateTable(database, "product_order"); ResultSet rs2 = ((MariaDbDatabaseMetaData) sharedConnection.getMetaData()) - .getImportedKeysUsingInformationSchema("testj", "product_order"); + .getImportedKeysUsingInformationSchema(database, "product_order"); assertEquals(rs1.getMetaData().getColumnCount(), rs2.getMetaData().getColumnCount()); + for (int i = 0; i < 2; i++) { + ResultSet rs = i == 0 ? rs1 : rs2; + assertTrue(rs.next()); - while (rs1.next()) { - assertTrue(rs2.next()); - for (int i = 1; i <= rs1.getMetaData().getColumnCount(); i++) { - Object s1 = rs1.getObject(i); - Object s2 = rs2.getObject(i); - if (s1 instanceof Number && s2 instanceof Number) { - assertEquals(((Number) s1).intValue(), ((Number) s2).intValue()); - } else { - if (s1 != null && s2 != null && !s1.equals(s2)) { - fail(); - } - assertEquals(s1, s2); - } - } + assertEquals("t1", rs.getString("PKTABLE_CAT")); + assertEquals(null, rs.getString("PKTABLE_SCHEM")); + assertEquals("product", rs.getString("PKTABLE_NAME")); + assertEquals("category", rs.getString("PKCOLUMN_NAME")); + assertEquals(database, rs.getString("FKTABLE_CAT")); + assertEquals(null, rs.getString("FKTABLE_SCHEM")); + assertEquals("product_order", rs.getString("FKTABLE_NAME")); + assertEquals("product_category", rs.getString("FKCOLUMN_NAME")); + assertEquals(1, rs.getInt("KEY_SEQ")); + assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt("UPDATE_RULE")); + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); + assertEquals("product_order_ibfk_1", rs.getString("FK_NAME")); + // with show, meta don't know contraint name + assertEquals((i == 0) ? null : "unik_name", rs.getString("PK_NAME")); + assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY")); + + assertTrue(rs.next()); + assertEquals("t1", rs.getString("PKTABLE_CAT")); + assertEquals(null, rs.getString("PKTABLE_SCHEM")); + assertEquals("product", rs.getString("PKTABLE_NAME")); + assertEquals("id", rs.getString("PKCOLUMN_NAME")); + assertEquals(database, rs.getString("FKTABLE_CAT")); + assertEquals(null, rs.getString("FKTABLE_SCHEM")); + assertEquals("product_order", rs.getString("FKTABLE_NAME")); + assertEquals("product_id", rs.getString("FKCOLUMN_NAME")); + assertEquals(2, rs.getInt("KEY_SEQ")); + assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt("UPDATE_RULE")); + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); + assertEquals("product_order_ibfk_1", rs.getString("FK_NAME")); + // with show, meta don't know contraint name + assertEquals((i == 0) ? null : "unik_name", rs.getString("PK_NAME")); + assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY")); + + assertTrue(rs.next()); + assertEquals(database, rs.getString("PKTABLE_CAT")); + assertEquals(null, rs.getString("PKTABLE_SCHEM")); + assertEquals("cus`tomer", rs.getString("PKTABLE_NAME")); + assertEquals("id", rs.getString("PKCOLUMN_NAME")); + assertEquals(database, rs.getString("FKTABLE_CAT")); + assertEquals(null, rs.getString("FKTABLE_SCHEM")); + assertEquals("product_order", rs.getString("FKTABLE_NAME")); + assertEquals("customer_id", rs.getString("FKCOLUMN_NAME")); + assertEquals(1, rs.getInt("KEY_SEQ")); + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("UPDATE_RULE")); + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); + assertEquals("product_order_ibfk_2", rs.getString("FK_NAME")); + // with show, meta don't know contraint name + assertEquals((i == 0) ? null : "PRIMARY", rs.getString("PK_NAME")); + assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY")); } /* Also compare metadata */ @@ -297,69 +357,79 @@ Get result sets using either method and compare (ignore minor differences INT vs @Test public void exportedKeysTest() throws SQLException { - Statement stmt = sharedConnection.createStatement(); - stmt.execute("drop table if exists fore_key0"); - stmt.execute("drop table if exists fore_key1"); - stmt.execute("drop table if exists prim_key"); - stmt.execute("drop table if exists fore_key3"); - stmt.execute("drop table if exists prim2_key"); - - stmt.execute( - "create table prim_key (id int not null primary key, val varchar(20)) engine=innodb"); - stmt.execute( - "create table prim2_key (id int not null primary key, val varchar(20)) engine=innodb"); - stmt.execute( - "create table fore_key0 (id int not null primary key, " - + "id_ref0 int, foreign key (id_ref0) references prim_key(id)) engine=innodb"); - stmt.execute( - "create table fore_key1 (id int not null primary key, " - + "id_ref1 int, foreign key (id_ref1) references prim_key(id) on update cascade) engine=innodb"); - stmt.execute( - "create table fore_key3 (id int not null primary key, " - + "id_ref0 int, foreign key (id_ref0) references prim2_key(id)) engine=innodb"); DatabaseMetaData dbmd = sharedConnection.getMetaData(); - ResultSet rs = dbmd.getExportedKeys("testj", null, "prim_key"); - int counter = 0; - while (rs.next()) { - assertEquals("id", rs.getString("pkcolumn_name")); - assertEquals("fore_key" + counter, rs.getString("fktable_name")); - assertEquals("id_ref" + counter, rs.getString("fkcolumn_name")); - assertEquals("PRIMARY", rs.getString("pk_name")); - counter++; + ResultSet rs = dbmd.getExportedKeys(database, null, "cross%"); + assertTrue(rs.next()); + assertEquals(database, rs.getString("PKTABLE_CAT")); + assertEquals(null, rs.getString("PKTABLE_SCHEM")); + assertEquals("cross1", rs.getString("PKTABLE_NAME")); + assertEquals("id", rs.getString("PKCOLUMN_NAME")); + assertEquals(database, rs.getString("FKTABLE_CAT")); + assertEquals(null, rs.getString("FKTABLE_SCHEM")); + assertEquals("cross2", rs.getString("FKTABLE_NAME")); + assertEquals("id_ref0", rs.getString("FKCOLUMN_NAME")); + assertEquals(1, rs.getInt("KEY_SEQ")); + if (!isMariadbServer() && minVersion(8,0)) { + assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("UPDATE_RULE")); + assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); + } else { + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("UPDATE_RULE")); + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); } - assertEquals(2, counter); + assertEquals("cross2_ibfk_1", rs.getString("FK_NAME")); + assertEquals("PRIMARY", rs.getString("PK_NAME")); - rs = dbmd.getExportedKeys("testj", null, "prim_k%"); - counter = 0; - while (rs.next()) { - assertEquals("id", rs.getString("pkcolumn_name")); - assertEquals("fore_key" + counter, rs.getString("fktable_name")); - assertEquals("id_ref" + counter, rs.getString("fkcolumn_name")); - assertEquals("PRIMARY", rs.getString("pk_name")); - counter++; + assertTrue(rs.next()); + + assertEquals(database, rs.getString("PKTABLE_CAT")); + assertEquals(null, rs.getString("PKTABLE_SCHEM")); + assertEquals("cross2", rs.getString("PKTABLE_NAME")); + assertEquals("id", rs.getString("PKCOLUMN_NAME")); + assertEquals(database, rs.getString("FKTABLE_CAT")); + assertEquals(null, rs.getString("FKTABLE_SCHEM")); + assertEquals("cross3", rs.getString("FKTABLE_NAME")); + assertEquals("id_ref1", rs.getString("FKCOLUMN_NAME")); + assertEquals(1, rs.getInt("KEY_SEQ")); + assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt("UPDATE_RULE")); + if (!isMariadbServer() && minVersion(8,0)) { + assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); + } else { + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); } - assertEquals(2, counter); + if (!isMariadbServer()) { + // index name not taken into account + assertEquals("cross3_ibfk_1", rs.getString("FK_NAME")); + } else { + assertEquals("fk_my_name", rs.getString("FK_NAME")); + } + assertEquals("unik_name", rs.getString("PK_NAME")); - rs = dbmd.getExportedKeys("testj", null, null); - counter = 0; - int totalCounter = 0; - while (rs.next()) { - if ("prim_key".equals(rs.getString("pktable_name"))) { - assertEquals("id", rs.getString("pkcolumn_name")); - assertEquals("fore_key" + counter, rs.getString("fktable_name")); - assertEquals("id_ref" + counter, rs.getString("fkcolumn_name")); - assertEquals("PRIMARY", rs.getString("PK_NAME")); - counter++; - } - totalCounter++; + assertTrue(rs.next()); + assertEquals(database, rs.getString("PKTABLE_CAT")); + assertEquals(null, rs.getString("PKTABLE_SCHEM")); + assertEquals("cross2", rs.getString("PKTABLE_NAME")); + assertEquals("id2", rs.getString("PKCOLUMN_NAME")); + assertEquals(database, rs.getString("FKTABLE_CAT")); + assertEquals(null, rs.getString("FKTABLE_SCHEM")); + assertEquals("cross3", rs.getString("FKTABLE_NAME")); + assertEquals("id_ref2", rs.getString("FKCOLUMN_NAME")); + assertEquals(2, rs.getInt("KEY_SEQ")); + assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt("UPDATE_RULE")); + if (!isMariadbServer() && minVersion(8,0)) { + assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); + } else { + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); } - assertEquals(2, counter); - assertTrue(totalCounter > 2); + if (!isMariadbServer()) { + // wrong index name + assertEquals("cross3_ibfk_1", rs.getString("FK_NAME")); + } else { + assertEquals("fk_my_name", rs.getString("FK_NAME")); + } + assertEquals("unik_name", rs.getString("PK_NAME")); - stmt.execute("drop table if exists fore_key0"); - stmt.execute("drop table if exists fore_key1"); - stmt.execute("drop table if exists prim_key"); + assertFalse(rs.next()); } @Test @@ -931,6 +1001,78 @@ public void getCrossReferenceBasic() throws SQLException { + "UPDATE_RULE short,DELETE_RULE short,FK_NAME String,PK_NAME String,DEFERRABILITY short"); } + @Test + public void getCrossReferenceResults() throws SQLException { + DatabaseMetaData dbmd = sharedConnection.getMetaData(); + ResultSet rs = dbmd.getCrossReference(null, null, "cross%", null, null, "cross%"); + + assertTrue(rs.next()); + assertEquals(database, rs.getString(1)); + assertEquals(null, rs.getString(2)); + assertEquals("cross1", rs.getString(3)); + assertEquals("id", rs.getString(4)); + assertEquals(database, rs.getString(5)); + assertEquals(null, rs.getString(6)); + assertEquals("cross2", rs.getString(7)); + assertEquals("id_ref0", rs.getString(8)); + assertEquals(1, rs.getInt(9)); + if (!isMariadbServer() && minVersion(8,0)) { + assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("UPDATE_RULE")); + assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); + } else { + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("UPDATE_RULE")); + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); + } + assertEquals("cross2_ibfk_1", rs.getString(12)); + + assertTrue(rs.next()); + assertEquals(database, rs.getString(1)); + assertEquals(null, rs.getString(2)); + assertEquals("cross2", rs.getString(3)); + assertEquals("id", rs.getString(4)); + assertEquals(database, rs.getString(5)); + assertEquals(null, rs.getString(6)); + assertEquals("cross3", rs.getString(7)); + assertEquals("id_ref1", rs.getString(8)); + assertEquals(1, rs.getInt(9)); + assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt(10)); + if (!isMariadbServer() && minVersion(8,0)) { + assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); + } else { + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); + } + if (!isMariadbServer()) { + // wrong index naming + assertEquals("cross3_ibfk_1", rs.getString(12)); + } else { + assertEquals("fk_my_name", rs.getString("FK_NAME")); + } + + assertTrue(rs.next()); + assertEquals(database, rs.getString(1)); + assertEquals(null, rs.getString(2)); + assertEquals("cross2", rs.getString(3)); + assertEquals("id2", rs.getString(4)); + assertEquals(database, rs.getString(5)); + assertEquals(null, rs.getString(6)); + assertEquals("cross3", rs.getString(7)); + assertEquals("id_ref2", rs.getString(8)); + assertEquals(2, rs.getInt(9)); + assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt(10)); + if (!isMariadbServer() && minVersion(8,0)) { + assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); + } else { + assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); + } + if (!isMariadbServer()) { + // wrong index naming + assertEquals("cross3_ibfk_1", rs.getString(12)); + } else { + assertEquals("fk_my_name", rs.getString(12)); + } + assertFalse(rs.next()); + } + @Test public void getUdtsBasic() throws SQLException { testResultSetColumns( diff --git a/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java b/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java index 93ce6024a..67e200aa2 100644 --- a/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java +++ b/src/test/java/org/mariadb/jdbc/UpdateResultSetTest.java @@ -58,7 +58,6 @@ import java.io.IOException; import java.io.InputStream; import java.sql.*; - import org.junit.Assume; import org.junit.Test; From f3055c7c7b3e4afb04718e0026240d7ae6295d47 Mon Sep 17 00:00:00 2001 From: rusher Date: Tue, 25 Aug 2020 17:10:11 +0200 Subject: [PATCH 14/30] [CONJ-812] DatabaseMetadata getBestRowIdentifier and getMaxProcedureNameLength correction * getBestRowIdentifier: ** Pseudo-code good value ** only return "best" column, so primary or if no primary unique cols depending on nullable parameter * getMaxProcedureNameLength() now return 64 in place of 256 (https://mariadb.com/kb/en/identifier-names/#maximum-length) --- .../mariadb/jdbc/MariaDbDatabaseMetaData.java | 33 +++-- .../mariadb/jdbc/DatabaseMetadataTest.java | 122 ++++++++++++++++-- 2 files changed, 136 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java index a764494aa..0afbfdc06 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java @@ -1070,19 +1070,29 @@ public ResultSet getBestRowIdentifier( String sql = "SELECT " - + DatabaseMetaData.bestRowUnknown + + bestRowSession + " SCOPE, COLUMN_NAME," + dataTypeClause("COLUMN_TYPE") + " DATA_TYPE, DATA_TYPE TYPE_NAME," + " IF(NUMERIC_PRECISION IS NULL, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION) COLUMN_SIZE, 0 BUFFER_LENGTH," + " NUMERIC_SCALE DECIMAL_DIGITS," - + " 1 PSEUDO_COLUMN" + + " if(IS_GENERATED='NEVER'," + + bestRowNotPseudo + + "," + + bestRowPseudo + + ") PSEUDO_COLUMN" + " FROM INFORMATION_SCHEMA.COLUMNS" - + " WHERE COLUMN_KEY IN('PRI', 'MUL', 'UNI')" - + " AND " + + " WHERE (COLUMN_KEY = 'PRI'" + + " OR (COLUMN_KEY = 'UNI' AND NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_KEY = " + + "'PRI' AND " + + catalogCond("TABLE_SCHEMA", catalog) + + " AND TABLE_NAME = " + + escapeQuote(table) + + " ))) AND " + catalogCond("TABLE_SCHEMA", catalog) + " AND TABLE_NAME = " - + escapeQuote(table); + + escapeQuote(table) + + (nullable ? "" : " AND IS_NULLABLE = 'NO'"); return executeQuery(sql); } @@ -1800,7 +1810,7 @@ public int getMaxSchemaNameLength() { } public int getMaxProcedureNameLength() { - return 256; + return 64; } public int getMaxCatalogNameLength() { @@ -2533,15 +2543,16 @@ public ResultSet getVersionColumns(String catalog, String schema, String table) * @param parentSchema a schema name; must match the schema name as it is stored in the database; * "" retrieves those without a schema; null means drop schema name from the * selection criteria - * @param parentTable the name of the table that exports the key; pattern, or null (means any table) value + * @param parentTable the name of the table that exports the key; pattern, or null (means any + * table) value * @param foreignCatalog a catalog name; must match the catalog name as it is stored in the * database; "" retrieves those without a catalog; null means drop catalog name * from the selection criteria * @param foreignSchema a schema name; must match the schema name as it is stored in the database; * "" retrieves those without a schema; null means drop schema name from the * selection criteria - * @param foreignTable the name of the table that imports the key; pattern, or null (means any table) value - * is stored in the database + * @param foreignTable the name of the table that imports the key; pattern, or null (means any + * table) value is stored in the database * @return ResultSet - each row is a foreign key column description * @throws SQLException if a database access error occurs * @see #getImportedKeys @@ -3366,7 +3377,9 @@ public ResultSet getIndexInfo( String sql = "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, NON_UNIQUE, " - + " TABLE_SCHEMA INDEX_QUALIFIER, INDEX_NAME, 3 TYPE," + + " TABLE_SCHEMA INDEX_QUALIFIER, INDEX_NAME, " + + tableIndexOther + + " TYPE," + " SEQ_IN_INDEX ORDINAL_POSITION, COLUMN_NAME, COLLATION ASC_OR_DESC," + " CARDINALITY, NULL PAGES, NULL FILTER_CONDITION" + " FROM INFORMATION_SCHEMA.STATISTICS" diff --git a/src/test/java/org/mariadb/jdbc/DatabaseMetadataTest.java b/src/test/java/org/mariadb/jdbc/DatabaseMetadataTest.java index 68d207107..bac2e6672 100644 --- a/src/test/java/org/mariadb/jdbc/DatabaseMetadataTest.java +++ b/src/test/java/org/mariadb/jdbc/DatabaseMetadataTest.java @@ -123,6 +123,13 @@ public static void initClass() throws SQLException { "create table cross3 (id int not null primary key, " + "id_ref1 int, id_ref2 int, foreign key fk_my_name (id_ref1, id_ref2) references cross2(id, id2) on " + "update cascade)"); + stmt.execute( + "create table getBestRowIdentifier1(i int not null primary key auto_increment, id int, " + + "id_ref1 int, id_ref2 int, foreign key fk_my_name_1 (id_ref1, id_ref2) references cross2(id, id2) on " + + "update cascade, UNIQUE getBestRowIdentifier_unik (id))"); + stmt.execute( + "create table getBestRowIdentifier2(id_ref0 int not null, " + + "id_ref1 int, id_ref2 int not null, UNIQUE (id_ref1, id_ref2) , UNIQUE (id_ref0, id_ref2))"); } /** @@ -133,6 +140,8 @@ public static void initClass() throws SQLException { @AfterClass public static void afterClass() throws SQLException { Statement stmt = sharedConnection.createStatement(); + stmt.execute("drop table if exists getBestRowIdentifier1"); + stmt.execute("drop table if exists getBestRowIdentifier2"); stmt.execute("drop table if exists cross3"); stmt.execute("drop table if exists cross2"); stmt.execute("drop table if exists cross1"); @@ -370,7 +379,7 @@ public void exportedKeysTest() throws SQLException { assertEquals("cross2", rs.getString("FKTABLE_NAME")); assertEquals("id_ref0", rs.getString("FKCOLUMN_NAME")); assertEquals(1, rs.getInt("KEY_SEQ")); - if (!isMariadbServer() && minVersion(8,0)) { + if (!isMariadbServer() && minVersion(8, 0)) { assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("UPDATE_RULE")); assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); } else { @@ -392,7 +401,7 @@ public void exportedKeysTest() throws SQLException { assertEquals("id_ref1", rs.getString("FKCOLUMN_NAME")); assertEquals(1, rs.getInt("KEY_SEQ")); assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt("UPDATE_RULE")); - if (!isMariadbServer() && minVersion(8,0)) { + if (!isMariadbServer() && minVersion(8, 0)) { assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); } else { assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); @@ -416,7 +425,7 @@ public void exportedKeysTest() throws SQLException { assertEquals("id_ref2", rs.getString("FKCOLUMN_NAME")); assertEquals(2, rs.getInt("KEY_SEQ")); assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt("UPDATE_RULE")); - if (!isMariadbServer() && minVersion(8,0)) { + if (!isMariadbServer() && minVersion(8, 0)) { assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); } else { assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); @@ -428,8 +437,6 @@ public void exportedKeysTest() throws SQLException { assertEquals("fk_my_name", rs.getString("FK_NAME")); } assertEquals("unik_name", rs.getString("PK_NAME")); - - assertFalse(rs.next()); } @Test @@ -848,12 +855,103 @@ public void identifierCaseSensitivity() throws Exception { } @Test - public void getBestRowIdentifierBasic() throws SQLException { + public void getBestRowIdentifier() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getBestRowIdentifier(null, null, "", 0, true), "SCOPE short,COLUMN_NAME String,DATA_TYPE int, TYPE_NAME String," + "COLUMN_SIZE int,BUFFER_LENGTH int," + "DECIMAL_DIGITS short,PSEUDO_COLUMN short"); + + ResultSet rs = + sharedConnection.getMetaData().getBestRowIdentifier(null, null, "cross1", 0, true); + assertTrue(rs.next()); + + assertEquals(DatabaseMetaData.bestRowSession, rs.getInt(1)); + assertEquals("id", rs.getString(2)); + assertEquals(Types.INTEGER, rs.getInt(3)); + assertEquals("int", rs.getString(4)); + assertEquals(10, rs.getInt(5)); + assertEquals(0, rs.getInt(6)); + assertEquals(0, rs.getInt(7)); + assertEquals(DatabaseMetaData.bestRowNotPseudo, rs.getInt(8)); + assertFalse(rs.next()); + + rs = sharedConnection.getMetaData().getBestRowIdentifier(null, null, "cross2", 0, true); + assertTrue(rs.next()); + assertEquals(DatabaseMetaData.bestRowSession, rs.getInt(1)); + assertEquals("id", rs.getString(2)); + assertEquals(Types.INTEGER, rs.getInt(3)); + assertEquals("int", rs.getString(4)); + assertEquals(10, rs.getInt(5)); + assertEquals(0, rs.getInt(6)); + assertEquals(0, rs.getInt(7)); + assertEquals(DatabaseMetaData.bestRowNotPseudo, rs.getInt(8)); + assertTrue(rs.next()); + assertEquals(DatabaseMetaData.bestRowSession, rs.getInt(1)); + assertEquals("id2", rs.getString(2)); + assertEquals(Types.INTEGER, rs.getInt(3)); + assertEquals("int", rs.getString(4)); + assertEquals(10, rs.getInt(5)); + assertEquals(0, rs.getInt(6)); + assertEquals(0, rs.getInt(7)); + assertEquals(DatabaseMetaData.bestRowNotPseudo, rs.getInt(8)); + assertFalse(rs.next()); + + rs = sharedConnection.getMetaData().getBestRowIdentifier(null, null, "cross3", 0, true); + assertTrue(rs.next()); + + assertEquals(DatabaseMetaData.bestRowSession, rs.getInt(1)); + assertEquals("id", rs.getString(2)); + assertEquals(Types.INTEGER, rs.getInt(3)); + assertEquals("int", rs.getString(4)); + assertEquals(10, rs.getInt(5)); + assertEquals(0, rs.getInt(6)); + assertEquals(0, rs.getInt(7)); + assertEquals(DatabaseMetaData.bestRowNotPseudo, rs.getInt(8)); + assertFalse(rs.next()); + + // CHECK using PRI even if exist UNI + + rs = + sharedConnection + .getMetaData() + .getBestRowIdentifier(null, null, "getBestRowIdentifier1", 0, true); + assertTrue(rs.next()); + + assertEquals(DatabaseMetaData.bestRowSession, rs.getInt(1)); + assertEquals("i", rs.getString(2)); + assertEquals(Types.INTEGER, rs.getInt(3)); + assertEquals("int", rs.getString(4)); + assertEquals(10, rs.getInt(5)); + assertEquals(0, rs.getInt(6)); + assertEquals(0, rs.getInt(7)); + assertEquals(DatabaseMetaData.bestRowNotPseudo, rs.getInt(8)); + assertFalse(rs.next()); + + rs = + sharedConnection + .getMetaData() + .getBestRowIdentifier(null, null, "getBestRowIdentifier2", 0, true); + assertTrue(rs.next()); + assertEquals(DatabaseMetaData.bestRowSession, rs.getInt(1)); + assertEquals("id_ref0", rs.getString(2)); + assertEquals(Types.INTEGER, rs.getInt(3)); + assertEquals("int", rs.getString(4)); + assertEquals(10, rs.getInt(5)); + assertEquals(0, rs.getInt(6)); + assertEquals(0, rs.getInt(7)); + assertEquals(DatabaseMetaData.bestRowNotPseudo, rs.getInt(8)); + assertTrue(rs.next()); + + assertEquals(DatabaseMetaData.bestRowSession, rs.getInt(1)); + assertEquals("id_ref2", rs.getString(2)); + assertEquals(Types.INTEGER, rs.getInt(3)); + assertEquals("int", rs.getString(4)); + assertEquals(10, rs.getInt(5)); + assertEquals(0, rs.getInt(6)); + assertEquals(0, rs.getInt(7)); + assertEquals(DatabaseMetaData.bestRowNotPseudo, rs.getInt(8)); + assertFalse(rs.next()); } @Test @@ -1016,7 +1114,7 @@ public void getCrossReferenceResults() throws SQLException { assertEquals("cross2", rs.getString(7)); assertEquals("id_ref0", rs.getString(8)); assertEquals(1, rs.getInt(9)); - if (!isMariadbServer() && minVersion(8,0)) { + if (!isMariadbServer() && minVersion(8, 0)) { assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("UPDATE_RULE")); assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); } else { @@ -1036,7 +1134,7 @@ public void getCrossReferenceResults() throws SQLException { assertEquals("id_ref1", rs.getString(8)); assertEquals(1, rs.getInt(9)); assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt(10)); - if (!isMariadbServer() && minVersion(8,0)) { + if (!isMariadbServer() && minVersion(8, 0)) { assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); } else { assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); @@ -1059,7 +1157,7 @@ public void getCrossReferenceResults() throws SQLException { assertEquals("id_ref2", rs.getString(8)); assertEquals(2, rs.getInt(9)); assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt(10)); - if (!isMariadbServer() && minVersion(8,0)) { + if (!isMariadbServer() && minVersion(8, 0)) { assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getInt("DELETE_RULE")); } else { assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE")); @@ -1494,4 +1592,10 @@ public void metaTimeProcedureResultSet() throws SQLException { assertFalse(rs.next()); } + + @Test + public void various() throws SQLException { + DatabaseMetaData meta = sharedConnection.getMetaData(); + assertEquals(64, meta.getMaxProcedureNameLength()); + } } From 09541596d6dfad61973ec6cf38ddc14f1dbea43d Mon Sep 17 00:00:00 2001 From: rusher Date: Wed, 2 Sep 2020 11:19:12 +0200 Subject: [PATCH 15/30] [CONJ-812] DatabaseMetadata getBestRowIdentifier pseudo code correction for server without IS_GENERATED column in INFORMATION_SCHEMA.COLUMNS --- .../org/mariadb/jdbc/MariaDbDatabaseMetaData.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java index 0afbfdc06..538e31b3a 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java @@ -1068,6 +1068,10 @@ public ResultSet getBestRowIdentifier( throw new SQLException("'table' parameter cannot be null in getBestRowIdentifier()"); } + boolean hasIsGeneratedCol = + (connection.isServerMariaDb() && connection.versionGreaterOrEqual(10,2, 0)) + || (!connection.isServerMariaDb() && connection.versionGreaterOrEqual(8,0, 0)); + String sql = "SELECT " + bestRowSession @@ -1076,11 +1080,9 @@ public ResultSet getBestRowIdentifier( + " DATA_TYPE, DATA_TYPE TYPE_NAME," + " IF(NUMERIC_PRECISION IS NULL, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION) COLUMN_SIZE, 0 BUFFER_LENGTH," + " NUMERIC_SCALE DECIMAL_DIGITS," - + " if(IS_GENERATED='NEVER'," - + bestRowNotPseudo - + "," - + bestRowPseudo - + ") PSEUDO_COLUMN" + + ( hasIsGeneratedCol ? ("IF(IS_GENERATED='NEVER'," + bestRowNotPseudo + "," + bestRowPseudo + ")") : + bestRowNotPseudo ) + + " PSEUDO_COLUMN" + " FROM INFORMATION_SCHEMA.COLUMNS" + " WHERE (COLUMN_KEY = 'PRI'" + " OR (COLUMN_KEY = 'UNI' AND NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_KEY = " From a49abc131a88efaeaf6488e3ec76b2f2921a5fc2 Mon Sep 17 00:00:00 2001 From: rusher Date: Wed, 2 Sep 2020 11:38:13 +0200 Subject: [PATCH 16/30] [misc] travis test MariaDB 10.5 addition --- .travis.yml | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0cc134f74..ce0a6eda3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,35 +48,37 @@ matrix: jdk: openjdk11 - env: DB=mariadb:10.3 PACKET=8M jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=8M - jdk: oraclejdk11 - env: DB=mariadb:10.4 PACKET=8M jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=8M GALERA=true + - env: DB=mariadb:10.5 PACKET=8M jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=8M PROFILE=true + - env: DB=mariadb:10.5 PACKET=8M + jdk: oraclejdk11 + - env: DB=mariadb:10.5 PACKET=8M GALERA=true jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=8M TYPE=PREPARE + - env: DB=mariadb:10.5 PACKET=8M PROFILE=true jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=8M TYPE=REWRITE + - env: DB=mariadb:10.5 PACKET=8M TYPE=PREPARE jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=8M TYPE=MULTI + - env: DB=mariadb:10.5 PACKET=8M TYPE=REWRITE jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=20M + - env: DB=mariadb:10.5 PACKET=8M TYPE=MULTI jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=40M + - env: DB=mariadb:10.5 PACKET=20M jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=40M TYPE=BULK_SERVER + - env: DB=mariadb:10.5 PACKET=40M jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=40M TYPE=NO_BULK_CLIENT + - env: DB=mariadb:10.5 PACKET=40M TYPE=BULK_SERVER jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=40M TYPE=NO_BULK_SERVER + - env: DB=mariadb:10.5 PACKET=40M TYPE=NO_BULK_CLIENT jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=40M COMPRESSION=true + - env: DB=mariadb:10.5 PACKET=40M TYPE=NO_BULK_SERVER jdk: openjdk11 - - env: DB=mariadb:10.4 PACKET=8M + - env: DB=mariadb:10.5 PACKET=40M COMPRESSION=true + jdk: openjdk11 + - env: DB=mariadb:10.5 PACKET=8M jdk: openjdk12 - - env: DB=mariadb:10.4 PACKET=8M MAXSCALE_VERSION=2.2.9 + - env: DB=mariadb:10.5 PACKET=8M MAXSCALE_VERSION=2.2.9 jdk: openjdk11 script: From 70c406b2c0ef8349428a08244af63c0357261991 Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 3 Sep 2020 16:07:01 +0200 Subject: [PATCH 17/30] [CONJ-825] XAResource.isSameRM did always return false --- .../mariadb/jdbc/MariaDbDatabaseMetaData.java | 9 +++++---- .../org/mariadb/jdbc/MariaXaResource.java | 9 +++++++-- .../jdbc/DistributedTransactionTest.java | 2 +- .../org/mariadb/jdbc/MariaXaResourceTest.java | 20 +++++++++++++++++-- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java index 538e31b3a..3aa0aac0b 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java @@ -1069,8 +1069,8 @@ public ResultSet getBestRowIdentifier( } boolean hasIsGeneratedCol = - (connection.isServerMariaDb() && connection.versionGreaterOrEqual(10,2, 0)) - || (!connection.isServerMariaDb() && connection.versionGreaterOrEqual(8,0, 0)); + (connection.isServerMariaDb() && connection.versionGreaterOrEqual(10, 2, 0)) + || (!connection.isServerMariaDb() && connection.versionGreaterOrEqual(8, 0, 0)); String sql = "SELECT " @@ -1080,8 +1080,9 @@ public ResultSet getBestRowIdentifier( + " DATA_TYPE, DATA_TYPE TYPE_NAME," + " IF(NUMERIC_PRECISION IS NULL, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION) COLUMN_SIZE, 0 BUFFER_LENGTH," + " NUMERIC_SCALE DECIMAL_DIGITS," - + ( hasIsGeneratedCol ? ("IF(IS_GENERATED='NEVER'," + bestRowNotPseudo + "," + bestRowPseudo + ")") : - bestRowNotPseudo ) + + (hasIsGeneratedCol + ? ("IF(IS_GENERATED='NEVER'," + bestRowNotPseudo + "," + bestRowPseudo + ")") + : bestRowNotPseudo) + " PSEUDO_COLUMN" + " FROM INFORMATION_SCHEMA.COLUMNS" + " WHERE (COLUMN_KEY = 'PRI'" diff --git a/src/main/java/org/mariadb/jdbc/MariaXaResource.java b/src/main/java/org/mariadb/jdbc/MariaXaResource.java index f918561da..54e9475e4 100644 --- a/src/main/java/org/mariadb/jdbc/MariaXaResource.java +++ b/src/main/java/org/mariadb/jdbc/MariaXaResource.java @@ -217,8 +217,13 @@ public int getTransactionTimeout() { */ @Override public boolean isSameRM(XAResource xaResource) { - // Typically used by transaction manager to "join" transactions. We do not support joins, - // so always return false; + if (xaResource instanceof MariaXaResource) { + MariaXaResource other = (MariaXaResource) xaResource; + return connection + .getProtocol() + .getUrlParser() + .equals(other.connection.getProtocol().getUrlParser()); + } return false; } diff --git a/src/test/java/org/mariadb/jdbc/DistributedTransactionTest.java b/src/test/java/org/mariadb/jdbc/DistributedTransactionTest.java index 706266a84..674091924 100644 --- a/src/test/java/org/mariadb/jdbc/DistributedTransactionTest.java +++ b/src/test/java/org/mariadb/jdbc/DistributedTransactionTest.java @@ -110,7 +110,7 @@ private Xid newXid(Xid branchFrom) { */ private int test2PhaseCommit(boolean doCommit) throws Exception { - int connectionNumber = 1; + int connectionNumber = 2; Xid parentXid = newXid(); Connection[] connections = new Connection[connectionNumber]; diff --git a/src/test/java/org/mariadb/jdbc/MariaXaResourceTest.java b/src/test/java/org/mariadb/jdbc/MariaXaResourceTest.java index 140e7b4ae..712369046 100644 --- a/src/test/java/org/mariadb/jdbc/MariaXaResourceTest.java +++ b/src/test/java/org/mariadb/jdbc/MariaXaResourceTest.java @@ -1,10 +1,11 @@ package org.mariadb.jdbc; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; +import javax.sql.XAConnection; import org.junit.Test; -public class MariaXaResourceTest { +public class MariaXaResourceTest extends BaseTest { @Test public void xidToString() { assertEquals( @@ -19,4 +20,19 @@ public void xidToString() { MariaXaResource.xidToString( new MariaDbXid(-1010695802, new byte[] {0x00}, new byte[] {0x00, 0x01, 0x00}))); } + + @Test + public void xaRmTest() throws Exception { + MariaDbDataSource dataSource1 = new MariaDbDataSource(mDefUrl); + MariaDbDataSource dataSource2 = new MariaDbDataSource(mDefUrl + "&test=t"); + XAConnection con1 = dataSource1.getXAConnection(); + XAConnection con2 = dataSource1.getXAConnection(); + XAConnection con3 = dataSource2.getXAConnection(); + assertTrue(con1.getXAResource().isSameRM(con1.getXAResource())); + assertTrue(con1.getXAResource().isSameRM(con2.getXAResource())); + assertFalse(con1.getXAResource().isSameRM(con3.getXAResource())); + con1.close(); + con2.close(); + con3.close(); + } } From 41d39b6cb76eeb6621240040a2fb70365ce72b79 Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 3 Sep 2020 16:33:47 +0200 Subject: [PATCH 18/30] [CONJ-817] Table with primary key with DEFAULT function can not be inserted to: Current position is after the last row. correction for 10.5 server --- .../read/resultset/UpdatableResultSet.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java index 59380771d..94127a065 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java @@ -1058,6 +1058,7 @@ public void insertRow() throws SQLException { // user) StringBuilder insertSql = new StringBuilder("INSERT `" + database + "`.`" + table + "` ( "); StringBuilder valueClause = new StringBuilder(); + StringBuilder returningClause = new StringBuilder(); int fieldsIndex = 0; for (int pos = 0; pos < columnInformationLength; pos++) { @@ -1066,9 +1067,11 @@ public void insertRow() throws SQLException { if (pos != 0) { insertSql.append(","); valueClause.append(", "); + returningClause.append(", "); } insertSql.append("`").append(colInfo.getOriginalName()).append("`"); + returningClause.append("`").append(colInfo.getOriginalName()).append("`"); valueClause.append("?"); ParameterHolder value = parameterHolders[pos]; if (value != null) { @@ -1105,7 +1108,7 @@ public void insertRow() throws SQLException { } insertSql.append(") VALUES (").append(valueClause).append(")"); if (connection.isServerMariaDb() && connection.versionGreaterOrEqual(10, 5, 1)) { - insertSql.append(" RETURNING *"); + insertSql.append(" RETURNING ").append(returningClause); } ClientSidePreparedStatement insertPreparedStatement = connection.clientPrepareStatement(insertSql.toString()); @@ -1115,7 +1118,12 @@ public void insertRow() throws SQLException { } ResultSet insertRs = insertPreparedStatement.executeQuery(); - if (hasGeneratedPrimaryFields) { + if (connection.isServerMariaDb() && connection.versionGreaterOrEqual(10, 5, 1)) { + if (insertRs.next()) { + byte[] rowByte = ((SelectResultSet) insertRs).getCurrentRowData(); + addRowData(rowByte); + } + } else if (hasGeneratedPrimaryFields) { // primary is auto_increment (only one field) ResultSet rsKey = insertPreparedStatement.getGeneratedKeys(); if (rsKey.next()) { @@ -1130,14 +1138,7 @@ public void insertRow() throws SQLException { } } } else { - if (connection.isServerMariaDb() && connection.versionGreaterOrEqual(10, 5, 1)) { - if (insertRs.next()) { - byte[] rowByte = ((SelectResultSet) insertRs).getCurrentRowData(); - addRowData(rowByte); - } - } else { - addRowData(refreshRawData()); - } + addRowData(refreshRawData()); } Arrays.fill(parameterHolders, null); From eebe1e58266aeca74b9db9d47955ecdd0e226254 Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 3 Sep 2020 16:49:54 +0200 Subject: [PATCH 19/30] [misc] test update for local infile and 10.5 server --- src/test/java/org/mariadb/jdbc/LocalInfileDisableTest.java | 4 +++- src/test/resources/conf.properties | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/mariadb/jdbc/LocalInfileDisableTest.java b/src/test/java/org/mariadb/jdbc/LocalInfileDisableTest.java index 0fc916487..1c054dd9a 100644 --- a/src/test/java/org/mariadb/jdbc/LocalInfileDisableTest.java +++ b/src/test/java/org/mariadb/jdbc/LocalInfileDisableTest.java @@ -88,7 +88,9 @@ public void testLocalInfileWithoutInputStream() throws SQLException { assertTrue( message.contains( "Usage of LOCAL INFILE is disabled. To use it enable it via the connection property allowLocalInfile=true") - || message.contains("Loading local data is disabled")); + || message.contains("Loading local data is disabled") + || message.contains( + "The used command is not allowed because the MariaDB server or client has disabled the local infile capability")); } } } diff --git a/src/test/resources/conf.properties b/src/test/resources/conf.properties index 1fe773618..d764d02a6 100644 --- a/src/test/resources/conf.properties +++ b/src/test/resources/conf.properties @@ -2,4 +2,5 @@ DB_HOST=localhost DB_PORT=3306 DB_DATABASE=testj DB_USER=root -DB_PASSWORD= \ No newline at end of file +DB_PASSWORD= +DB_OTHER= \ No newline at end of file From 79a9b64b8663642ca8ffab01772b7296b9f1daf7 Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 3 Sep 2020 17:06:22 +0200 Subject: [PATCH 20/30] [CONJ-825] XAResource.isSameRM test correction --- src/test/java/org/mariadb/jdbc/MariaXaResourceTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/mariadb/jdbc/MariaXaResourceTest.java b/src/test/java/org/mariadb/jdbc/MariaXaResourceTest.java index 712369046..126301db8 100644 --- a/src/test/java/org/mariadb/jdbc/MariaXaResourceTest.java +++ b/src/test/java/org/mariadb/jdbc/MariaXaResourceTest.java @@ -23,8 +23,9 @@ public void xidToString() { @Test public void xaRmTest() throws Exception { - MariaDbDataSource dataSource1 = new MariaDbDataSource(mDefUrl); - MariaDbDataSource dataSource2 = new MariaDbDataSource(mDefUrl + "&test=t"); + String url = System.getProperty("dbUrl", mDefUrl); + MariaDbDataSource dataSource1 = new MariaDbDataSource(url); + MariaDbDataSource dataSource2 = new MariaDbDataSource(url + "&test=t"); XAConnection con1 = dataSource1.getXAConnection(); XAConnection con2 = dataSource1.getXAConnection(); XAConnection con3 = dataSource2.getXAConnection(); From a8f9b5fc820036f7e303f6eeedd244d15b3328ee Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 4 Sep 2020 15:49:57 +0200 Subject: [PATCH 21/30] [CONJ-817] correction handling default data when resultset is using binary protocol --- .../com/read/resultset/SelectResultSet.java | 2 +- .../read/resultset/UpdatableResultSet.java | 38 +++++++++++++------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java index 08b6c4a55..aac0eb49a 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java @@ -87,7 +87,7 @@ public class SelectResultSet implements ResultSet { private boolean isEof; private boolean callableResult; private MariaDbStatement statement; - private RowProtocol row; + protected RowProtocol row; private int dataFetchTime; private boolean streaming; private byte[][] data; diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java index 94127a065..a7720ded8 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java @@ -65,6 +65,7 @@ import org.mariadb.jdbc.*; import org.mariadb.jdbc.internal.ColumnType; import org.mariadb.jdbc.internal.com.read.dao.Results; +import org.mariadb.jdbc.internal.com.read.resultset.rowprotocol.BinaryRowProtocol; import org.mariadb.jdbc.internal.com.send.parameters.*; import org.mariadb.jdbc.internal.io.input.PacketInputStream; import org.mariadb.jdbc.internal.protocol.Protocol; @@ -1060,22 +1061,26 @@ public void insertRow() throws SQLException { StringBuilder valueClause = new StringBuilder(); StringBuilder returningClause = new StringBuilder(); int fieldsIndex = 0; + boolean firstParam = true; for (int pos = 0; pos < columnInformationLength; pos++) { UpdatableColumnDefinition colInfo = getUpdatableColumns()[pos]; if (pos != 0) { - insertSql.append(","); - valueClause.append(", "); returningClause.append(", "); } - - insertSql.append("`").append(colInfo.getOriginalName()).append("`"); returningClause.append("`").append(colInfo.getOriginalName()).append("`"); - valueClause.append("?"); + ParameterHolder value = parameterHolders[pos]; if (value != null) { + if (!firstParam) { + insertSql.append(","); + valueClause.append(", "); + } + insertSql.append("`").append(colInfo.getOriginalName()).append("`"); + valueClause.append("?"); paramMap.put((fieldsIndex++) + 1, value); + firstParam = false; } else { if (colInfo.isPrimary()) { if (colInfo.isAutoIncrement() || colInfo.hasDefault()) { @@ -1098,11 +1103,17 @@ public void insertRow() throws SQLException { "Cannot call insertRow() not setting value for primary key %s", colInfo.getOriginalName())); } - paramMap.put((fieldsIndex++) + 1, new DefaultParameter()); - } else { - paramMap.put( - (fieldsIndex++) + 1, - colInfo.hasDefault() ? new DefaultParameter() : new NullParameter()); + // paramMap.put((fieldsIndex++) + 1, new DefaultParameter()); + } else if (!colInfo.hasDefault()) { + if (!firstParam) { + insertSql.append(","); + valueClause.append(", "); + } + firstParam = false; + insertSql.append("`").append(colInfo.getOriginalName()).append("`"); + valueClause.append("?"); + + paramMap.put((fieldsIndex++) + 1, new NullParameter()); } } } @@ -1110,8 +1121,11 @@ public void insertRow() throws SQLException { if (connection.isServerMariaDb() && connection.versionGreaterOrEqual(10, 5, 1)) { insertSql.append(" RETURNING ").append(returningClause); } - ClientSidePreparedStatement insertPreparedStatement = - connection.clientPrepareStatement(insertSql.toString()); + + BasePrepareStatement insertPreparedStatement = + (row instanceof BinaryRowProtocol) + ? connection.serverPrepareStatement(insertSql.toString()) + : connection.clientPrepareStatement(insertSql.toString()); for (Map.Entry entry : paramMap.entrySet()) { insertPreparedStatement.setParameter(entry.getKey(), entry.getValue()); From 0e8d5739c0ebdbf622ba3402622f295ce70804bd Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 10 Sep 2020 16:02:38 +0200 Subject: [PATCH 22/30] [CONJ-805] maxFieldSize truncation correction #156 Correction of possible ArrayOutOfBoundsError when using maxFieldSize Correct behaviour of maxFieldSize, limiting not length of the string, but byte length. --- .../rowprotocol/TextRowProtocol.java | 2 +- .../java/org/mariadb/jdbc/StringUTFTest.java | 28 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java index b9142fdee..3631b56e7 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java @@ -234,7 +234,7 @@ public String getInternalString(ColumnDefinition columnInfo, Calendar cal, TimeZ } if (maxFieldSize > 0) { - return new String(buf, pos, Math.min(maxFieldSize, length), StandardCharsets.UTF_8); + return new String(buf, pos, Math.min(maxFieldSize, length), StandardCharsets.UTF_8); } return new String(buf, pos, length, StandardCharsets.UTF_8); diff --git a/src/test/java/org/mariadb/jdbc/StringUTFTest.java b/src/test/java/org/mariadb/jdbc/StringUTFTest.java index 53fb046c3..aac07f7a3 100644 --- a/src/test/java/org/mariadb/jdbc/StringUTFTest.java +++ b/src/test/java/org/mariadb/jdbc/StringUTFTest.java @@ -67,25 +67,27 @@ public class StringUTFTest extends BaseTest { */ @BeforeClass() public static void initClass() throws SQLException { - createTable( - "stringutftest", - "id int not null primary key auto_increment, stringutf varchar(40)", - "COLLATE='utf8_general_ci'"); + createTable("stringutftest", "stringutf varchar(40)", "COLLATE='utf8mb4_general_ci'"); } @Test - public void testString() throws SQLException { + public void maxFieldSizeTruncation() throws SQLException { PreparedStatement ps = - sharedConnection.prepareStatement("insert into stringutftest values(null, ?)"); - ps.setString(1, "śćżźęąółń"); + sharedConnection.prepareStatement("insert into stringutftest(stringutf) values(?)"); + ps.setString(1, "śćżź"); ps.execute(); + + ps.setString(1, "1234567\uD83E\uDD42"); + ps.execute(); + Statement stmt = sharedConnection.createStatement(); - stmt.setMaxFieldSize(40); + stmt.setMaxFieldSize(10); ResultSet rs = stmt.executeQuery("select * from stringutftest"); - if (rs.next()) { - assertEquals("śćżźęąółń", rs.getString(2)); - } else { - fail("must have a result !"); - } + assertTrue(rs.next()); + // no truncation + assertEquals("śćżź", rs.getString(1)); + assertTrue(rs.next()); + // truncation + assertEquals("1234567�", rs.getString(1)); } } From 6601971b1d0252662475c443dd00219332138dd7 Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 10 Sep 2020 17:29:42 +0200 Subject: [PATCH 23/30] [CONJ-828] new option `ensureSocketState` When a query is issued, the connector ensures that any streaming result-set will be fully read from the socket before issuing a new command. This permits to ensure the socket state. Adding a new option `ensureSocketState` that when enable will ensure that the socket buffer is empty before issuing new command. (this doesn't concern pipelining commands). If data is present in socket. An error will be raised, throwing the content of socket data to permit identification of error. The goal of this option is mainly for debugging. This functionality add a few overheads so will be disabled by default --- .../io/input/DecompressPacketInputStream.java | 4 ++ .../internal/io/input/PacketInputStream.java | 3 ++ .../io/input/ReadAheadBufferedStream.java | 2 +- .../protocol/AbstractQueryProtocol.java | 36 ++++++++++++++++-- .../org/mariadb/jdbc/util/DefaultOptions.java | 7 +++- .../java/org/mariadb/jdbc/util/Options.java | 1 + .../java/org/mariadb/jdbc/StatementTest.java | 38 +++++++++++++++++++ 7 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/internal/io/input/DecompressPacketInputStream.java b/src/main/java/org/mariadb/jdbc/internal/io/input/DecompressPacketInputStream.java index 9703b665d..88c85ee53 100644 --- a/src/main/java/org/mariadb/jdbc/internal/io/input/DecompressPacketInputStream.java +++ b/src/main/java/org/mariadb/jdbc/internal/io/input/DecompressPacketInputStream.java @@ -324,4 +324,8 @@ public void setServerThreadId(long serverThreadId, Boolean isMaster) { public void setTraceCache(LruTraceCache traceCache) { this.traceCache = traceCache; } + + public InputStream getInputStream() { + return inputStream; + } } diff --git a/src/main/java/org/mariadb/jdbc/internal/io/input/PacketInputStream.java b/src/main/java/org/mariadb/jdbc/internal/io/input/PacketInputStream.java index c34b04372..71b23570e 100644 --- a/src/main/java/org/mariadb/jdbc/internal/io/input/PacketInputStream.java +++ b/src/main/java/org/mariadb/jdbc/internal/io/input/PacketInputStream.java @@ -53,6 +53,7 @@ package org.mariadb.jdbc.internal.io.input; import java.io.IOException; +import java.io.InputStream; import org.mariadb.jdbc.internal.com.read.Buffer; import org.mariadb.jdbc.internal.io.LruTraceCache; @@ -71,4 +72,6 @@ public interface PacketInputStream { void setServerThreadId(long serverThreadId, Boolean isMaster); void setTraceCache(LruTraceCache traceCache); + + InputStream getInputStream(); } diff --git a/src/main/java/org/mariadb/jdbc/internal/io/input/ReadAheadBufferedStream.java b/src/main/java/org/mariadb/jdbc/internal/io/input/ReadAheadBufferedStream.java index 94bfe02cc..547f5d5cf 100644 --- a/src/main/java/org/mariadb/jdbc/internal/io/input/ReadAheadBufferedStream.java +++ b/src/main/java/org/mariadb/jdbc/internal/io/input/ReadAheadBufferedStream.java @@ -137,7 +137,7 @@ public synchronized long skip(long n) throws IOException { } public synchronized int available() throws IOException { - throw new IOException("available from socket not implemented"); + return end - pos + super.available(); } public synchronized void reset() throws IOException { diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java index 3ab9f0ceb..0f84fd3fe 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java @@ -55,10 +55,7 @@ import static org.mariadb.jdbc.internal.com.Packet.*; import static org.mariadb.jdbc.internal.util.SqlStates.*; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; @@ -1940,6 +1937,37 @@ private void cmdPrologue() throws SQLException { throw exceptionFactory.create("Connection is closed", "08000", 1220); } interrupted = false; + if (this.options.ensureSocketState) { + // ensure that the socket buffer is empty before issuing new command. + // (this doesn't concern pipelining commands). + // If data is present in socket, an error will be raised, throwing the content of socket data to permit + // identification of error. + try { + int avail = this.reader.getInputStream().available(); + if (avail > 0) { + // unexpected data in socket buffer + + // reading socket buffer to add content to error. + byte[] data = new byte[Math.min(avail, 16000)]; + int remaining = avail; + int off = 0; + do { + int count = this.reader.getInputStream().read(data, off, remaining); + if (count < 0) { + break; + } + remaining -= count; + off += count; + } while (remaining > 0); + + throw exceptionFactory.create( + "Unexpected data in socket buffer:" + Utils.hexdump(data), "HY000"); + } + + } catch (IOException ioe) { + throw exceptionFactory.create("Unexpected socket error", "08000", ioe); + } + } } /** diff --git a/src/main/java/org/mariadb/jdbc/util/DefaultOptions.java b/src/main/java/org/mariadb/jdbc/util/DefaultOptions.java index c370e85ab..a74a039b6 100644 --- a/src/main/java/org/mariadb/jdbc/util/DefaultOptions.java +++ b/src/main/java/org/mariadb/jdbc/util/DefaultOptions.java @@ -685,8 +685,13 @@ public enum DefaultOptions { Boolean.TRUE, "2.6.0", "manage session_track_schema setting when server has CLIENT_SESSION_TRACK capability", + false), + ENSURE_SOCKET_STATE( + "ensureSocketState", + Boolean.FALSE, + "2.7.0", + "ensure socket state before issuing a new command", false); - private final String optionName; private final String description; private final boolean required; diff --git a/src/main/java/org/mariadb/jdbc/util/Options.java b/src/main/java/org/mariadb/jdbc/util/Options.java index 26b14e7ab..8e7980943 100644 --- a/src/main/java/org/mariadb/jdbc/util/Options.java +++ b/src/main/java/org/mariadb/jdbc/util/Options.java @@ -140,6 +140,7 @@ public class Options implements Cloneable { // MySQL sha authentication public String serverRsaPublicKeyFile; public boolean allowPublicKeyRetrieval; + public boolean ensureSocketState; @Override public String toString() { diff --git a/src/test/java/org/mariadb/jdbc/StatementTest.java b/src/test/java/org/mariadb/jdbc/StatementTest.java index c7ff57201..d956c2603 100644 --- a/src/test/java/org/mariadb/jdbc/StatementTest.java +++ b/src/test/java/org/mariadb/jdbc/StatementTest.java @@ -743,4 +743,42 @@ public void escaping() throws Exception { } } } + + @Test + public void ensureStreamingState() throws Exception { + Assume.assumeTrue(isMariadbServer() && minVersion(10, 1)); + createProcedure( + "ensureStreamingState", + "(INOUT p1 INT) BEGIN SELECT * from seq_1_to_3; SELECT * from " + "seq_5_to_7; END"); + Statement stmt = sharedConnection.createStatement(); + PreparedStatement prep = sharedConnection.prepareCall("CALL ensureStreamingState(?)"); + prep.setObject(1, 5); + prep.setFetchSize(1); + prep.execute(); + + ResultSet rs = stmt.executeQuery("SELECT 50"); + assertTrue(rs.next()); + assertEquals(50, rs.getInt(1)); + rs = prep.getResultSet(); + assertTrue(rs.next()); + assertEquals(1, rs.getInt(1)); + assertTrue(rs.next()); + assertEquals(2, rs.getInt(1)); + assertTrue(rs.next()); + assertEquals(3, rs.getInt(1)); + assertFalse(rs.next()); + + assertTrue(prep.getMoreResults()); + + rs = prep.getResultSet(); + assertTrue(rs.next()); + assertEquals(5, rs.getInt(1)); + assertTrue(rs.next()); + assertEquals(6, rs.getInt(1)); + assertTrue(rs.next()); + assertEquals(7, rs.getInt(1)); + assertFalse(rs.next()); + + assertFalse(prep.getMoreResults()); + } } From 49f14d63763bcb7d974212f9fef799dbffb8fcaa Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 10 Sep 2020 18:37:59 +0200 Subject: [PATCH 24/30] [misc] skysql test suite correction --- src/test/java/org/mariadb/jdbc/StatementTest.java | 1 + .../java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/mariadb/jdbc/StatementTest.java b/src/test/java/org/mariadb/jdbc/StatementTest.java index d956c2603..23202c1ad 100644 --- a/src/test/java/org/mariadb/jdbc/StatementTest.java +++ b/src/test/java/org/mariadb/jdbc/StatementTest.java @@ -780,5 +780,6 @@ public void ensureStreamingState() throws Exception { assertFalse(rs.next()); assertFalse(prep.getMoreResults()); + prep.close(); } } diff --git a/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java b/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java index 5d40f3285..4c0caf102 100644 --- a/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java +++ b/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java @@ -347,7 +347,7 @@ public void testTimeUtcNow() throws SQLException { @Test public void testTimeOffsetNowUseServer() throws SQLException { - Assume.assumeFalse("true".equals(System.getenv("AURORA"))); + Assume.assumeTrue(System.getenv("AURORA") == null || System.getenv("SKYSQL") == null); try (Connection connection = setConnection("&useLegacyDatetimeCode=false&serverTimezone=+5:00")) { setSessionTimeZone(connection, "+5:00"); From 4f798679d2eb76e0460e2119b218628fa7e8d72a Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 10 Sep 2020 18:48:35 +0200 Subject: [PATCH 25/30] [CONJ-829] Option to cache callablestatement disabled by default Option `cacheCallableStmts` is enable by default. the default will now be disabled for different reasons : * differ compared to MySQL driver. * more important, since using binary protocol when using out parameters, this can lead to having a lot of prepare statements cached in the server without the user knowing it, even resulting reaching max_prepared_stmt_count maximum. --- src/main/java/org/mariadb/jdbc/util/DefaultOptions.java | 4 ++-- src/main/java/org/mariadb/jdbc/util/Options.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/util/DefaultOptions.java b/src/main/java/org/mariadb/jdbc/util/DefaultOptions.java index a74a039b6..7664503fb 100644 --- a/src/main/java/org/mariadb/jdbc/util/DefaultOptions.java +++ b/src/main/java/org/mariadb/jdbc/util/DefaultOptions.java @@ -399,9 +399,9 @@ public enum DefaultOptions { false), CACHE_CALLABLE_STMTS( "cacheCallableStmts", - Boolean.TRUE, + Boolean.FALSE, "1.4.0", - "enable/disable callable Statement cache, default" + " true.", + "enable/disable callable Statement cache, default false.", false), CALLABLE_STMT_CACHE_SIZE( "callableStmtCacheSize", diff --git a/src/main/java/org/mariadb/jdbc/util/Options.java b/src/main/java/org/mariadb/jdbc/util/Options.java index 8e7980943..613372916 100644 --- a/src/main/java/org/mariadb/jdbc/util/Options.java +++ b/src/main/java/org/mariadb/jdbc/util/Options.java @@ -91,7 +91,7 @@ public class Options implements Cloneable { public boolean useServerPrepStmts; public boolean continueBatchOnError = true; public boolean jdbcCompliantTruncation = true; - public boolean cacheCallableStmts = true; + public boolean cacheCallableStmts; public int callableStmtCacheSize = 150; public String connectionAttributes; public Boolean useBatchMultiSend; From 8e2d523d51f92be45f4eded5c647eea3de4533ad Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 11 Sep 2020 12:07:34 +0200 Subject: [PATCH 26/30] [CONJ-830] issue SSL negotiation only if server show SSL capability. The connector was initiating SSL negotiation when option `useSsl` is set even if server doesn't support SSL. This was resulting throwing a wrong exception that doesn't show the initial problem --- .../mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java index a8a4b0de2..b124cbf38 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java @@ -633,7 +633,7 @@ private void sslWrapper( if (Boolean.TRUE.equals(options.useSsl)) { if ((serverCapabilities & MariaDbServerCapabilities.SSL) == 0) { - exceptionFactory.create( + throw exceptionFactory.create( "Trying to connect with ssl, but ssl not enabled in the server", "08000"); } clientCapabilities |= MariaDbServerCapabilities.SSL; From 5bf84cca278adec657a1ef4f646b23789bbc7a9c Mon Sep 17 00:00:00 2001 From: rusher Date: Mon, 14 Sep 2020 09:49:45 +0200 Subject: [PATCH 27/30] [CONJ-827] update maxscale test to recent version --- .travis.yml | 7 +- .travis/maxscale-compose.yml | 34 +++-- .travis/maxscale/Dockerfile | 6 +- .travis/maxscale/maxscale.cnf | 118 +++++++++--------- .travis/script.sh | 19 +-- .travis/sql/dbinit.sql | 8 +- .../protocol/AbstractConnectProtocol.java | 14 ++- .../protocol/AbstractQueryProtocol.java | 5 +- .../org/mariadb/jdbc/AutoReconnectTest.java | 5 +- .../java/org/mariadb/jdbc/CancelTest.java | 3 +- .../java/org/mariadb/jdbc/ConnectionTest.java | 13 +- .../mariadb/jdbc/CredentialPluginTest.java | 11 +- .../org/mariadb/jdbc/DataSourcePoolTest.java | 2 +- .../java/org/mariadb/jdbc/DataSourceTest.java | 2 +- .../java/org/mariadb/jdbc/DriverTest.java | 6 +- .../org/mariadb/jdbc/ErrorMessageTest.java | 3 +- .../java/org/mariadb/jdbc/FetchSizeTest.java | 13 +- .../jdbc/LocalInfileInputStreamTest.java | 2 +- .../jdbc/MariaDbPoolDataSourceTest.java | 4 +- src/test/java/org/mariadb/jdbc/MultiTest.java | 2 +- .../mariadb/jdbc/PooledConnectionTest.java | 2 +- src/test/java/org/mariadb/jdbc/SslTest.java | 103 ++++++++++----- .../org/mariadb/jdbc/StoredProcedureTest.java | 18 ++- .../java/org/mariadb/jdbc/TimeoutTest.java | 3 +- .../jdbc/TimezoneDaylightSavingTimeTest.java | 2 +- .../jdbc/failover/MonoServerFailoverTest.java | 2 +- 26 files changed, 247 insertions(+), 160 deletions(-) diff --git a/.travis.yml b/.travis.yml index ce0a6eda3..88a8a50c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,9 @@ cache: directories: - $HOME/.m2 +env: + - SSLPORT=3305 + matrix: allow_failures: - env: DB=build PACKET=8M @@ -36,8 +39,6 @@ matrix: jdk: openjdk11 - env: SKYSQL=true PACKET=8M jdk: openjdk11 - - env: DB=mysql:5.6 PACKET=8M - jdk: openjdk11 - env: DB=mysql:5.7 PACKET=8M jdk: openjdk11 - env: DB=mysql:8.0 PACKET=8M ADDITIONAL_CONF=--default-authentication-plugin=mysql_native_password --caching_sha2_password_private_key_path=/etc/sslcert/server.key --caching_sha2_password_public_key_path=/etc/sslcert/public.key @@ -78,7 +79,7 @@ matrix: jdk: openjdk11 - env: DB=mariadb:10.5 PACKET=8M jdk: openjdk12 - - env: DB=mariadb:10.5 PACKET=8M MAXSCALE_VERSION=2.2.9 + - env: DB=mariadb:10.5 PACKET=8M MAXSCALE_VERSION=2.5.3 MAXSCALE_TEST_DISABLE=true SSLPORT=4009 jdk: openjdk11 script: diff --git a/.travis/maxscale-compose.yml b/.travis/maxscale-compose.yml index ae8ea7d03..9fb200649 100644 --- a/.travis/maxscale-compose.yml +++ b/.travis/maxscale-compose.yml @@ -1,17 +1,5 @@ version: '2.1' services: - maxscale: - depends_on: - - db - ports: - - 4006:4006 - - 4007:4007 - - 4008:4008 - build: - context: . - dockerfile: maxscale/Dockerfile - args: - MAXSCALE_VERSION: $MAXSCALE_VERSION db: image: $DB command: --max-connections=500 --max-allowed-packet=$PACKET --innodb-log-file-size=$INNODB_LOG_FILE_SIZE --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --ssl-ca=/etc/sslcert/ca.crt --ssl-cert=/etc/sslcert/server.crt --ssl-key=/etc/sslcert/server.key --bind-address=0.0.0.0 @@ -23,3 +11,25 @@ services: environment: MYSQL_DATABASE: testj MYSQL_ALLOW_EMPTY_PASSWORD: 1 + healthcheck: + test: ["CMD", "mysql", "--protocol=tcp", "-ubob", "-h127.0.0.1", "-ubob"] + timeout: 20s + retries: 10 + + maxscale: + depends_on: + db: + condition: service_healthy + links: + - "db:database" + ports: + - 4006:4006 + - 4008:4008 + - 4009:4009 + volumes: + - $SSLCERT:/etc/sslcert + build: + context: . + dockerfile: maxscale/Dockerfile + args: + MAXSCALE_VERSION: $MAXSCALE_VERSION diff --git a/.travis/maxscale/Dockerfile b/.travis/maxscale/Dockerfile index 0ae214d93..0a60b4e79 100644 --- a/.travis/maxscale/Dockerfile +++ b/.travis/maxscale/Dockerfile @@ -1,12 +1,12 @@ FROM centos:7 ARG MAXSCALE_VERSION -ENV MAXSCALE_VERSION ${MAXSCALE_VERSION:-2.1.4} +ENV MAXSCALE_VERSION ${MAXSCALE_VERSION:-2.5.3} COPY maxscale/mariadb.repo /etc/yum.repos.d/ RUN rpm --import https://yum.mariadb.org/RPM-GPG-KEY-MariaDB \ - && yum -y install https://downloads.mariadb.com/MaxScale/${MAXSCALE_VERSION}/centos/7/x86_64/maxscale-${MAXSCALE_VERSION}-1.centos.7.x86_64.rpm \ + && yum -y install https://downloads.mariadb.com/MaxScale/${MAXSCALE_VERSION}/centos/7/x86_64/maxscale-${MAXSCALE_VERSION}-2.rhel.7.x86_64.rpm \ && yum -y update RUN yum -y install maxscale-${MAXSCALE_VERSION} MariaDB-client \ @@ -14,8 +14,8 @@ RUN yum -y install maxscale-${MAXSCALE_VERSION} MariaDB-client \ && rm -rf /tmp/* COPY maxscale/docker-entrypoint.sh / -RUN chmod 777 /etc/maxscale.cnf COPY maxscale/maxscale.cnf /etc/ +RUN chmod 777 /etc/maxscale.cnf RUN chmod 777 /docker-entrypoint.sh diff --git a/.travis/maxscale/maxscale.cnf b/.travis/maxscale/maxscale.cnf index 01f5dbd0d..8a85c9e84 100644 --- a/.travis/maxscale/maxscale.cnf +++ b/.travis/maxscale/maxscale.cnf @@ -1,45 +1,59 @@ -# MaxScale documentation on GitHub: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Documentation-Contents.md +# MaxScale documentation: +# https://mariadb.com/kb/en/mariadb-maxscale-24/ # Global parameters # # Complete list of configuration options: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Getting-Started/Configuration-Guide.md - +# https://mariadb.com/kb/en/mariadb-maxscale-24-mariadb-maxscale-configuration-guide/ [maxscale] -threads=2 -log_messages=1 -log_trace=1 -log_debug=1 +threads=auto # Server definitions # # Set the address of the server to the network -# address of a MySQL server. +# address of a MariaDB server. # +[server2] +type=server +address=database +port=3306 +protocol=MariaDBBackend +ssl=true +ssl_ca_cert=/etc/sslcert/server.crt +ssl_cert=/etc/sslcert/client.crt +ssl_key=/etc/sslcert/client.key + + [server1] type=server address=db port=3306 protocol=MariaDBBackend -authenticator_options=skip_authentication=true -router_options=master + # Monitor for the servers # # This will keep MaxScale aware of the state of the servers. -# MySQL Monitor documentation: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Monitors/MySQL-Monitor.md +# MariaDB Monitor documentation: +# https://mariadb.com/kb/en/mariadb-maxscale-24-mariadb-monitor/ -[MySQLMonitor] +[MariaDB-Monitor] type=monitor module=mariadbmon servers=server1 user=boby -passwd=hey -monitor_interval=10000 +password=hey +monitor_interval=2000 + +[MariaDB-Monitor2] +type=monitor +module=mariadbmon +servers=server2 +user=boby +password=hey +monitor_interval=2000 # Service definitions # @@ -48,78 +62,60 @@ monitor_interval=10000 # # ReadConnRoute documentation: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Routers/ReadConnRoute.md +# https://mariadb.com/kb/en/mariadb-maxscale-24-readconnroute/ -[Read-OnlyService] -enable_root_user=1 -version_string=10.4.99-MariaDB-maxScale +[Read-Only-Service] type=service router=readconnroute servers=server1 user=boby -passwd=hey +password=hey router_options=slave -localhost_match_wildcard_host=1 -[Read-WriteService] -enable_root_user=1 -version_string=10.4.99-MariaDB-maxScale +# ReadWriteSplit documentation: +# https://mariadb.com/kb/en/mariadb-maxscale-24-readwritesplit/ + +[Read-Write-Service] type=service router=readwritesplit servers=server1 +version_string=10.5.99-MariaDB-maxScale user=boby -passwd=hey -localhost_match_wildcard_host=1 +password=hey -[WriteService] +[Read-Write-Service2] type=service -router=readconnroute -servers=server1 +router=readwritesplit +version_string=10.5.99-MariaDB-maxScale +servers=server2 user=boby -passwd=hey -router_options=master -localhost_match_wildcard_host=1 -version_string=10.4.99-MariaDB-maxscale - - -# This service enables the use of the MaxAdmin interface -# MaxScale administration guide: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Reference/MaxAdmin.mda - -[MaxAdminService] -enable_root_user=1 -version_string=10.4.99-MariaDB-maxScale -type=service -router=cli +password=hey # Listener definitions for the services # # These listeners represent the ports the # services will listen on. # -[WriteListener] -type=listener -service=WriteService -protocol=MariaDBClient -port=4007 -#socket=/var/lib/maxscale/writeconn.sock -[Read-OnlyListener] +[Read-Only-Listener] type=listener -service=Read-OnlyService +service=Read-Only-Service protocol=MariaDBClient port=4008 -#socket=/var/lib/maxscale/readconn.sock -[Read-WriteListener] +[Read-Write-Listener] type=listener -service=Read-WriteService +service=Read-Write-Service protocol=MariaDBClient port=4006 -#socket=/var/lib/maxscale/rwsplit.sock -[MaxAdminListener] + +[Read-Write-Listener2] type=listener -service=MaxAdminService -protocol=maxscaled -socket=/tmp/maxadmin.sock +service=Read-Write-Service2 +protocol=MariaDBClient +port=4009 +ssl=true +ssl_ca_cert=/etc/sslcert/ca.crt +ssl_cert=/etc/sslcert/server.crt +ssl_key=/etc/sslcert/server.key diff --git a/.travis/script.sh b/.travis/script.sh index cecd472fc..b10af628c 100644 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -63,7 +63,8 @@ else -Dkeystore2Password="kspass" -DkeyPassword="kspasskey" \ -Dkeystore2PathP12="$SSLCERT/fullclient-keystore.p12" \ -DrunLongTest=true \ - -DserverPublicKey="$SSLCERT/public.key" ) + -DserverPublicKey="$SSLCERT/public.key"\ + -DsslPort="$SSLPORT") if [ -n "$AURORA" ] ; then if [ -n "$AURORA_STRING_URL" ] ; then @@ -82,9 +83,9 @@ else ################################################################################################################### # launch Maxscale with one server ################################################################################################################### - mysql=( mysql --protocol=tcp -ubob -h127.0.0.1 --port=4007 ) + mysql=( mysql --protocol=TCP -ubob -h127.0.0.1 --port=4006 test2) export COMPOSE_FILE=.travis/maxscale-compose.yml - urlString='jdbc:mariadb://mariadb.example.com:4007/testj?user=bob&killFetchStmtOnClose=false&enablePacketDebug=true' + urlString='jdbc:mariadb://mariadb.example.com:4006/testj?user=bob&enablePacketDebug=true' docker-compose -f ${COMPOSE_FILE} build docker-compose -f ${COMPOSE_FILE} up -d else @@ -93,7 +94,7 @@ else ################################################################################################################### # launch 3 galera servers ################################################################################################################### - mysql=( mysql --protocol=tcp -ubob -hmariadb.example.com --port=3106 ) + mysql=( mysql --protocol=TCP -ubob -hmariadb.example.com --port=3106 test2) export COMPOSE_FILE=.travis/galera-compose.yml urlString='jdbc:mariadb://mariadb.example.com:3106/testj?user=bob&enablePacketDebug=true' @@ -101,7 +102,7 @@ else docker-compose -f ${COMPOSE_FILE} up -d SLEEP 10 else - mysql=( mysql --protocol=tcp -ubob -hmariadb.example.com --port=3106 ) + mysql=( mysql --protocol=tcp -ubob -hmariadb.example.com --port=3106 test2) urlString='jdbc:mariadb://mariadb.example.com:3106/testj?user=bob&enablePacketDebug=true' docker run \ @@ -135,7 +136,7 @@ else ################################################################################################################### # launch docker server ################################################################################################################### - mysql=( mysql --protocol=tcp -ubob -h127.0.0.1 --port=3305 ) + mysql=( mysql --protocol=TCP -ubob -hmariadb.example.com --port=3305 test2) export COMPOSE_FILE=.travis/docker-compose.yml docker-compose -f ${COMPOSE_FILE} up -d @@ -147,12 +148,12 @@ else # wait for docker initialisation ################################################################################################################### - for i in {60..0}; do - if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then + for i in {15..0}; do + if echo 'SELECT 1' | "${mysql[@]}" ; then break fi echo 'data server still not active' - sleep 1 + sleep 2 done diff --git a/.travis/sql/dbinit.sql b/.travis/sql/dbinit.sql index e9dc8b690..eff6d41e6 100644 --- a/.travis/sql/dbinit.sql +++ b/.travis/sql/dbinit.sql @@ -1,8 +1,14 @@ +CREATE USER 'bob'@'localhost'; +GRANT ALL ON *.* TO 'bob'@'localhost' with grant option; + CREATE USER 'bob'@'%'; GRANT ALL ON *.* TO 'bob'@'%' with grant option; CREATE USER 'boby'@'%' identified by 'hey'; -GRANT ALL ON *.* TO 'boby'@'%' with grant option; +GRANT ALL ON *.* TO 'boby'@'%' identified by 'hey' with grant option; + +CREATE USER 'boby'@'localhost' identified by 'hey'; +GRANT ALL ON *.* TO 'boby'@'localhost' identified by 'hey' with grant option; FLUSH PRIVILEGES; diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java index b124cbf38..2be182ace 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java @@ -872,7 +872,7 @@ private void postConnectionQueries() throws SQLException { sendPipelineAdditionalData(); readPipelineAdditionalData(serverData); } catch (SQLException sqle) { - if ("08".equals(sqle.getSQLState())) { + if (sqle.getSQLState() != null && sqle.getSQLState().startsWith("08")) { throw sqle; } // in case pipeline is not supported @@ -1031,6 +1031,18 @@ private void readPipelineAdditionalData(Map serverData) throws S try { readRequestSessionVariables(serverData); } catch (SQLException sqlException) { + if (resultingException != null) { + if (resultingException.getSQLState() != null + && !resultingException.getSQLState().startsWith("08") + && sqlException.getSQLState() != null + && sqlException.getSQLState().startsWith("08")) { + throw new SQLException( + resultingException.getMessage(), + "08000", + resultingException.getErrorCode(), + resultingException); + } + } if (resultingException == null) { resultingException = exceptionFactory.create("could not load system variables", "08000", sqlException); diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java index 0f84fd3fe..d875d79fc 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java @@ -55,7 +55,10 @@ import static org.mariadb.jdbc.internal.com.Packet.*; import static org.mariadb.jdbc.internal.util.SqlStates.*; -import java.io.*; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; diff --git a/src/test/java/org/mariadb/jdbc/AutoReconnectTest.java b/src/test/java/org/mariadb/jdbc/AutoReconnectTest.java index 7ed5a459a..71ed9007d 100644 --- a/src/test/java/org/mariadb/jdbc/AutoReconnectTest.java +++ b/src/test/java/org/mariadb/jdbc/AutoReconnectTest.java @@ -61,7 +61,8 @@ public class AutoReconnectTest extends BaseTest { @Test public void autoReconnect() throws SQLException, InterruptedException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); try (Connection conn = setConnection("&autoReconnect")) { Statement stmt = conn.createStatement(); stmt.executeQuery("SELECT 1"); @@ -89,7 +90,7 @@ public void autoReconnect() throws SQLException, InterruptedException { @Test public void autoReconnectPing() throws SQLException, InterruptedException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); try (Connection conn = setConnection("&autoReconnect")) { Statement stmt = conn.createStatement(); stmt.executeQuery("SELECT 1"); diff --git a/src/test/java/org/mariadb/jdbc/CancelTest.java b/src/test/java/org/mariadb/jdbc/CancelTest.java index 2d8fcde27..34ceaa910 100644 --- a/src/test/java/org/mariadb/jdbc/CancelTest.java +++ b/src/test/java/org/mariadb/jdbc/CancelTest.java @@ -69,7 +69,7 @@ public class CancelTest extends BaseTest { @Before public void cancelSupported() throws SQLException { requireMinimumVersion(5, 0); - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); } @Test @@ -88,6 +88,7 @@ public void cancelTest() { exec.shutdown(); Assert.fail(); } catch (SQLException e) { + assertTrue(e.getMessage().contains("Query execution was interrupted")); // normal exception } } diff --git a/src/test/java/org/mariadb/jdbc/ConnectionTest.java b/src/test/java/org/mariadb/jdbc/ConnectionTest.java index c2b1a5fb6..9af8ffdc3 100644 --- a/src/test/java/org/mariadb/jdbc/ConnectionTest.java +++ b/src/test/java/org/mariadb/jdbc/ConnectionTest.java @@ -582,7 +582,8 @@ public void run() { @Test public void verificationEd25519AuthPlugin() throws Throwable { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); Assume.assumeTrue(isMariadbServer() && minVersion(10, 2)); Statement stmt = sharedConnection.createStatement(); @@ -708,7 +709,8 @@ public void slaveDownConnection() throws SQLException { @Test public void multiAuthPlugin() throws Throwable { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); Assume.assumeTrue(isMariadbServer() && minVersion(10, 4, 2)); Statement stmt = sharedConnection.createStatement(); try { @@ -766,7 +768,7 @@ public void quoteIdentifier() { @Test public void connectionUnexpectedClose() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); try (Connection connection = DriverManager.getConnection( "jdbc:mariadb:failover//" @@ -821,7 +823,7 @@ public void nativeSql() throws SQLException { @Test public void setReadonlyError() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); try (Connection connection = DriverManager.getConnection( "jdbc:mariadb:replication://" @@ -917,7 +919,8 @@ public void unwrapp() throws Throwable { @Test public void setClientNotConnectError() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); // only mariadb return a specific error when connection has explicitly been killed Assume.assumeTrue(isMariadbServer()); diff --git a/src/test/java/org/mariadb/jdbc/CredentialPluginTest.java b/src/test/java/org/mariadb/jdbc/CredentialPluginTest.java index f8ac46876..889de3c3b 100644 --- a/src/test/java/org/mariadb/jdbc/CredentialPluginTest.java +++ b/src/test/java/org/mariadb/jdbc/CredentialPluginTest.java @@ -43,15 +43,23 @@ public void before() throws SQLException { } Statement stmt = sharedConnection.createStatement(); if (useOldNotation) { + stmt.execute("CREATE USER 'identityUser'@'localhost'"); + stmt.execute( + "GRANT SELECT ON " + + database + + ".* TO 'identityUser'@'localhost' IDENTIFIED BY '!Passw0rd3Works'"); stmt.execute("CREATE USER 'identityUser'@'%'"); stmt.execute( "GRANT SELECT ON " + database + ".* TO 'identityUser'@'%' IDENTIFIED BY '!Passw0rd3Works'"); } else { + stmt.execute("CREATE USER 'identityUser'@'localhost' IDENTIFIED BY '!Passw0rd3Works'"); + stmt.execute("GRANT SELECT ON " + database + ".* TO 'identityUser'@'localhost'"); stmt.execute("CREATE USER 'identityUser'@'%' IDENTIFIED BY '!Passw0rd3Works'"); stmt.execute("GRANT SELECT ON " + database + ".* TO 'identityUser'@'%'"); } + stmt.execute("FLUSH PRIVILEGES"); } /** @@ -62,7 +70,8 @@ public void before() throws SQLException { @After public void after() throws SQLException { Statement stmt = sharedConnection.createStatement(); - stmt.execute("DROP USER 'identityUser'@'%'"); + stmt.execute("DROP USER IF EXISTS 'identityUser'@'%'"); + stmt.execute("DROP USER IF EXISTS 'identityUser'@'localhost'"); } @Test diff --git a/src/test/java/org/mariadb/jdbc/DataSourcePoolTest.java b/src/test/java/org/mariadb/jdbc/DataSourcePoolTest.java index 43b103d2f..d3ff218d1 100644 --- a/src/test/java/org/mariadb/jdbc/DataSourcePoolTest.java +++ b/src/test/java/org/mariadb/jdbc/DataSourcePoolTest.java @@ -113,7 +113,7 @@ public void testDataSourcePool() throws SQLException { */ @Test public void setDatabaseNameTest() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); try (MariaDbPoolDataSource ds = new MariaDbPoolDataSource(hostname == null ? "localhost" : hostname, port, database)) { try (Connection connection = ds.getConnection(username, password)) { diff --git a/src/test/java/org/mariadb/jdbc/DataSourceTest.java b/src/test/java/org/mariadb/jdbc/DataSourceTest.java index 6812d947f..8b05056b2 100644 --- a/src/test/java/org/mariadb/jdbc/DataSourceTest.java +++ b/src/test/java/org/mariadb/jdbc/DataSourceTest.java @@ -152,7 +152,7 @@ public void testDataSourceTimeout4() throws SQLException { @Test public void setDatabaseNameTest() throws SQLException { Assume.assumeFalse(options.useSsl != null && options.useSsl); - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); MariaDbDataSource ds = new MariaDbDataSource(hostname == null ? "localhost" : hostname, port, database); try (Connection connection = ds.getConnection(username, password)) { diff --git a/src/test/java/org/mariadb/jdbc/DriverTest.java b/src/test/java/org/mariadb/jdbc/DriverTest.java index 4f57b7512..e3c035d75 100644 --- a/src/test/java/org/mariadb/jdbc/DriverTest.java +++ b/src/test/java/org/mariadb/jdbc/DriverTest.java @@ -1026,7 +1026,7 @@ public void testUpdateCountProcedure() throws SQLException { @Test public void testConnectWithDb() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); requireMinimumVersion(5, 0); try { @@ -1194,7 +1194,7 @@ public void mdev3916() throws Exception { @Test public void conj1() throws Exception { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); requireMinimumVersion(5, 0); @@ -1672,7 +1672,7 @@ public void testAutoCommit() throws SQLException { @Test public void databaseType() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); Assume.assumeTrue(System.getenv("TRAVIS") != null); boolean isMysql = System.getenv("AURORA") != null || System.getenv("DB").contains("mysql"); assertEquals( diff --git a/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java b/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java index 4b740218c..7042ce507 100644 --- a/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java +++ b/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java @@ -347,7 +347,8 @@ private void executeBigBatchWithException(Connection connection) throws SQLExcep @Test public void testFailOverKillCmd() throws Throwable { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); Assume.assumeTrue(isMariadbServer()); DataSource ds = new MariaDbDataSource( diff --git a/src/test/java/org/mariadb/jdbc/FetchSizeTest.java b/src/test/java/org/mariadb/jdbc/FetchSizeTest.java index 06178dfa1..6f9020d50 100644 --- a/src/test/java/org/mariadb/jdbc/FetchSizeTest.java +++ b/src/test/java/org/mariadb/jdbc/FetchSizeTest.java @@ -201,12 +201,12 @@ private void prepareRecords(int recordNumber, String tableName) throws SQLExcept */ @Test public void fetchSizeCancel() throws SQLException { - ifMaxscaleRequireMinimumVersion(2, 2); + Assume.assumeTrue(minVersion(10, 1)); // 10.1.2 in fact Assume.assumeTrue(!sharedOptions().profileSql); long start = System.currentTimeMillis(); try (Statement stmt = sharedConnection.createStatement()) { stmt.executeQuery( - "select * from information_schema.columns as c1, information_schema.tables LIMIT 200000"); + "select * from information_schema.columns as c1, information_schema.tables LIMIT 400000"); } final long normalExecutionTime = System.currentTimeMillis() - start; @@ -214,18 +214,15 @@ public void fetchSizeCancel() throws SQLException { try (Statement stmt = sharedConnection.createStatement()) { stmt.setFetchSize(1); stmt.executeQuery( - "select * from information_schema.columns as c1, information_schema.tables LIMIT 200000"); + "select * from information_schema.columns as c1, information_schema.tables LIMIT 400000"); stmt.cancel(); } long interruptedExecutionTime = System.currentTimeMillis() - start; - Assume.assumeTrue(minVersion(10, 1)); // 10.1.2 in fact - // ensure that query is a long query. if not cancelling the query (that might lead to creating a // new connection) // may not render the test reliable - String maxscaleVersion = System.getenv("MAXSCALE_VERSION"); - if (maxscaleVersion == null && normalExecutionTime > 500) { + if (normalExecutionTime > 500) { assertTrue( "interruptedExecutionTime:" + interruptedExecutionTime @@ -237,7 +234,7 @@ public void fetchSizeCancel() throws SQLException { @Test public void fetchSizePrepareCancel() throws SQLException { - ifMaxscaleRequireMinimumVersion(2, 2); + Assume.assumeTrue(System.getenv("MAXSCALE_TEST_DISABLE") == null); Assume.assumeTrue(!sharedOptions().profileSql && !sharedOptions().pool); long start; diff --git a/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java b/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java index a5ea3544d..0ccdf3467 100644 --- a/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java +++ b/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java @@ -300,7 +300,7 @@ public void test2xBigLocalInfileInputStream() throws Exception { public void testMoreThanMaxAllowedPacketLocalInfileInputStream() throws Exception { Assume.assumeFalse( (isMariadbServer() && minVersion(10, 4, 0)) || (!isMariadbServer() && minVersion(8, 0, 3))); - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); Assume.assumeFalse(sharedIsAurora()); Statement stmt = sharedConnection.createStatement(); ResultSet rs = stmt.executeQuery("select @@max_allowed_packet"); diff --git a/src/test/java/org/mariadb/jdbc/MariaDbPoolDataSourceTest.java b/src/test/java/org/mariadb/jdbc/MariaDbPoolDataSourceTest.java index c08c605e5..928d7cc38 100644 --- a/src/test/java/org/mariadb/jdbc/MariaDbPoolDataSourceTest.java +++ b/src/test/java/org/mariadb/jdbc/MariaDbPoolDataSourceTest.java @@ -296,9 +296,7 @@ public void testIdleTimeout() throws Throwable { // not for maxscale, testing thread id is not relevant. // appveyor is so slow wait time are not relevant. Assume.assumeTrue( - System.getenv("MAXSCALE_VERSION") == null - && System.getenv("SKYSQL") == null - && System.getenv("APPVEYOR_BUILD_WORKER_IMAGE") == null); + System.getenv("SKYSQL") == null && System.getenv("APPVEYOR_BUILD_WORKER_IMAGE") == null); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); ObjectName filter = new ObjectName("org.mariadb.jdbc.pool:type=testIdleTimeout-*"); diff --git a/src/test/java/org/mariadb/jdbc/MultiTest.java b/src/test/java/org/mariadb/jdbc/MultiTest.java index d913be887..046c7e85f 100644 --- a/src/test/java/org/mariadb/jdbc/MultiTest.java +++ b/src/test/java/org/mariadb/jdbc/MultiTest.java @@ -65,7 +65,7 @@ public class MultiTest extends BaseTest { /** Tables initialisation. */ @BeforeClass() public static void initClass() throws SQLException { - System.out.println("DIEGO MultiTest initClass BEGIN"); + createTable("MultiTestt1", "id int, test varchar(100)"); createTable("MultiTestt2", "id int, test varchar(100)"); createTable("MultiTestt3", "message text"); diff --git a/src/test/java/org/mariadb/jdbc/PooledConnectionTest.java b/src/test/java/org/mariadb/jdbc/PooledConnectionTest.java index 9e8b26f14..921f36dfe 100644 --- a/src/test/java/org/mariadb/jdbc/PooledConnectionTest.java +++ b/src/test/java/org/mariadb/jdbc/PooledConnectionTest.java @@ -88,7 +88,7 @@ public void testPooledConnectionClosed() throws Exception { @Test(expected = SQLException.class) public void testPooledConnectionException() throws Exception { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); ConnectionPoolDataSource ds = new MariaDbDataSource(hostname != null ? hostname : "localhost", port, database); diff --git a/src/test/java/org/mariadb/jdbc/SslTest.java b/src/test/java/org/mariadb/jdbc/SslTest.java index 5a2b8dda4..4cb951759 100644 --- a/src/test/java/org/mariadb/jdbc/SslTest.java +++ b/src/test/java/org/mariadb/jdbc/SslTest.java @@ -82,14 +82,12 @@ public class SslTest extends BaseTest { private String serverCertificatePath; private String clientKeystorePath; private String clientKeystorePassword; + private int sslPort; /** Enable Crypto. */ @BeforeClass public static void enableCrypto() { - Assume.assumeFalse( - System.getenv("MAXSCALE_VERSION") != null - || System.getenv("SKYSQL") != null - || "true".equals(System.getenv("AURORA"))); + Assume.assumeFalse(System.getenv("SKYSQL") != null || "true".equals(System.getenv("AURORA"))); try { Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted"); field.setAccessible(true); @@ -129,27 +127,35 @@ public void checkSsl() throws SQLException { } else { serverCertificatePath = System.getProperty("serverCertificatePath"); } + sslPort = + System.getProperty("sslPort") == null || System.getProperty("sslPort").isEmpty() + ? port + : Integer.valueOf(System.getProperty("sslPort")); clientKeystorePath = System.getProperty("keystorePath"); clientKeystorePassword = System.getProperty("keystorePassword"); Statement stmt = sharedConnection.createStatement(); - try { - stmt.execute("DROP USER 'ssltestUser'@'%'"); - } catch (SQLException e) { - // eat - } + boolean useOldNotation = true; if ((isMariadbServer() && minVersion(10, 2, 0)) || (!isMariadbServer() && minVersion(8, 0, 0))) { useOldNotation = false; } if (useOldNotation) { - stmt.execute("CREATE USER 'ssltestUser'@'%'"); + stmt.execute("CREATE USER IF NOT EXISTS 'ssltestUser'@'%'"); stmt.execute( "GRANT SELECT ON *.* TO 'ssltestUser'@'%' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); + stmt.execute("CREATE USER IF NOT EXISTS 'ssltestUser'@'localhost'"); + stmt.execute( + "GRANT SELECT ON *.* TO 'ssltestUser'@'localhost' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); } else { - stmt.execute("CREATE USER 'ssltestUser'@'%' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); + stmt.execute( + "CREATE USER IF NOT EXISTS 'ssltestUser'@'%' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); stmt.execute("GRANT SELECT ON *.* TO 'ssltestUser'@'%'"); + stmt.execute( + "CREATE USER IF NOT EXISTS 'ssltestUser'@'localhost' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); + stmt.execute("GRANT SELECT ON *.* TO 'ssltestUser'@'localhost'"); } + stmt.execute("FLUSH PRIVILEGES"); } @Test @@ -157,7 +163,7 @@ public void useSsl() throws Exception { Assume.assumeTrue(haveSsl(sharedConnection) && isMariadbServer()); // Skip SSL test on java 7 since SSL stream size JDK-6521495). Assume.assumeFalse(System.getProperty("java.version").contains("1.7.")); - try (Connection connection = setConnection("&useSSL=true&trustServerCertificate=true")) { + try (Connection connection = createConnection("&useSSL=true&trustServerCertificate=true")) { connection.createStatement().execute("select 1"); } } @@ -179,7 +185,7 @@ protected void useSslForceTls(String tls, String ciphers) throws Exception { info.setProperty("enabledSslCipherSuites", ciphers); } - try (Connection connection = setConnection(info)) { + try (Connection connection = createConnection(info)) { connection.createStatement().execute("select 1"); } } @@ -272,8 +278,13 @@ public void useSslForceTlsV12AndCipher() throws Exception { || (isMariadbServer() && Platform.isWindows() && !minVersion(10, 4))); // Only test with MariaDB since MySQL community is compiled with yaSSL if (isMariadbServer()) { - useSslForceTls( - "TLSv1.2", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"); + try { + useSslForceTls( + "TLSv1.2", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"); + } catch (SQLException sqle) { + // in case ciphers not supported by server + assertTrue(sqle.getMessage().contains("handshake_failure")); + } } } @@ -323,7 +334,7 @@ public void wrongCipherMysqlOptionCompatibility() { // enabledSSLCipherSuites, not enabledSslCipherSuites (different case) info.setProperty("enabledSSLCipherSuites", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"); - try (Connection connection = setConnection(info)) { + try (Connection connection = createConnection(info)) { connection.createStatement().execute("select 1"); fail("Must have thrown error since cipher aren't TLSv1.1 ciphers"); } @@ -387,12 +398,30 @@ private void saveToFile(String path, String contents) { } private Connection createConnection(Properties info) throws SQLException { - return createConnection(info, username, password); + return createConnection(info, username, password, sslPort); + } + + private Connection createConnection(String param) throws SQLException { + return createConnection(param, new Properties(), username, password, sslPort); } - private Connection createConnection(Properties info, String user, String pwd) + private Connection createConnection(Properties info, String user, String pwd, int port) throws SQLException { - String jdbcUrl = connDnsUri; + return createConnection(null, info, user, pwd, port); + } + + private Connection createConnection( + String param, Properties info, String user, String pwd, int port) throws SQLException { + String jdbcUrl = + "jdbc:mariadb://mariadb.example.com:" + + port + + "/" + + database + + "?" + + parameters + + (password != null && !"".equals(password) ? "&password=" + password : "") + + (param != null ? param : ""); + ; Properties connProps = new Properties(info); connProps.setProperty("user", user); if (pwd != null) { @@ -426,7 +455,8 @@ public void testConnect(Properties info, boolean sslExpected, String user, Strin throws SQLException { Assume.assumeTrue(System.getenv("SKYSQL") == null); Assume.assumeTrue(haveSsl(sharedConnection) && isMariadbServer()); - try (Connection conn = createConnection(info, user, pwd)) { + + try (Connection conn = createConnection(info, user, pwd, sslPort)) { // First do a basic select test: try (Statement stmt = conn.createStatement()) { try (ResultSet rs = stmt.executeQuery("SHOW STATUS like 'Ssl_version'")) { @@ -453,7 +483,9 @@ public void testConnectNonSsl() throws SQLException { testConnect(info, false); fail("Must fail since user require SSL"); } catch (SQLException e) { - assertTrue(e.getMessage().contains("Access denied for user 'ssltestUser'")); + assertTrue( + e.getMessage().contains("Access denied for user 'ssltestUser'") + || e.getMessage().contains("Bad SSL handshake")); } } @@ -581,7 +613,7 @@ public void testNoSessionResumption() Assume.assumeTrue(haveSsl(sharedConnection) && isMariadbServer()); long sessionsReused = 0; - try (Connection conn = createConnection(info, "ssltestUser", "!Passw0rd3Works")) { + try (Connection conn = createConnection(info, "ssltestUser", "!Passw0rd3Works", sslPort)) { // First do a basic select test: Statement stmt = conn.createStatement(); @@ -597,7 +629,7 @@ public void testNoSessionResumption() sessionsReused = rs.getLong(2); } - try (Connection conn2 = createConnection(info, "ssltestUser", "!Passw0rd3Works")) { + try (Connection conn2 = createConnection(info, "ssltestUser", "!Passw0rd3Works", sslPort)) { Statement stmt2 = conn2.createStatement(); try (ResultSet rs = stmt2.executeQuery("SHOW STATUS LIKE 'Ssl_sessions_reused'")) { @@ -830,6 +862,7 @@ public void testClientKeystore() throws SQLException { */ @Test public void testClientKeyStoreWithPrivateKeyPwd() throws Exception { + Assume.assumeTrue(System.getenv("MAXSCALE_TEST_DISABLE") == null); Assume.assumeTrue(haveSsl(sharedConnection) && isMariadbServer()); String clientKeyStore2Path = System.getProperty("keystore2Path"); String clientKeyStore2Password = System.getProperty("keystore2Password"); @@ -1111,20 +1144,28 @@ private void createSslTestUser(String user) throws SQLException { } Statement st = sharedConnection.createStatement(); - try { - st.execute("DROP USER '" + user + "'@'%'"); - } catch (SQLException e) { - // eat - } - st.execute("FLUSH PRIVILEGES"); if (useOldNotation) { - st.execute("CREATE USER '" + user + "'@'%'"); + st.execute("CREATE USER IF NOT EXISTS '" + user + "'@'%'"); st.execute( "GRANT SELECT on *.* to '" + user + "'@'%' identified by 'ssltestpassword' REQUIRE X509"); + st.execute("CREATE USER IF NOT EXISTS '" + user + "'@'localhost'"); + st.execute( + "GRANT SELECT on *.* to '" + + user + + "'@'localhost' identified by 'ssltestpassword' REQUIRE X509"); } else { - st.execute("CREATE USER '" + user + "'@'%' identified by 'ssltestpassword' REQUIRE X509"); + st.execute( + "CREATE USER IF NOT EXISTS '" + + user + + "'@'%' identified by 'ssltestpassword' REQUIRE X509"); st.execute("GRANT SELECT on *.* to '" + user + "'@'%'"); + st.execute( + "CREATE USER IF NOT EXISTS '" + + user + + "'@'localhost' identified by 'ssltestpassword' REQUIRE X509"); + st.execute("GRANT SELECT on *.* to '" + user + "'@'localhost'"); } + st.execute("FLUSH PRIVILEGES"); } private void deleteSslTestUser(String user) throws SQLException { diff --git a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java index 227b65a79..f3e7a9f3d 100644 --- a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java +++ b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java @@ -404,22 +404,27 @@ public void meta() throws Exception { @Test public void testMetaCatalogNoAccessToProcedureBodies() throws Exception { + Assume.assumeTrue(System.getenv("SKYSQL") == null); + // cancel for version 10.2 beta before fix https://jira.mariadb.org/browse/MDEV-11761 cancelForVersion(10, 2, 2); cancelForVersion(10, 2, 3); cancelForVersion(10, 2, 4); Statement statement = sharedConnection.createStatement(); - try { - statement.execute("DROP USER 'test_jdbc'@'%'"); - } catch (SQLException e) { - // eat exception - } + statement.execute("DROP USER IF EXISTS 'test_jdbc'@'%'"); + statement.execute("DROP USER IF EXISTS 'test_jdbc'@'localhost'"); + statement.execute("CREATE USER 'test_jdbc'@'localhost' IDENTIFIED BY 'testJ@dc1'"); + statement.execute( + "GRANT ALL ON " + + database + + ".* TO 'test_jdbc'@'localhost' IDENTIFIED BY 'testJ@dc1' WITH GRANT OPTION"); statement.execute("CREATE USER 'test_jdbc'@'%' IDENTIFIED BY 'testJ@dc1'"); statement.execute( - "GRANT SELECT, EXECUTE ON " + "GRANT ALL ON " + database + ".* TO 'test_jdbc'@'%' IDENTIFIED BY 'testJ@dc1' WITH GRANT OPTION"); + statement.execute("FLUSH PRIVILEGES"); Properties properties = new Properties(); properties.put("user", "test_jdbc"); properties.put("password", "testJ@dc1"); @@ -470,6 +475,7 @@ public void testMetaCatalogNoAccessToProcedureBodies() throws Exception { // MySQL 5.5 doesn't permit 'test_jdbc'@'localhost' } statement.execute("DROP USER 'test_jdbc'@'%'"); + statement.execute("DROP USER 'test_jdbc'@'localhost'"); } @Test diff --git a/src/test/java/org/mariadb/jdbc/TimeoutTest.java b/src/test/java/org/mariadb/jdbc/TimeoutTest.java index 10aab992f..4a4c7455e 100644 --- a/src/test/java/org/mariadb/jdbc/TimeoutTest.java +++ b/src/test/java/org/mariadb/jdbc/TimeoutTest.java @@ -77,7 +77,8 @@ private static int selectValue(Connection conn, int value) throws SQLException { public void resultSetAfterSocketTimeoutTest() { // appveyor vm are very slow, cannot compare time Assume.assumeTrue( - System.getenv("APPVEYOR") == null + System.getenv("MAXSCALE_TEST_DISABLE") == null + && System.getenv("APPVEYOR") == null && System.getenv("DOCKER_SOCKET") == null && System.getenv("SKYSQL") == null); diff --git a/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java b/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java index 4c0caf102..5d40f3285 100644 --- a/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java +++ b/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java @@ -347,7 +347,7 @@ public void testTimeUtcNow() throws SQLException { @Test public void testTimeOffsetNowUseServer() throws SQLException { - Assume.assumeTrue(System.getenv("AURORA") == null || System.getenv("SKYSQL") == null); + Assume.assumeFalse("true".equals(System.getenv("AURORA"))); try (Connection connection = setConnection("&useLegacyDatetimeCode=false&serverTimezone=+5:00")) { setSessionTimeZone(connection, "+5:00"); diff --git a/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java b/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java index 37fa8e919..7fd641b34 100644 --- a/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java +++ b/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java @@ -163,7 +163,7 @@ public void checkAutoReconnectDeconnection() throws Throwable { */ @Test public void isValidConnectionThatIsKilledExternally() throws Throwable { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); try (Connection connection = getNewConnection()) { connection.setCatalog("mysql"); Protocol protocol = getProtocolFromConnection(connection); From e5f340551025dc67a76531b170dbe396393d9f34 Mon Sep 17 00:00:00 2001 From: rusher Date: Mon, 14 Sep 2020 10:40:56 +0200 Subject: [PATCH 28/30] [CONJ-827] update maxscale test to recent version --- .travis.yml | 7 +- .travis/maxscale-compose.yml | 34 +++-- .travis/maxscale/Dockerfile | 6 +- .travis/maxscale/maxscale.cnf | 118 +++++++++--------- .travis/script.sh | 34 ++--- .travis/sql/dbinit.sql | 8 +- .../protocol/AbstractConnectProtocol.java | 14 ++- .../protocol/AbstractQueryProtocol.java | 5 +- .../org/mariadb/jdbc/AutoReconnectTest.java | 5 +- .../java/org/mariadb/jdbc/CancelTest.java | 3 +- .../java/org/mariadb/jdbc/ConnectionTest.java | 13 +- .../mariadb/jdbc/CredentialPluginTest.java | 11 +- .../org/mariadb/jdbc/DataSourcePoolTest.java | 2 +- .../java/org/mariadb/jdbc/DataSourceTest.java | 2 +- .../java/org/mariadb/jdbc/DriverTest.java | 8 +- .../org/mariadb/jdbc/ErrorMessageTest.java | 3 +- .../java/org/mariadb/jdbc/FetchSizeTest.java | 13 +- .../jdbc/LocalInfileInputStreamTest.java | 2 +- .../jdbc/MariaDbPoolDataSourceTest.java | 4 +- src/test/java/org/mariadb/jdbc/MultiTest.java | 2 +- .../mariadb/jdbc/PooledConnectionTest.java | 2 +- src/test/java/org/mariadb/jdbc/SslTest.java | 103 ++++++++++----- .../org/mariadb/jdbc/StoredProcedureTest.java | 18 ++- .../java/org/mariadb/jdbc/TimeoutTest.java | 3 +- .../jdbc/TimezoneDaylightSavingTimeTest.java | 2 +- .../jdbc/failover/MonoServerFailoverTest.java | 2 +- 26 files changed, 256 insertions(+), 168 deletions(-) diff --git a/.travis.yml b/.travis.yml index ce0a6eda3..88a8a50c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,9 @@ cache: directories: - $HOME/.m2 +env: + - SSLPORT=3305 + matrix: allow_failures: - env: DB=build PACKET=8M @@ -36,8 +39,6 @@ matrix: jdk: openjdk11 - env: SKYSQL=true PACKET=8M jdk: openjdk11 - - env: DB=mysql:5.6 PACKET=8M - jdk: openjdk11 - env: DB=mysql:5.7 PACKET=8M jdk: openjdk11 - env: DB=mysql:8.0 PACKET=8M ADDITIONAL_CONF=--default-authentication-plugin=mysql_native_password --caching_sha2_password_private_key_path=/etc/sslcert/server.key --caching_sha2_password_public_key_path=/etc/sslcert/public.key @@ -78,7 +79,7 @@ matrix: jdk: openjdk11 - env: DB=mariadb:10.5 PACKET=8M jdk: openjdk12 - - env: DB=mariadb:10.5 PACKET=8M MAXSCALE_VERSION=2.2.9 + - env: DB=mariadb:10.5 PACKET=8M MAXSCALE_VERSION=2.5.3 MAXSCALE_TEST_DISABLE=true SSLPORT=4009 jdk: openjdk11 script: diff --git a/.travis/maxscale-compose.yml b/.travis/maxscale-compose.yml index ae8ea7d03..9fb200649 100644 --- a/.travis/maxscale-compose.yml +++ b/.travis/maxscale-compose.yml @@ -1,17 +1,5 @@ version: '2.1' services: - maxscale: - depends_on: - - db - ports: - - 4006:4006 - - 4007:4007 - - 4008:4008 - build: - context: . - dockerfile: maxscale/Dockerfile - args: - MAXSCALE_VERSION: $MAXSCALE_VERSION db: image: $DB command: --max-connections=500 --max-allowed-packet=$PACKET --innodb-log-file-size=$INNODB_LOG_FILE_SIZE --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --ssl-ca=/etc/sslcert/ca.crt --ssl-cert=/etc/sslcert/server.crt --ssl-key=/etc/sslcert/server.key --bind-address=0.0.0.0 @@ -23,3 +11,25 @@ services: environment: MYSQL_DATABASE: testj MYSQL_ALLOW_EMPTY_PASSWORD: 1 + healthcheck: + test: ["CMD", "mysql", "--protocol=tcp", "-ubob", "-h127.0.0.1", "-ubob"] + timeout: 20s + retries: 10 + + maxscale: + depends_on: + db: + condition: service_healthy + links: + - "db:database" + ports: + - 4006:4006 + - 4008:4008 + - 4009:4009 + volumes: + - $SSLCERT:/etc/sslcert + build: + context: . + dockerfile: maxscale/Dockerfile + args: + MAXSCALE_VERSION: $MAXSCALE_VERSION diff --git a/.travis/maxscale/Dockerfile b/.travis/maxscale/Dockerfile index 0ae214d93..0a60b4e79 100644 --- a/.travis/maxscale/Dockerfile +++ b/.travis/maxscale/Dockerfile @@ -1,12 +1,12 @@ FROM centos:7 ARG MAXSCALE_VERSION -ENV MAXSCALE_VERSION ${MAXSCALE_VERSION:-2.1.4} +ENV MAXSCALE_VERSION ${MAXSCALE_VERSION:-2.5.3} COPY maxscale/mariadb.repo /etc/yum.repos.d/ RUN rpm --import https://yum.mariadb.org/RPM-GPG-KEY-MariaDB \ - && yum -y install https://downloads.mariadb.com/MaxScale/${MAXSCALE_VERSION}/centos/7/x86_64/maxscale-${MAXSCALE_VERSION}-1.centos.7.x86_64.rpm \ + && yum -y install https://downloads.mariadb.com/MaxScale/${MAXSCALE_VERSION}/centos/7/x86_64/maxscale-${MAXSCALE_VERSION}-2.rhel.7.x86_64.rpm \ && yum -y update RUN yum -y install maxscale-${MAXSCALE_VERSION} MariaDB-client \ @@ -14,8 +14,8 @@ RUN yum -y install maxscale-${MAXSCALE_VERSION} MariaDB-client \ && rm -rf /tmp/* COPY maxscale/docker-entrypoint.sh / -RUN chmod 777 /etc/maxscale.cnf COPY maxscale/maxscale.cnf /etc/ +RUN chmod 777 /etc/maxscale.cnf RUN chmod 777 /docker-entrypoint.sh diff --git a/.travis/maxscale/maxscale.cnf b/.travis/maxscale/maxscale.cnf index 01f5dbd0d..8a85c9e84 100644 --- a/.travis/maxscale/maxscale.cnf +++ b/.travis/maxscale/maxscale.cnf @@ -1,45 +1,59 @@ -# MaxScale documentation on GitHub: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Documentation-Contents.md +# MaxScale documentation: +# https://mariadb.com/kb/en/mariadb-maxscale-24/ # Global parameters # # Complete list of configuration options: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Getting-Started/Configuration-Guide.md - +# https://mariadb.com/kb/en/mariadb-maxscale-24-mariadb-maxscale-configuration-guide/ [maxscale] -threads=2 -log_messages=1 -log_trace=1 -log_debug=1 +threads=auto # Server definitions # # Set the address of the server to the network -# address of a MySQL server. +# address of a MariaDB server. # +[server2] +type=server +address=database +port=3306 +protocol=MariaDBBackend +ssl=true +ssl_ca_cert=/etc/sslcert/server.crt +ssl_cert=/etc/sslcert/client.crt +ssl_key=/etc/sslcert/client.key + + [server1] type=server address=db port=3306 protocol=MariaDBBackend -authenticator_options=skip_authentication=true -router_options=master + # Monitor for the servers # # This will keep MaxScale aware of the state of the servers. -# MySQL Monitor documentation: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Monitors/MySQL-Monitor.md +# MariaDB Monitor documentation: +# https://mariadb.com/kb/en/mariadb-maxscale-24-mariadb-monitor/ -[MySQLMonitor] +[MariaDB-Monitor] type=monitor module=mariadbmon servers=server1 user=boby -passwd=hey -monitor_interval=10000 +password=hey +monitor_interval=2000 + +[MariaDB-Monitor2] +type=monitor +module=mariadbmon +servers=server2 +user=boby +password=hey +monitor_interval=2000 # Service definitions # @@ -48,78 +62,60 @@ monitor_interval=10000 # # ReadConnRoute documentation: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Routers/ReadConnRoute.md +# https://mariadb.com/kb/en/mariadb-maxscale-24-readconnroute/ -[Read-OnlyService] -enable_root_user=1 -version_string=10.4.99-MariaDB-maxScale +[Read-Only-Service] type=service router=readconnroute servers=server1 user=boby -passwd=hey +password=hey router_options=slave -localhost_match_wildcard_host=1 -[Read-WriteService] -enable_root_user=1 -version_string=10.4.99-MariaDB-maxScale +# ReadWriteSplit documentation: +# https://mariadb.com/kb/en/mariadb-maxscale-24-readwritesplit/ + +[Read-Write-Service] type=service router=readwritesplit servers=server1 +version_string=10.5.99-MariaDB-maxScale user=boby -passwd=hey -localhost_match_wildcard_host=1 +password=hey -[WriteService] +[Read-Write-Service2] type=service -router=readconnroute -servers=server1 +router=readwritesplit +version_string=10.5.99-MariaDB-maxScale +servers=server2 user=boby -passwd=hey -router_options=master -localhost_match_wildcard_host=1 -version_string=10.4.99-MariaDB-maxscale - - -# This service enables the use of the MaxAdmin interface -# MaxScale administration guide: -# /~https://github.com/mariadb-corporation/MaxScale/blob/2.1/Documentation/Reference/MaxAdmin.mda - -[MaxAdminService] -enable_root_user=1 -version_string=10.4.99-MariaDB-maxScale -type=service -router=cli +password=hey # Listener definitions for the services # # These listeners represent the ports the # services will listen on. # -[WriteListener] -type=listener -service=WriteService -protocol=MariaDBClient -port=4007 -#socket=/var/lib/maxscale/writeconn.sock -[Read-OnlyListener] +[Read-Only-Listener] type=listener -service=Read-OnlyService +service=Read-Only-Service protocol=MariaDBClient port=4008 -#socket=/var/lib/maxscale/readconn.sock -[Read-WriteListener] +[Read-Write-Listener] type=listener -service=Read-WriteService +service=Read-Write-Service protocol=MariaDBClient port=4006 -#socket=/var/lib/maxscale/rwsplit.sock -[MaxAdminListener] + +[Read-Write-Listener2] type=listener -service=MaxAdminService -protocol=maxscaled -socket=/tmp/maxadmin.sock +service=Read-Write-Service2 +protocol=MariaDBClient +port=4009 +ssl=true +ssl_ca_cert=/etc/sslcert/ca.crt +ssl_cert=/etc/sslcert/server.crt +ssl_key=/etc/sslcert/server.key diff --git a/.travis/script.sh b/.travis/script.sh index cecd472fc..c74be9f0f 100644 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -63,7 +63,8 @@ else -Dkeystore2Password="kspass" -DkeyPassword="kspasskey" \ -Dkeystore2PathP12="$SSLCERT/fullclient-keystore.p12" \ -DrunLongTest=true \ - -DserverPublicKey="$SSLCERT/public.key" ) + -DserverPublicKey="$SSLCERT/public.key"\ + -DsslPort="$SSLPORT") if [ -n "$AURORA" ] ; then if [ -n "$AURORA_STRING_URL" ] ; then @@ -82,9 +83,9 @@ else ################################################################################################################### # launch Maxscale with one server ################################################################################################################### - mysql=( mysql --protocol=tcp -ubob -h127.0.0.1 --port=4007 ) + mysql=( mysql --protocol=TCP -ubob -h127.0.0.1 --port=4006 test2) export COMPOSE_FILE=.travis/maxscale-compose.yml - urlString='jdbc:mariadb://mariadb.example.com:4007/testj?user=bob&killFetchStmtOnClose=false&enablePacketDebug=true' + urlString='jdbc:mariadb://mariadb.example.com:4006/testj?user=bob&enablePacketDebug=true' docker-compose -f ${COMPOSE_FILE} build docker-compose -f ${COMPOSE_FILE} up -d else @@ -93,7 +94,7 @@ else ################################################################################################################### # launch 3 galera servers ################################################################################################################### - mysql=( mysql --protocol=tcp -ubob -hmariadb.example.com --port=3106 ) + mysql=( mysql --protocol=TCP -ubob -hmariadb.example.com --port=3106 test2) export COMPOSE_FILE=.travis/galera-compose.yml urlString='jdbc:mariadb://mariadb.example.com:3106/testj?user=bob&enablePacketDebug=true' @@ -101,7 +102,7 @@ else docker-compose -f ${COMPOSE_FILE} up -d SLEEP 10 else - mysql=( mysql --protocol=tcp -ubob -hmariadb.example.com --port=3106 ) + mysql=( mysql --protocol=tcp -ubob -hmariadb.example.com --port=3106 test2) urlString='jdbc:mariadb://mariadb.example.com:3106/testj?user=bob&enablePacketDebug=true' docker run \ @@ -135,7 +136,7 @@ else ################################################################################################################### # launch docker server ################################################################################################################### - mysql=( mysql --protocol=tcp -ubob -h127.0.0.1 --port=3305 ) + mysql=( mysql --protocol=TCP -ubob -hmariadb.example.com --port=3305 test2) export COMPOSE_FILE=.travis/docker-compose.yml docker-compose -f ${COMPOSE_FILE} up -d @@ -147,27 +148,29 @@ else # wait for docker initialisation ################################################################################################################### - for i in {60..0}; do - if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then + for i in {15..0}; do + if echo 'SELECT 1' | "${mysql[@]}" ; then break fi echo 'data server still not active' - sleep 1 + sleep 2 done if [ "$i" = 0 ]; then - if [ -n "COMPOSE_FILE" ] ; then - docker-compose -f ${COMPOSE_FILE} logs + + if echo 'SELECT 1' | "${mysql[@]}" ; then + break fi - echo 'SELECT 1' | "${mysql[@]}" + docker-compose -f ${COMPOSE_FILE} logs + if [ -n "$MAXSCALE_VERSION" ] ; then + docker-compose -f $COMPOSE_FILE exec maxscale tail -n 500 /var/log/maxscale/maxscale.log + fi echo >&2 'data server init process failed.' exit 1 fi fi - - fi @@ -179,8 +182,5 @@ cmd+=( -DdbUrl="$urlString" ) cmd+=( -DtestSingleHost="$testSingleHost" ) echo ${cmd} -if [ -n "$MAXSCALE_VERSION" ] ; then - docker-compose -f $COMPOSE_FILE exec maxscale tail -n 500 /var/log/maxscale/maxscale.log -fi "${cmd[@]}" \ No newline at end of file diff --git a/.travis/sql/dbinit.sql b/.travis/sql/dbinit.sql index e9dc8b690..eff6d41e6 100644 --- a/.travis/sql/dbinit.sql +++ b/.travis/sql/dbinit.sql @@ -1,8 +1,14 @@ +CREATE USER 'bob'@'localhost'; +GRANT ALL ON *.* TO 'bob'@'localhost' with grant option; + CREATE USER 'bob'@'%'; GRANT ALL ON *.* TO 'bob'@'%' with grant option; CREATE USER 'boby'@'%' identified by 'hey'; -GRANT ALL ON *.* TO 'boby'@'%' with grant option; +GRANT ALL ON *.* TO 'boby'@'%' identified by 'hey' with grant option; + +CREATE USER 'boby'@'localhost' identified by 'hey'; +GRANT ALL ON *.* TO 'boby'@'localhost' identified by 'hey' with grant option; FLUSH PRIVILEGES; diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java index b124cbf38..2be182ace 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java @@ -872,7 +872,7 @@ private void postConnectionQueries() throws SQLException { sendPipelineAdditionalData(); readPipelineAdditionalData(serverData); } catch (SQLException sqle) { - if ("08".equals(sqle.getSQLState())) { + if (sqle.getSQLState() != null && sqle.getSQLState().startsWith("08")) { throw sqle; } // in case pipeline is not supported @@ -1031,6 +1031,18 @@ private void readPipelineAdditionalData(Map serverData) throws S try { readRequestSessionVariables(serverData); } catch (SQLException sqlException) { + if (resultingException != null) { + if (resultingException.getSQLState() != null + && !resultingException.getSQLState().startsWith("08") + && sqlException.getSQLState() != null + && sqlException.getSQLState().startsWith("08")) { + throw new SQLException( + resultingException.getMessage(), + "08000", + resultingException.getErrorCode(), + resultingException); + } + } if (resultingException == null) { resultingException = exceptionFactory.create("could not load system variables", "08000", sqlException); diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java index 0f84fd3fe..d875d79fc 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java @@ -55,7 +55,10 @@ import static org.mariadb.jdbc.internal.com.Packet.*; import static org.mariadb.jdbc.internal.util.SqlStates.*; -import java.io.*; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; diff --git a/src/test/java/org/mariadb/jdbc/AutoReconnectTest.java b/src/test/java/org/mariadb/jdbc/AutoReconnectTest.java index 7ed5a459a..71ed9007d 100644 --- a/src/test/java/org/mariadb/jdbc/AutoReconnectTest.java +++ b/src/test/java/org/mariadb/jdbc/AutoReconnectTest.java @@ -61,7 +61,8 @@ public class AutoReconnectTest extends BaseTest { @Test public void autoReconnect() throws SQLException, InterruptedException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); try (Connection conn = setConnection("&autoReconnect")) { Statement stmt = conn.createStatement(); stmt.executeQuery("SELECT 1"); @@ -89,7 +90,7 @@ public void autoReconnect() throws SQLException, InterruptedException { @Test public void autoReconnectPing() throws SQLException, InterruptedException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); try (Connection conn = setConnection("&autoReconnect")) { Statement stmt = conn.createStatement(); stmt.executeQuery("SELECT 1"); diff --git a/src/test/java/org/mariadb/jdbc/CancelTest.java b/src/test/java/org/mariadb/jdbc/CancelTest.java index 2d8fcde27..838f78b57 100644 --- a/src/test/java/org/mariadb/jdbc/CancelTest.java +++ b/src/test/java/org/mariadb/jdbc/CancelTest.java @@ -69,7 +69,7 @@ public class CancelTest extends BaseTest { @Before public void cancelSupported() throws SQLException { requireMinimumVersion(5, 0); - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null && System.getenv("MAXSCALE_TEST_DISABLE") == null); } @Test @@ -88,6 +88,7 @@ public void cancelTest() { exec.shutdown(); Assert.fail(); } catch (SQLException e) { + assertTrue(e.getMessage().contains("Query execution was interrupted")); // normal exception } } diff --git a/src/test/java/org/mariadb/jdbc/ConnectionTest.java b/src/test/java/org/mariadb/jdbc/ConnectionTest.java index c2b1a5fb6..9af8ffdc3 100644 --- a/src/test/java/org/mariadb/jdbc/ConnectionTest.java +++ b/src/test/java/org/mariadb/jdbc/ConnectionTest.java @@ -582,7 +582,8 @@ public void run() { @Test public void verificationEd25519AuthPlugin() throws Throwable { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); Assume.assumeTrue(isMariadbServer() && minVersion(10, 2)); Statement stmt = sharedConnection.createStatement(); @@ -708,7 +709,8 @@ public void slaveDownConnection() throws SQLException { @Test public void multiAuthPlugin() throws Throwable { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); Assume.assumeTrue(isMariadbServer() && minVersion(10, 4, 2)); Statement stmt = sharedConnection.createStatement(); try { @@ -766,7 +768,7 @@ public void quoteIdentifier() { @Test public void connectionUnexpectedClose() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); try (Connection connection = DriverManager.getConnection( "jdbc:mariadb:failover//" @@ -821,7 +823,7 @@ public void nativeSql() throws SQLException { @Test public void setReadonlyError() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); try (Connection connection = DriverManager.getConnection( "jdbc:mariadb:replication://" @@ -917,7 +919,8 @@ public void unwrapp() throws Throwable { @Test public void setClientNotConnectError() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); // only mariadb return a specific error when connection has explicitly been killed Assume.assumeTrue(isMariadbServer()); diff --git a/src/test/java/org/mariadb/jdbc/CredentialPluginTest.java b/src/test/java/org/mariadb/jdbc/CredentialPluginTest.java index f8ac46876..889de3c3b 100644 --- a/src/test/java/org/mariadb/jdbc/CredentialPluginTest.java +++ b/src/test/java/org/mariadb/jdbc/CredentialPluginTest.java @@ -43,15 +43,23 @@ public void before() throws SQLException { } Statement stmt = sharedConnection.createStatement(); if (useOldNotation) { + stmt.execute("CREATE USER 'identityUser'@'localhost'"); + stmt.execute( + "GRANT SELECT ON " + + database + + ".* TO 'identityUser'@'localhost' IDENTIFIED BY '!Passw0rd3Works'"); stmt.execute("CREATE USER 'identityUser'@'%'"); stmt.execute( "GRANT SELECT ON " + database + ".* TO 'identityUser'@'%' IDENTIFIED BY '!Passw0rd3Works'"); } else { + stmt.execute("CREATE USER 'identityUser'@'localhost' IDENTIFIED BY '!Passw0rd3Works'"); + stmt.execute("GRANT SELECT ON " + database + ".* TO 'identityUser'@'localhost'"); stmt.execute("CREATE USER 'identityUser'@'%' IDENTIFIED BY '!Passw0rd3Works'"); stmt.execute("GRANT SELECT ON " + database + ".* TO 'identityUser'@'%'"); } + stmt.execute("FLUSH PRIVILEGES"); } /** @@ -62,7 +70,8 @@ public void before() throws SQLException { @After public void after() throws SQLException { Statement stmt = sharedConnection.createStatement(); - stmt.execute("DROP USER 'identityUser'@'%'"); + stmt.execute("DROP USER IF EXISTS 'identityUser'@'%'"); + stmt.execute("DROP USER IF EXISTS 'identityUser'@'localhost'"); } @Test diff --git a/src/test/java/org/mariadb/jdbc/DataSourcePoolTest.java b/src/test/java/org/mariadb/jdbc/DataSourcePoolTest.java index 43b103d2f..d3ff218d1 100644 --- a/src/test/java/org/mariadb/jdbc/DataSourcePoolTest.java +++ b/src/test/java/org/mariadb/jdbc/DataSourcePoolTest.java @@ -113,7 +113,7 @@ public void testDataSourcePool() throws SQLException { */ @Test public void setDatabaseNameTest() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); try (MariaDbPoolDataSource ds = new MariaDbPoolDataSource(hostname == null ? "localhost" : hostname, port, database)) { try (Connection connection = ds.getConnection(username, password)) { diff --git a/src/test/java/org/mariadb/jdbc/DataSourceTest.java b/src/test/java/org/mariadb/jdbc/DataSourceTest.java index 6812d947f..8b05056b2 100644 --- a/src/test/java/org/mariadb/jdbc/DataSourceTest.java +++ b/src/test/java/org/mariadb/jdbc/DataSourceTest.java @@ -152,7 +152,7 @@ public void testDataSourceTimeout4() throws SQLException { @Test public void setDatabaseNameTest() throws SQLException { Assume.assumeFalse(options.useSsl != null && options.useSsl); - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); MariaDbDataSource ds = new MariaDbDataSource(hostname == null ? "localhost" : hostname, port, database); try (Connection connection = ds.getConnection(username, password)) { diff --git a/src/test/java/org/mariadb/jdbc/DriverTest.java b/src/test/java/org/mariadb/jdbc/DriverTest.java index 4f57b7512..a2c3f8cdc 100644 --- a/src/test/java/org/mariadb/jdbc/DriverTest.java +++ b/src/test/java/org/mariadb/jdbc/DriverTest.java @@ -234,6 +234,7 @@ public void parameterMetaDataTypeNotAvailable() throws SQLException { @Test public void parameterMetaDataNotPreparable() throws SQLException { + Assume.assumeTrue(System.getenv("SKYSQL") == null); Assume.assumeFalse(sharedUsePrepare()); Statement stmt = sharedConnection.createStatement(); Map initValues = loadVariables(stmt); @@ -277,6 +278,7 @@ private Map loadVariables(Statement stmt) throws SQLException { @Test public void parameterMetaDataPreparable() throws SQLException { + Assume.assumeTrue(System.getenv("SKYSQL") == null); Assume.assumeFalse(sharedUsePrepare()); Statement stmt = sharedConnection.createStatement(); Map initValues = loadVariables(stmt); @@ -1026,7 +1028,7 @@ public void testUpdateCountProcedure() throws SQLException { @Test public void testConnectWithDb() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); requireMinimumVersion(5, 0); try { @@ -1194,7 +1196,7 @@ public void mdev3916() throws Exception { @Test public void conj1() throws Exception { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); requireMinimumVersion(5, 0); @@ -1672,7 +1674,7 @@ public void testAutoCommit() throws SQLException { @Test public void databaseType() throws SQLException { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); Assume.assumeTrue(System.getenv("TRAVIS") != null); boolean isMysql = System.getenv("AURORA") != null || System.getenv("DB").contains("mysql"); assertEquals( diff --git a/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java b/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java index 4b740218c..7042ce507 100644 --- a/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java +++ b/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java @@ -347,7 +347,8 @@ private void executeBigBatchWithException(Connection connection) throws SQLExcep @Test public void testFailOverKillCmd() throws Throwable { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue( + System.getenv("MAXSCALE_TEST_DISABLE") == null && System.getenv("SKYSQL") == null); Assume.assumeTrue(isMariadbServer()); DataSource ds = new MariaDbDataSource( diff --git a/src/test/java/org/mariadb/jdbc/FetchSizeTest.java b/src/test/java/org/mariadb/jdbc/FetchSizeTest.java index 06178dfa1..6f9020d50 100644 --- a/src/test/java/org/mariadb/jdbc/FetchSizeTest.java +++ b/src/test/java/org/mariadb/jdbc/FetchSizeTest.java @@ -201,12 +201,12 @@ private void prepareRecords(int recordNumber, String tableName) throws SQLExcept */ @Test public void fetchSizeCancel() throws SQLException { - ifMaxscaleRequireMinimumVersion(2, 2); + Assume.assumeTrue(minVersion(10, 1)); // 10.1.2 in fact Assume.assumeTrue(!sharedOptions().profileSql); long start = System.currentTimeMillis(); try (Statement stmt = sharedConnection.createStatement()) { stmt.executeQuery( - "select * from information_schema.columns as c1, information_schema.tables LIMIT 200000"); + "select * from information_schema.columns as c1, information_schema.tables LIMIT 400000"); } final long normalExecutionTime = System.currentTimeMillis() - start; @@ -214,18 +214,15 @@ public void fetchSizeCancel() throws SQLException { try (Statement stmt = sharedConnection.createStatement()) { stmt.setFetchSize(1); stmt.executeQuery( - "select * from information_schema.columns as c1, information_schema.tables LIMIT 200000"); + "select * from information_schema.columns as c1, information_schema.tables LIMIT 400000"); stmt.cancel(); } long interruptedExecutionTime = System.currentTimeMillis() - start; - Assume.assumeTrue(minVersion(10, 1)); // 10.1.2 in fact - // ensure that query is a long query. if not cancelling the query (that might lead to creating a // new connection) // may not render the test reliable - String maxscaleVersion = System.getenv("MAXSCALE_VERSION"); - if (maxscaleVersion == null && normalExecutionTime > 500) { + if (normalExecutionTime > 500) { assertTrue( "interruptedExecutionTime:" + interruptedExecutionTime @@ -237,7 +234,7 @@ public void fetchSizeCancel() throws SQLException { @Test public void fetchSizePrepareCancel() throws SQLException { - ifMaxscaleRequireMinimumVersion(2, 2); + Assume.assumeTrue(System.getenv("MAXSCALE_TEST_DISABLE") == null); Assume.assumeTrue(!sharedOptions().profileSql && !sharedOptions().pool); long start; diff --git a/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java b/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java index a5ea3544d..0ccdf3467 100644 --- a/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java +++ b/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java @@ -300,7 +300,7 @@ public void test2xBigLocalInfileInputStream() throws Exception { public void testMoreThanMaxAllowedPacketLocalInfileInputStream() throws Exception { Assume.assumeFalse( (isMariadbServer() && minVersion(10, 4, 0)) || (!isMariadbServer() && minVersion(8, 0, 3))); - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); Assume.assumeFalse(sharedIsAurora()); Statement stmt = sharedConnection.createStatement(); ResultSet rs = stmt.executeQuery("select @@max_allowed_packet"); diff --git a/src/test/java/org/mariadb/jdbc/MariaDbPoolDataSourceTest.java b/src/test/java/org/mariadb/jdbc/MariaDbPoolDataSourceTest.java index c08c605e5..928d7cc38 100644 --- a/src/test/java/org/mariadb/jdbc/MariaDbPoolDataSourceTest.java +++ b/src/test/java/org/mariadb/jdbc/MariaDbPoolDataSourceTest.java @@ -296,9 +296,7 @@ public void testIdleTimeout() throws Throwable { // not for maxscale, testing thread id is not relevant. // appveyor is so slow wait time are not relevant. Assume.assumeTrue( - System.getenv("MAXSCALE_VERSION") == null - && System.getenv("SKYSQL") == null - && System.getenv("APPVEYOR_BUILD_WORKER_IMAGE") == null); + System.getenv("SKYSQL") == null && System.getenv("APPVEYOR_BUILD_WORKER_IMAGE") == null); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); ObjectName filter = new ObjectName("org.mariadb.jdbc.pool:type=testIdleTimeout-*"); diff --git a/src/test/java/org/mariadb/jdbc/MultiTest.java b/src/test/java/org/mariadb/jdbc/MultiTest.java index d913be887..046c7e85f 100644 --- a/src/test/java/org/mariadb/jdbc/MultiTest.java +++ b/src/test/java/org/mariadb/jdbc/MultiTest.java @@ -65,7 +65,7 @@ public class MultiTest extends BaseTest { /** Tables initialisation. */ @BeforeClass() public static void initClass() throws SQLException { - System.out.println("DIEGO MultiTest initClass BEGIN"); + createTable("MultiTestt1", "id int, test varchar(100)"); createTable("MultiTestt2", "id int, test varchar(100)"); createTable("MultiTestt3", "message text"); diff --git a/src/test/java/org/mariadb/jdbc/PooledConnectionTest.java b/src/test/java/org/mariadb/jdbc/PooledConnectionTest.java index 9e8b26f14..921f36dfe 100644 --- a/src/test/java/org/mariadb/jdbc/PooledConnectionTest.java +++ b/src/test/java/org/mariadb/jdbc/PooledConnectionTest.java @@ -88,7 +88,7 @@ public void testPooledConnectionClosed() throws Exception { @Test(expected = SQLException.class) public void testPooledConnectionException() throws Exception { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null); ConnectionPoolDataSource ds = new MariaDbDataSource(hostname != null ? hostname : "localhost", port, database); diff --git a/src/test/java/org/mariadb/jdbc/SslTest.java b/src/test/java/org/mariadb/jdbc/SslTest.java index 5a2b8dda4..4cb951759 100644 --- a/src/test/java/org/mariadb/jdbc/SslTest.java +++ b/src/test/java/org/mariadb/jdbc/SslTest.java @@ -82,14 +82,12 @@ public class SslTest extends BaseTest { private String serverCertificatePath; private String clientKeystorePath; private String clientKeystorePassword; + private int sslPort; /** Enable Crypto. */ @BeforeClass public static void enableCrypto() { - Assume.assumeFalse( - System.getenv("MAXSCALE_VERSION") != null - || System.getenv("SKYSQL") != null - || "true".equals(System.getenv("AURORA"))); + Assume.assumeFalse(System.getenv("SKYSQL") != null || "true".equals(System.getenv("AURORA"))); try { Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted"); field.setAccessible(true); @@ -129,27 +127,35 @@ public void checkSsl() throws SQLException { } else { serverCertificatePath = System.getProperty("serverCertificatePath"); } + sslPort = + System.getProperty("sslPort") == null || System.getProperty("sslPort").isEmpty() + ? port + : Integer.valueOf(System.getProperty("sslPort")); clientKeystorePath = System.getProperty("keystorePath"); clientKeystorePassword = System.getProperty("keystorePassword"); Statement stmt = sharedConnection.createStatement(); - try { - stmt.execute("DROP USER 'ssltestUser'@'%'"); - } catch (SQLException e) { - // eat - } + boolean useOldNotation = true; if ((isMariadbServer() && minVersion(10, 2, 0)) || (!isMariadbServer() && minVersion(8, 0, 0))) { useOldNotation = false; } if (useOldNotation) { - stmt.execute("CREATE USER 'ssltestUser'@'%'"); + stmt.execute("CREATE USER IF NOT EXISTS 'ssltestUser'@'%'"); stmt.execute( "GRANT SELECT ON *.* TO 'ssltestUser'@'%' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); + stmt.execute("CREATE USER IF NOT EXISTS 'ssltestUser'@'localhost'"); + stmt.execute( + "GRANT SELECT ON *.* TO 'ssltestUser'@'localhost' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); } else { - stmt.execute("CREATE USER 'ssltestUser'@'%' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); + stmt.execute( + "CREATE USER IF NOT EXISTS 'ssltestUser'@'%' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); stmt.execute("GRANT SELECT ON *.* TO 'ssltestUser'@'%'"); + stmt.execute( + "CREATE USER IF NOT EXISTS 'ssltestUser'@'localhost' IDENTIFIED BY '!Passw0rd3Works' REQUIRE SSL"); + stmt.execute("GRANT SELECT ON *.* TO 'ssltestUser'@'localhost'"); } + stmt.execute("FLUSH PRIVILEGES"); } @Test @@ -157,7 +163,7 @@ public void useSsl() throws Exception { Assume.assumeTrue(haveSsl(sharedConnection) && isMariadbServer()); // Skip SSL test on java 7 since SSL stream size JDK-6521495). Assume.assumeFalse(System.getProperty("java.version").contains("1.7.")); - try (Connection connection = setConnection("&useSSL=true&trustServerCertificate=true")) { + try (Connection connection = createConnection("&useSSL=true&trustServerCertificate=true")) { connection.createStatement().execute("select 1"); } } @@ -179,7 +185,7 @@ protected void useSslForceTls(String tls, String ciphers) throws Exception { info.setProperty("enabledSslCipherSuites", ciphers); } - try (Connection connection = setConnection(info)) { + try (Connection connection = createConnection(info)) { connection.createStatement().execute("select 1"); } } @@ -272,8 +278,13 @@ public void useSslForceTlsV12AndCipher() throws Exception { || (isMariadbServer() && Platform.isWindows() && !minVersion(10, 4))); // Only test with MariaDB since MySQL community is compiled with yaSSL if (isMariadbServer()) { - useSslForceTls( - "TLSv1.2", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"); + try { + useSslForceTls( + "TLSv1.2", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"); + } catch (SQLException sqle) { + // in case ciphers not supported by server + assertTrue(sqle.getMessage().contains("handshake_failure")); + } } } @@ -323,7 +334,7 @@ public void wrongCipherMysqlOptionCompatibility() { // enabledSSLCipherSuites, not enabledSslCipherSuites (different case) info.setProperty("enabledSSLCipherSuites", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"); - try (Connection connection = setConnection(info)) { + try (Connection connection = createConnection(info)) { connection.createStatement().execute("select 1"); fail("Must have thrown error since cipher aren't TLSv1.1 ciphers"); } @@ -387,12 +398,30 @@ private void saveToFile(String path, String contents) { } private Connection createConnection(Properties info) throws SQLException { - return createConnection(info, username, password); + return createConnection(info, username, password, sslPort); + } + + private Connection createConnection(String param) throws SQLException { + return createConnection(param, new Properties(), username, password, sslPort); } - private Connection createConnection(Properties info, String user, String pwd) + private Connection createConnection(Properties info, String user, String pwd, int port) throws SQLException { - String jdbcUrl = connDnsUri; + return createConnection(null, info, user, pwd, port); + } + + private Connection createConnection( + String param, Properties info, String user, String pwd, int port) throws SQLException { + String jdbcUrl = + "jdbc:mariadb://mariadb.example.com:" + + port + + "/" + + database + + "?" + + parameters + + (password != null && !"".equals(password) ? "&password=" + password : "") + + (param != null ? param : ""); + ; Properties connProps = new Properties(info); connProps.setProperty("user", user); if (pwd != null) { @@ -426,7 +455,8 @@ public void testConnect(Properties info, boolean sslExpected, String user, Strin throws SQLException { Assume.assumeTrue(System.getenv("SKYSQL") == null); Assume.assumeTrue(haveSsl(sharedConnection) && isMariadbServer()); - try (Connection conn = createConnection(info, user, pwd)) { + + try (Connection conn = createConnection(info, user, pwd, sslPort)) { // First do a basic select test: try (Statement stmt = conn.createStatement()) { try (ResultSet rs = stmt.executeQuery("SHOW STATUS like 'Ssl_version'")) { @@ -453,7 +483,9 @@ public void testConnectNonSsl() throws SQLException { testConnect(info, false); fail("Must fail since user require SSL"); } catch (SQLException e) { - assertTrue(e.getMessage().contains("Access denied for user 'ssltestUser'")); + assertTrue( + e.getMessage().contains("Access denied for user 'ssltestUser'") + || e.getMessage().contains("Bad SSL handshake")); } } @@ -581,7 +613,7 @@ public void testNoSessionResumption() Assume.assumeTrue(haveSsl(sharedConnection) && isMariadbServer()); long sessionsReused = 0; - try (Connection conn = createConnection(info, "ssltestUser", "!Passw0rd3Works")) { + try (Connection conn = createConnection(info, "ssltestUser", "!Passw0rd3Works", sslPort)) { // First do a basic select test: Statement stmt = conn.createStatement(); @@ -597,7 +629,7 @@ public void testNoSessionResumption() sessionsReused = rs.getLong(2); } - try (Connection conn2 = createConnection(info, "ssltestUser", "!Passw0rd3Works")) { + try (Connection conn2 = createConnection(info, "ssltestUser", "!Passw0rd3Works", sslPort)) { Statement stmt2 = conn2.createStatement(); try (ResultSet rs = stmt2.executeQuery("SHOW STATUS LIKE 'Ssl_sessions_reused'")) { @@ -830,6 +862,7 @@ public void testClientKeystore() throws SQLException { */ @Test public void testClientKeyStoreWithPrivateKeyPwd() throws Exception { + Assume.assumeTrue(System.getenv("MAXSCALE_TEST_DISABLE") == null); Assume.assumeTrue(haveSsl(sharedConnection) && isMariadbServer()); String clientKeyStore2Path = System.getProperty("keystore2Path"); String clientKeyStore2Password = System.getProperty("keystore2Password"); @@ -1111,20 +1144,28 @@ private void createSslTestUser(String user) throws SQLException { } Statement st = sharedConnection.createStatement(); - try { - st.execute("DROP USER '" + user + "'@'%'"); - } catch (SQLException e) { - // eat - } - st.execute("FLUSH PRIVILEGES"); if (useOldNotation) { - st.execute("CREATE USER '" + user + "'@'%'"); + st.execute("CREATE USER IF NOT EXISTS '" + user + "'@'%'"); st.execute( "GRANT SELECT on *.* to '" + user + "'@'%' identified by 'ssltestpassword' REQUIRE X509"); + st.execute("CREATE USER IF NOT EXISTS '" + user + "'@'localhost'"); + st.execute( + "GRANT SELECT on *.* to '" + + user + + "'@'localhost' identified by 'ssltestpassword' REQUIRE X509"); } else { - st.execute("CREATE USER '" + user + "'@'%' identified by 'ssltestpassword' REQUIRE X509"); + st.execute( + "CREATE USER IF NOT EXISTS '" + + user + + "'@'%' identified by 'ssltestpassword' REQUIRE X509"); st.execute("GRANT SELECT on *.* to '" + user + "'@'%'"); + st.execute( + "CREATE USER IF NOT EXISTS '" + + user + + "'@'localhost' identified by 'ssltestpassword' REQUIRE X509"); + st.execute("GRANT SELECT on *.* to '" + user + "'@'localhost'"); } + st.execute("FLUSH PRIVILEGES"); } private void deleteSslTestUser(String user) throws SQLException { diff --git a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java index 227b65a79..f3e7a9f3d 100644 --- a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java +++ b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java @@ -404,22 +404,27 @@ public void meta() throws Exception { @Test public void testMetaCatalogNoAccessToProcedureBodies() throws Exception { + Assume.assumeTrue(System.getenv("SKYSQL") == null); + // cancel for version 10.2 beta before fix https://jira.mariadb.org/browse/MDEV-11761 cancelForVersion(10, 2, 2); cancelForVersion(10, 2, 3); cancelForVersion(10, 2, 4); Statement statement = sharedConnection.createStatement(); - try { - statement.execute("DROP USER 'test_jdbc'@'%'"); - } catch (SQLException e) { - // eat exception - } + statement.execute("DROP USER IF EXISTS 'test_jdbc'@'%'"); + statement.execute("DROP USER IF EXISTS 'test_jdbc'@'localhost'"); + statement.execute("CREATE USER 'test_jdbc'@'localhost' IDENTIFIED BY 'testJ@dc1'"); + statement.execute( + "GRANT ALL ON " + + database + + ".* TO 'test_jdbc'@'localhost' IDENTIFIED BY 'testJ@dc1' WITH GRANT OPTION"); statement.execute("CREATE USER 'test_jdbc'@'%' IDENTIFIED BY 'testJ@dc1'"); statement.execute( - "GRANT SELECT, EXECUTE ON " + "GRANT ALL ON " + database + ".* TO 'test_jdbc'@'%' IDENTIFIED BY 'testJ@dc1' WITH GRANT OPTION"); + statement.execute("FLUSH PRIVILEGES"); Properties properties = new Properties(); properties.put("user", "test_jdbc"); properties.put("password", "testJ@dc1"); @@ -470,6 +475,7 @@ public void testMetaCatalogNoAccessToProcedureBodies() throws Exception { // MySQL 5.5 doesn't permit 'test_jdbc'@'localhost' } statement.execute("DROP USER 'test_jdbc'@'%'"); + statement.execute("DROP USER 'test_jdbc'@'localhost'"); } @Test diff --git a/src/test/java/org/mariadb/jdbc/TimeoutTest.java b/src/test/java/org/mariadb/jdbc/TimeoutTest.java index 10aab992f..4a4c7455e 100644 --- a/src/test/java/org/mariadb/jdbc/TimeoutTest.java +++ b/src/test/java/org/mariadb/jdbc/TimeoutTest.java @@ -77,7 +77,8 @@ private static int selectValue(Connection conn, int value) throws SQLException { public void resultSetAfterSocketTimeoutTest() { // appveyor vm are very slow, cannot compare time Assume.assumeTrue( - System.getenv("APPVEYOR") == null + System.getenv("MAXSCALE_TEST_DISABLE") == null + && System.getenv("APPVEYOR") == null && System.getenv("DOCKER_SOCKET") == null && System.getenv("SKYSQL") == null); diff --git a/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java b/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java index 4c0caf102..5d40f3285 100644 --- a/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java +++ b/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java @@ -347,7 +347,7 @@ public void testTimeUtcNow() throws SQLException { @Test public void testTimeOffsetNowUseServer() throws SQLException { - Assume.assumeTrue(System.getenv("AURORA") == null || System.getenv("SKYSQL") == null); + Assume.assumeFalse("true".equals(System.getenv("AURORA"))); try (Connection connection = setConnection("&useLegacyDatetimeCode=false&serverTimezone=+5:00")) { setSessionTimeZone(connection, "+5:00"); diff --git a/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java b/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java index 37fa8e919..be26d2287 100644 --- a/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java +++ b/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java @@ -163,7 +163,7 @@ public void checkAutoReconnectDeconnection() throws Throwable { */ @Test public void isValidConnectionThatIsKilledExternally() throws Throwable { - Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null && System.getenv("SKYSQL") == null); + Assume.assumeTrue(System.getenv("SKYSQL") == null && System.getenv("MAXSCALE_TEST_DISABLE") == null); try (Connection connection = getNewConnection()) { connection.setCatalog("mysql"); Protocol protocol = getProtocolFromConnection(connection); From 143e8c9230e4723c7b6910329db71c8b5515cfe6 Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 24 Sep 2020 14:31:05 +0200 Subject: [PATCH 29/30] [CONJ-810] normalization of resultset getDate/getTime of timestamp field. To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance is now 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated (current client timezone or if option `useLegacyDatetimeCode` is disabled to server timezone). Same for java.sql.Time: The date components is set to the "zero epoch" value of January 1, 1970. example: getTime() on value '2015-03-29T01:45:00.012' return a java.sql.Time with value '01:45:00', submethod getTime return time in millisecond that did correspond to '2015-03-29T01:45:00.012'. Now correspond to '1970-01-01T01:45:00.012' --- CHANGELOG.md | 17 + .../mariadb/jdbc/BasePrepareStatement.java | 25 +- .../com/read/resultset/SelectResultSet.java | 5 +- .../read/resultset/UpdatableResultSet.java | 13 +- .../rowprotocol/BinaryRowProtocol.java | 212 +++++++-- .../rowprotocol/TextRowProtocol.java | 188 +++++++- .../com/send/parameters/DateParameter.java | 8 +- .../send/parameters/OffsetTimeParameter.java | 9 +- .../send/parameters/TimestampParameter.java | 6 +- .../parameters/ZonedDateTimeParameter.java | 7 +- .../protocol/AbstractConnectProtocol.java | 3 +- .../protocol/AbstractQueryProtocol.java | 3 +- .../java/org/mariadb/jdbc/CancelTest.java | 3 +- src/test/java/org/mariadb/jdbc/DateTest.java | 9 +- .../jdbc/LocalInfileInputStreamTest.java | 1 - .../java/org/mariadb/jdbc/LocalTimeTest.java | 12 +- .../jdbc/TimezoneDaylightSavingTimeTest.java | 441 +++++++++--------- .../jdbc/TimezoneExplicitCalendarTest.java | 1 + .../jdbc/failover/MonoServerFailoverTest.java | 3 +- 19 files changed, 642 insertions(+), 324 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfa1917ac..ff3115373 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Change Log +## [2.7.0](/~https://github.com/mariadb-corporation/mariadb-connector-j/tree/2.7.0) (24 Sep. 2020) +[Full Changelog](/~https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.6.2...2.7.0) + +* CONJ-805 maxFieldSize string truncation occurs on bytes length, not character length +* CONJ-807 Correcting possible Get Access Denied error if using multiple classloader +* CONJ-810 normalization of resultset getDate/getTime of timestamp field. +* CONJ-812 DatabaseMetadata.getBestRowIdentifier and getMaxProcedureNameLength correction +* CONJ-813 setConfiguration not being called on classes that extend ConfigurableSocketFactory +* CONJ-816 Table with primary key with DEFAULT function can be inserted for 10.5 servers +* CONJ-817 Switched position of REMARKS and PROCEDURE_TYPE in the getProcedures result +* CONJ-820 MySQLPreparedStatement.setObject can now handle java.lang.Character type +* CONJ-828 new option `ensureSocketState` to ensure protocol state +* CONJ-829 Option to cache callablestatement is now disabled by default +* CONJ-830 connector now throw a better error if SSL is mandatory and server doesn't support SSL +* CONJ-814 Small possible improvement of getCrossReference, getExportedKeys and getImportedKey +* CONJ-825 XAResource.isSameRM implementation + ## [2.6.2](/~https://github.com/mariadb-corporation/mariadb-connector-j/tree/2.6.2) (23 Jul. 2020) [Full Changelog](/~https://github.com/mariadb-corporation/mariadb-connector-j/compare/2.6.1...2.6.2) diff --git a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java index e2efd198c..9efa0550c 100644 --- a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java +++ b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java @@ -911,22 +911,19 @@ public void setObject(final int parameterIndex, final Object obj) throws SQLExce parameterIndex, new ZonedDateTimeParameter( ((OffsetDateTime) obj).toZonedDateTime(), - protocol.getTimeZone().toZoneId(), + protocol.getTimeZone(), useFractionalSeconds, options)); } else if (obj instanceof OffsetTime) { setParameter( parameterIndex, new OffsetTimeParameter( - (OffsetTime) obj, protocol.getTimeZone().toZoneId(), useFractionalSeconds, options)); + (OffsetTime) obj, protocol.getTimeZone(), useFractionalSeconds, options)); } else if (obj instanceof ZonedDateTime) { setParameter( parameterIndex, new ZonedDateTimeParameter( - (ZonedDateTime) obj, - protocol.getTimeZone().toZoneId(), - useFractionalSeconds, - options)); + (ZonedDateTime) obj, protocol.getTimeZone(), useFractionalSeconds, options)); } else if (obj instanceof LocalTime) { setParameter(parameterIndex, new LocalTimeParameter((LocalTime) obj, useFractionalSeconds)); } else { @@ -1025,17 +1022,14 @@ private void setInternalObject( setParameter( parameterIndex, new OffsetTimeParameter( - OffsetTime.parse(str), - protocol.getTimeZone().toZoneId(), - useFractionalSeconds, - options)); + OffsetTime.parse(str), protocol.getTimeZone(), useFractionalSeconds, options)); break; case Types.TIMESTAMP_WITH_TIMEZONE: setParameter( parameterIndex, new ZonedDateTimeParameter( ZonedDateTime.parse(str, SPEC_ISO_ZONED_DATE_TIME), - protocol.getTimeZone().toZoneId(), + protocol.getTimeZone(), useFractionalSeconds, options)); break; @@ -1136,22 +1130,19 @@ private void setInternalObject( parameterIndex, new ZonedDateTimeParameter( ((OffsetDateTime) obj).toZonedDateTime(), - protocol.getTimeZone().toZoneId(), + protocol.getTimeZone(), useFractionalSeconds, options)); } else if (obj instanceof OffsetTime) { setParameter( parameterIndex, new OffsetTimeParameter( - (OffsetTime) obj, protocol.getTimeZone().toZoneId(), useFractionalSeconds, options)); + (OffsetTime) obj, protocol.getTimeZone(), useFractionalSeconds, options)); } else if (obj instanceof ZonedDateTime) { setParameter( parameterIndex, new ZonedDateTimeParameter( - (ZonedDateTime) obj, - protocol.getTimeZone().toZoneId(), - useFractionalSeconds, - options)); + (ZonedDateTime) obj, protocol.getTimeZone(), useFractionalSeconds, options)); } else if (obj instanceof LocalTime) { setParameter(parameterIndex, new LocalTimeParameter((LocalTime) obj, useFractionalSeconds)); } else { diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java index aac0eb49a..8ddc39356 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java @@ -1214,7 +1214,7 @@ public T getObject(int columnIndex, Class type) throws SQLException { System.arraycopy(row.buf, row.pos, data, 0, row.getLengthMaxFieldSize()); return (T) data; - } else if (type.equals(Date.class)) { + } else if (type.equals(Date.class) || type.equals(java.util.Date.class)) { return (T) row.getInternalDate(col, null, timeZone); } else if (type.equals(Time.class)) { @@ -1227,7 +1227,8 @@ public T getObject(int columnIndex, Class type) throws SQLException { return (T) (Boolean) row.getInternalBoolean(col); } else if (type.equals(Calendar.class)) { - Calendar calendar = Calendar.getInstance(timeZone); + Calendar calendar = + timeZone == null ? Calendar.getInstance() : Calendar.getInstance(timeZone); Timestamp timestamp = row.getInternalTimestamp(col, null, timeZone); if (timestamp == null) { return null; diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java index a7720ded8..21e4bd833 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/UpdatableResultSet.java @@ -688,16 +688,13 @@ private void updateInternalObject( case Types.TIME_WITH_TIMEZONE: parameterHolders[parameterIndex - 1] = new OffsetTimeParameter( - OffsetTime.parse(str), - timeZone.toZoneId(), - options.useFractionalSeconds, - options); + OffsetTime.parse(str), timeZone, options.useFractionalSeconds, options); break; case Types.TIMESTAMP_WITH_TIMEZONE: parameterHolders[parameterIndex - 1] = new ZonedDateTimeParameter( ZonedDateTime.parse(str, BasePrepareStatement.SPEC_ISO_ZONED_DATE_TIME), - timeZone.toZoneId(), + timeZone, options.useFractionalSeconds, options); break; @@ -797,17 +794,17 @@ private void updateInternalObject( parameterHolders[parameterIndex - 1] = new ZonedDateTimeParameter( ((OffsetDateTime) obj).toZonedDateTime(), - timeZone.toZoneId(), + timeZone, options.useFractionalSeconds, options); } else if (obj instanceof OffsetTime) { parameterHolders[parameterIndex - 1] = new OffsetTimeParameter( - (OffsetTime) obj, timeZone.toZoneId(), options.useFractionalSeconds, options); + (OffsetTime) obj, timeZone, options.useFractionalSeconds, options); } else if (obj instanceof ZonedDateTime) { parameterHolders[parameterIndex - 1] = new ZonedDateTimeParameter( - (ZonedDateTime) obj, timeZone.toZoneId(), options.useFractionalSeconds, options); + (ZonedDateTime) obj, timeZone, options.useFractionalSeconds, options); } else if (obj instanceof LocalTime) { updateTime(parameterIndex, Time.valueOf((LocalTime) obj)); } else { diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/BinaryRowProtocol.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/BinaryRowProtocol.java index 05a6cc003..63b6ab052 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/BinaryRowProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/BinaryRowProtocol.java @@ -61,6 +61,7 @@ import java.time.format.DateTimeParseException; import java.util.Calendar; import java.util.TimeZone; +import org.mariadb.jdbc.internal.ColumnType; import org.mariadb.jdbc.internal.com.read.resultset.ColumnDefinition; import org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory; import org.mariadb.jdbc.util.Options; @@ -802,11 +803,79 @@ public Date getInternalDate(ColumnDefinition columnInfo, Calendar cal, TimeZone if (lastValueWasNull()) { return null; } + if (length == 0) { + lastValueNull |= BIT_LAST_FIELD_NULL; + return null; + } + int year; + int month = 1; + int day = 1; + Calendar calendar; switch (columnInfo.getColumnType()) { case TIMESTAMP: case DATETIME: - Timestamp timestamp = getInternalTimestamp(columnInfo, cal, timeZone); - return (timestamp == null) ? null : new Date(timestamp.getTime()); + year = ((buf[pos] & 0xff) | (buf[pos + 1] & 0xff) << 8); + month = buf[pos + 2]; + day = buf[pos + 3]; + int hour = 0; + int minutes = 0; + int seconds = 0; + int microseconds = 0; + + if (length > 4) { + hour = buf[pos + 4]; + minutes = buf[pos + 5]; + seconds = buf[pos + 6]; + + if (length > 7) { + microseconds = + ((buf[pos + 7] & 0xff) + + ((buf[pos + 8] & 0xff) << 8) + + ((buf[pos + 9] & 0xff) << 16) + + ((buf[pos + 10] & 0xff) << 24)); + } + } + + if (year == 0 && month == 0 && day == 0) { + lastValueNull |= BIT_LAST_FIELD_NULL; + return null; + } + + if (timeZone == null) { + // legacy is to send timestamps with current driver timezone. So display, is immediate + calendar = (cal != null) ? cal : Calendar.getInstance(); + synchronized (calendar) { + calendar.clear(); + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, month - 1); + calendar.set(Calendar.DAY_OF_MONTH, day); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return new Date(calendar.getTimeInMillis()); + } + } + + // timestamp is saved in server timezone, + LocalDateTime ldt = + LocalDateTime.of(year, month, day, hour, minutes, seconds, microseconds * 1000); + ZonedDateTime zdt = + ldt.atZone(timeZone.toZoneId()).withZoneSameInstant(TimeZone.getDefault().toZoneId()); + + calendar = cal != null ? cal : Calendar.getInstance(); + synchronized (calendar) { + calendar.clear(); + calendar.set(Calendar.YEAR, zdt.getYear()); + calendar.set(Calendar.MONTH, zdt.getMonthValue() - 1); + calendar.set(Calendar.DAY_OF_MONTH, zdt.getDayOfMonth()); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return new Date(calendar.getTimeInMillis()); + } + case TIME: throw new SQLException("Cannot read Date using a Types.TIME field"); case STRING: @@ -821,12 +890,7 @@ public Date getInternalDate(ColumnDefinition columnInfo, Calendar cal, TimeZone Integer.parseInt(rawValue.substring(5, 7)) - 1, Integer.parseInt(rawValue.substring(8, 10))); default: - if (length == 0) { - lastValueNull |= BIT_LAST_FIELD_NULL; - return null; - } - - int year = ((buf[pos] & 0xff) | (buf[pos + 1] & 0xff) << 8); + year = ((buf[pos] & 0xff) | (buf[pos + 1] & 0xff) << 8); if (length == 2 && columnInfo.getLength() == 2) { // YEAR(2) - deprecated @@ -837,25 +901,12 @@ public Date getInternalDate(ColumnDefinition columnInfo, Calendar cal, TimeZone } } - int month = 1; - int day = 1; - if (length >= 4) { month = buf[pos + 2]; day = buf[pos + 3]; } - Calendar calendar = Calendar.getInstance(); - calendar.clear(); - calendar.set(Calendar.YEAR, year); - calendar.set(Calendar.MONTH, month - 1); - calendar.set(Calendar.DAY_OF_MONTH, day); - calendar.set(Calendar.HOUR_OF_DAY, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MILLISECOND, 0); - Date dt = new Date(calendar.getTimeInMillis()); - return dt; + return new Date(year - 1900, month - 1, day); } } @@ -873,20 +924,78 @@ public Time getInternalTime(ColumnDefinition columnInfo, Calendar cal, TimeZone if (lastValueWasNull()) { return null; } + + Calendar calendar; + int day = 0; + int hour = 0; + int minutes = 0; + int seconds = 0; + int microseconds = 0; + switch (columnInfo.getColumnType()) { case TIMESTAMP: case DATETIME: - Timestamp ts = getInternalTimestamp(columnInfo, cal, timeZone); - return (ts == null) ? null : new Time(ts.getTime()); + if (length == 0) { + lastValueNull |= BIT_LAST_FIELD_NULL; + return null; + } + int year = ((buf[pos] & 0xff) | (buf[pos + 1] & 0xff) << 8); + int month = buf[pos + 2]; + day = buf[pos + 3]; + if (length > 4) { + hour = buf[pos + 4]; + minutes = buf[pos + 5]; + seconds = buf[pos + 6]; + + if (length > 7) { + microseconds = + ((buf[pos + 7] & 0xff) + + ((buf[pos + 8] & 0xff) << 8) + + ((buf[pos + 9] & 0xff) << 16) + + ((buf[pos + 10] & 0xff) << 24)); + } + } + + if (timeZone == null) { + calendar = cal != null ? cal : Calendar.getInstance(); + synchronized (calendar) { + calendar.clear(); + calendar.set(Calendar.YEAR, 1970); + calendar.set(Calendar.MONTH, 0); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.set(Calendar.HOUR_OF_DAY, hour); + calendar.set(Calendar.MINUTE, minutes); + calendar.set(Calendar.SECOND, seconds); + calendar.set(Calendar.MILLISECOND, microseconds / 1_000); + return new Time(calendar.getTimeInMillis()); + } + } + + LocalDateTime ldt = + LocalDateTime.of(year, month, day, hour, minutes, seconds, microseconds * 1000); + ZonedDateTime zdt = + ldt.atZone(timeZone.toZoneId()).withZoneSameInstant(TimeZone.getDefault().toZoneId()); + + calendar = cal != null ? cal : Calendar.getInstance(); + synchronized (calendar) { + calendar.clear(); + calendar.set(Calendar.YEAR, 1970); + calendar.set(Calendar.MONTH, 0); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.set(Calendar.HOUR_OF_DAY, zdt.getHour()); + calendar.set(Calendar.MINUTE, zdt.getMinute()); + calendar.set(Calendar.SECOND, zdt.getSecond()); + calendar.set(Calendar.MILLISECOND, zdt.getNano() / 1_000_000); + return new Time(calendar.getTimeInMillis()); + } + case DATE: throw new SQLException("Cannot read Time using a Types.DATE field"); + default: - Calendar calendar = cal != null ? cal : Calendar.getInstance(); + calendar = cal != null ? cal : Calendar.getInstance(); calendar.clear(); - int day = 0; - int hour = 0; - int minutes = 0; - int seconds = 0; + boolean negate = false; if (length > 0) { negate = (buf[pos] & 0xff) == 0x01; @@ -953,9 +1062,10 @@ public Timestamp getInternalTimestamp( int seconds = 0; int microseconds = 0; + Calendar calendar; switch (columnInfo.getColumnType()) { case TIME: - Calendar calendar = userCalendar != null ? userCalendar : Calendar.getInstance(); + calendar = userCalendar != null ? userCalendar : Calendar.getInstance(); boolean negate = false; if (length > 0) { @@ -1010,6 +1120,15 @@ public Timestamp getInternalTimestamp( } } } + + if (userCalendar != null) { + calendar = userCalendar; + } else if (timeZone != null) { + calendar = Calendar.getInstance(timeZone); + } else { + calendar = Calendar.getInstance(); + } + break; default: @@ -1029,15 +1148,14 @@ public Timestamp getInternalTimestamp( + ((buf[pos + 10] & 0xff) << 24)); } } - } - Calendar calendar; - if (userCalendar != null) { - calendar = userCalendar; - } else if (columnInfo.getColumnType().getSqlType() == Types.TIMESTAMP) { - calendar = Calendar.getInstance(timeZone); - } else { - calendar = Calendar.getInstance(); + if (userCalendar != null) { + calendar = userCalendar; + } else if (timeZone != null && columnInfo.getColumnType() != ColumnType.DATE) { + calendar = Calendar.getInstance(timeZone); + } else { + calendar = Calendar.getInstance(); + } } Timestamp tt; @@ -1489,7 +1607,14 @@ public ZonedDateTime getInternalZonedDateTime( } return ZonedDateTime.of( - year, month, day, hour, minutes, seconds, microseconds * 1000, timeZone.toZoneId()); + year, + month, + day, + hour, + minutes, + seconds, + microseconds * 1000, + timeZone == null ? ZoneId.systemDefault() : timeZone.toZoneId()); case Types.VARCHAR: case Types.LONGVARCHAR: @@ -1537,7 +1662,8 @@ public OffsetTime getInternalOffsetTime(ColumnDefinition columnInfo, TimeZone ti return null; } - ZoneId zoneId = timeZone.toZoneId().normalized(); + ZoneId zoneId = + timeZone == null ? ZoneId.systemDefault().normalized() : timeZone.toZoneId().normalized(); if (zoneId instanceof ZoneOffset) { ZoneOffset zoneOffset = (ZoneOffset) zoneId; @@ -1702,6 +1828,9 @@ public LocalTime getInternalLocalTime(ColumnDefinition columnInfo, TimeZone time // string conversion String raw = new String(buf, pos, length, StandardCharsets.UTF_8); try { + if (timeZone == null) { + return LocalTime.parse(raw, DateTimeFormatter.ISO_LOCAL_TIME); + } return LocalTime.parse( raw, DateTimeFormatter.ISO_LOCAL_TIME.withZone(timeZone.toZoneId())); } catch (DateTimeParseException dateParserEx) { @@ -1768,6 +1897,9 @@ public LocalDate getInternalLocalDate(ColumnDefinition columnInfo, TimeZone time return null; } try { + if (timeZone == null) { + return LocalDate.parse(raw, DateTimeFormatter.ISO_LOCAL_DATE); + } return LocalDate.parse( raw, DateTimeFormatter.ISO_LOCAL_DATE.withZone(timeZone.toZoneId())); } catch (DateTimeParseException dateParserEx) { diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java index 3631b56e7..956c31e00 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/rowprotocol/TextRowProtocol.java @@ -483,10 +483,10 @@ public Date getInternalDate(ColumnDefinition columnInfo, Calendar cal, TimeZone return null; } + int partIdx = 0; switch (columnInfo.getColumnType()) { case DATE: int[] datePart = new int[] {0, 0, 0}; - int partIdx = 0; for (int begin = pos; begin < pos + length; begin++) { byte b = buf[begin]; if (b == '-') { @@ -511,11 +511,87 @@ public Date getInternalDate(ColumnDefinition columnInfo, Calendar cal, TimeZone case TIMESTAMP: case DATETIME: - Timestamp timestamp = getInternalTimestamp(columnInfo, cal, timeZone); - if (timestamp == null) { + int nanoBegin = -1; + int[] timestampsPart = new int[] {0, 0, 0, 0, 0, 0, 0}; + for (int begin = pos; begin < pos + length; begin++) { + byte b = buf[begin]; + if (b == '-' || b == ' ' || b == ':') { + partIdx++; + continue; + } + if (b == '.') { + partIdx++; + nanoBegin = begin; + continue; + } + if (b < '0' || b > '9') { + throw new SQLException( + "cannot parse data in timestamp string '" + + new String(buf, pos, length, StandardCharsets.UTF_8) + + "'"); + } + + timestampsPart[partIdx] = timestampsPart[partIdx] * 10 + b - 48; + } + if (timestampsPart[0] == 0 + && timestampsPart[1] == 0 + && timestampsPart[2] == 0 + && timestampsPart[3] == 0 + && timestampsPart[4] == 0 + && timestampsPart[5] == 0 + && timestampsPart[6] == 0) { + lastValueNull |= BIT_LAST_ZERO_DATE; return null; } - return new Date(timestamp.getTime()); + + // fix non leading tray for nanoseconds + if (nanoBegin > 0) { + for (int begin = 0; begin < 6 - (pos + length - nanoBegin - 1); begin++) { + timestampsPart[6] = timestampsPart[6] * 10; + } + } + + if (timeZone == null) { + // legacy is to send timestamps with current driver timezone. So display, is immediate + Calendar calendar = (cal != null) ? cal : Calendar.getInstance(); + synchronized (calendar) { + calendar.clear(); + calendar.set(Calendar.YEAR, timestampsPart[0]); + calendar.set(Calendar.MONTH, timestampsPart[1] - 1); + calendar.set(Calendar.DAY_OF_MONTH, timestampsPart[2]); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return new Date(calendar.getTimeInMillis()); + } + } + + // timestamp is saved in server timezone, + LocalDateTime ldt = + LocalDateTime.of( + timestampsPart[0], + timestampsPart[1], + timestampsPart[2], + timestampsPart[3], + timestampsPart[4], + timestampsPart[5], + timestampsPart[6] * 1000); + ZonedDateTime zdt = + ldt.atZone(timeZone.toZoneId()).withZoneSameInstant(TimeZone.getDefault().toZoneId()); + + Calendar calendar = cal != null ? cal : Calendar.getInstance(); + synchronized (calendar) { + calendar.clear(); + calendar.set(Calendar.YEAR, zdt.getYear()); + calendar.set(Calendar.MONTH, zdt.getMonthValue() - 1); + calendar.set(Calendar.DAY_OF_MONTH, zdt.getDayOfMonth()); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return new Date(calendar.getTimeInMillis()); + } case TIME: throw new SQLException("Cannot read DATE using a Types.TIME field"); @@ -537,7 +613,9 @@ public Date getInternalDate(ColumnDefinition columnInfo, Calendar cal, TimeZone default: try { DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - sdf.setTimeZone(timeZone); + if (timeZone != null) { + sdf.setTimeZone(timeZone); + } java.util.Date utilDate = sdf.parse(new String(buf, pos, length, StandardCharsets.UTF_8)); return new Date(utilDate.getTime()); @@ -565,8 +643,86 @@ public Time getInternalTime(ColumnDefinition columnInfo, Calendar cal, TimeZone if (columnInfo.getColumnType() == ColumnType.TIMESTAMP || columnInfo.getColumnType() == ColumnType.DATETIME) { - Timestamp timestamp = getInternalTimestamp(columnInfo, cal, timeZone); - return (timestamp == null) ? null : new Time(timestamp.getTime()); + int nanoBegin = -1; + int[] timestampsPart = new int[] {0, 0, 0, 0, 0, 0, 0}; + int partIdx = 0; + for (int begin = pos; begin < pos + length; begin++) { + byte b = buf[begin]; + if (b == '-' || b == ' ' || b == ':') { + partIdx++; + continue; + } + if (b == '.') { + partIdx++; + nanoBegin = begin; + continue; + } + if (b < '0' || b > '9') { + throw new SQLException( + "cannot parse data in timestamp string '" + + new String(buf, pos, length, StandardCharsets.UTF_8) + + "'"); + } + + timestampsPart[partIdx] = timestampsPart[partIdx] * 10 + b - 48; + } + if (timestampsPart[0] == 0 + && timestampsPart[1] == 0 + && timestampsPart[2] == 0 + && timestampsPart[3] == 0 + && timestampsPart[4] == 0 + && timestampsPart[5] == 0 + && timestampsPart[6] == 0) { + lastValueNull |= BIT_LAST_ZERO_DATE; + return null; + } + + // fix non leading tray for nanoseconds + if (nanoBegin > 0) { + for (int begin = 0; begin < 6 - (pos + length - nanoBegin - 1); begin++) { + timestampsPart[6] = timestampsPart[6] * 10; + } + } + + if (timeZone == null) { + Calendar calendar = cal != null ? cal : Calendar.getInstance(); + synchronized (calendar) { + calendar.clear(); + calendar.set(Calendar.YEAR, 1970); + calendar.set(Calendar.MONTH, 0); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.set(Calendar.HOUR_OF_DAY, timestampsPart[3]); + calendar.set(Calendar.MINUTE, timestampsPart[4]); + calendar.set(Calendar.SECOND, timestampsPart[5]); + calendar.set(Calendar.MILLISECOND, timestampsPart[6] / 1_000); + return new Time(calendar.getTimeInMillis()); + } + } + + LocalDateTime ldt = + LocalDateTime.of( + timestampsPart[0], + timestampsPart[1], + timestampsPart[2], + timestampsPart[3], + timestampsPart[4], + timestampsPart[5], + timestampsPart[6] * 1000); + ZonedDateTime zdt = + ldt.atZone(timeZone.toZoneId()).withZoneSameInstant(TimeZone.getDefault().toZoneId()); + + Calendar calendar = cal != null ? cal : Calendar.getInstance(); + synchronized (calendar) { + calendar.clear(); + calendar.set(Calendar.YEAR, 1970); + calendar.set(Calendar.MONTH, 0); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.set(Calendar.HOUR_OF_DAY, zdt.getHour()); + calendar.set(Calendar.MINUTE, zdt.getMinute()); + calendar.set(Calendar.SECOND, zdt.getSecond()); + calendar.set(Calendar.MILLISECOND, zdt.getNano() / 1_000_000); + return new Time(calendar.getTimeInMillis()); + } } else if (columnInfo.getColumnType() == ColumnType.DATE) { @@ -672,7 +828,7 @@ public Timestamp getInternalTimestamp( Calendar calendar; if (userCalendar != null) { calendar = userCalendar; - } else if (columnInfo.getColumnType().getSqlType() == Types.TIMESTAMP) { + } else if (timeZone != null && columnInfo.getColumnType() != ColumnType.DATE) { calendar = Calendar.getInstance(timeZone); } else { calendar = Calendar.getInstance(); @@ -920,6 +1076,11 @@ public ZonedDateTime getInternalZonedDateTime( return null; } try { + if (timeZone == null) { + LocalDateTime localDateTime = LocalDateTime.parse(raw, TEXT_LOCAL_DATE_TIME); + return ZonedDateTime.of(localDateTime, TimeZone.getDefault().toZoneId()); + } + LocalDateTime localDateTime = LocalDateTime.parse(raw, TEXT_LOCAL_DATE_TIME.withZone(timeZone.toZoneId())); return ZonedDateTime.of(localDateTime, timeZone.toZoneId()); @@ -972,7 +1133,10 @@ public OffsetTime getInternalOffsetTime(ColumnDefinition columnInfo, TimeZone ti return null; } - ZoneId zoneId = timeZone.toZoneId().normalized(); + ZoneId zoneId = + timeZone != null + ? timeZone.toZoneId().normalized() + : TimeZone.getDefault().toZoneId().normalized(); if (zoneId instanceof ZoneOffset) { ZoneOffset zoneOffset = (ZoneOffset) zoneId; String raw = new String(buf, pos, length, StandardCharsets.UTF_8); @@ -1068,6 +1232,9 @@ public LocalTime getInternalLocalTime(ColumnDefinition columnInfo, TimeZone time case Types.LONGVARCHAR: case Types.CHAR: try { + if (timeZone == null) { + return LocalTime.parse(raw, DateTimeFormatter.ISO_LOCAL_TIME); + } return LocalTime.parse( raw, DateTimeFormatter.ISO_LOCAL_TIME.withZone(timeZone.toZoneId())); } catch (DateTimeParseException dateParserEx) { @@ -1122,6 +1289,9 @@ public LocalDate getInternalLocalDate(ColumnDefinition columnInfo, TimeZone time return null; } try { + if (timeZone == null) { + return LocalDate.parse(raw, DateTimeFormatter.ISO_LOCAL_DATE); + } return LocalDate.parse( raw, DateTimeFormatter.ISO_LOCAL_DATE.withZone(timeZone.toZoneId())); } catch (DateTimeParseException dateParserEx) { diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/DateParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/DateParameter.java index 77f86bae3..4dca208dd 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/DateParameter.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/DateParameter.java @@ -93,12 +93,7 @@ public void writeTo(final PacketOutputStream os) throws IOException { private byte[] dateByteFormat() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - if (options.useLegacyDatetimeCode || options.maximizeMysqlCompatibility) { - sdf.setTimeZone(Calendar.getInstance().getTimeZone()); - } else { - sdf.setTimeZone(timeZone); - } - + sdf.setTimeZone(timeZone); return sdf.format(date).getBytes(); } @@ -115,7 +110,6 @@ public int getApproximateTextProtocolLength() { public void writeBinary(final PacketOutputStream pos) throws IOException { Calendar calendar = Calendar.getInstance(timeZone); calendar.setTimeInMillis(date.getTime()); - pos.write((byte) 7); // length pos.writeShort((short) calendar.get(Calendar.YEAR)); pos.write((byte) ((calendar.get(Calendar.MONTH) + 1) & 0xff)); diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/OffsetTimeParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/OffsetTimeParameter.java index 8a48ac63e..73a61eebe 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/OffsetTimeParameter.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/OffsetTimeParameter.java @@ -59,6 +59,7 @@ import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.Locale; +import java.util.TimeZone; import org.mariadb.jdbc.internal.ColumnType; import org.mariadb.jdbc.internal.io.output.PacketOutputStream; import org.mariadb.jdbc.util.Options; @@ -72,19 +73,19 @@ public class OffsetTimeParameter implements Cloneable, ParameterHolder { * Constructor. * * @param offsetTime time with offset - * @param serverZoneId server session zoneId + * @param timezone server session zoneId * @param fractionalSeconds must fractional Seconds be send to database. * @param options session options * @throws SQLException if offset cannot be converted to server offset */ public OffsetTimeParameter( - OffsetTime offsetTime, ZoneId serverZoneId, boolean fractionalSeconds, Options options) + OffsetTime offsetTime, TimeZone timezone, boolean fractionalSeconds, Options options) throws SQLException { - ZoneId zoneId = options.useLegacyDatetimeCode ? ZoneOffset.systemDefault() : serverZoneId; + ZoneId zoneId = timezone == null ? ZoneOffset.systemDefault() : timezone.toZoneId(); if (zoneId instanceof ZoneOffset) { throw new SQLException( "cannot set OffsetTime, since server time zone is set to '" - + serverZoneId.toString() + + timezone.toZoneId().toString() + "' (check server variables time_zone and system_time_zone)"); } this.time = offsetTime.withOffsetSameInstant((ZoneOffset) zoneId); diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/TimestampParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/TimestampParameter.java index 131b2f48a..8c10218b4 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/TimestampParameter.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/TimestampParameter.java @@ -86,7 +86,7 @@ public TimestampParameter(Timestamp ts, TimeZone timeZone, boolean fractionalSec */ public void writeTo(final PacketOutputStream pos) throws IOException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - sdf.setTimeZone(timeZone); + if (timeZone != null) sdf.setTimeZone(timeZone); pos.write(QUOTE); pos.write(sdf.format(ts).getBytes()); @@ -116,7 +116,9 @@ public int getApproximateTextProtocolLength() { * @throws IOException if socket error occur */ public void writeBinary(final PacketOutputStream pos) throws IOException { - Calendar calendar = Calendar.getInstance(timeZone); + + Calendar calendar = + (timeZone == null) ? Calendar.getInstance() : Calendar.getInstance(timeZone); calendar.setTimeInMillis(ts.getTime()); pos.write((byte) (fractionalSeconds ? 11 : 7)); // length diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ZonedDateTimeParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ZonedDateTimeParameter.java index 6f35b2841..3617a2d78 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ZonedDateTimeParameter.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ZonedDateTimeParameter.java @@ -58,6 +58,7 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; +import java.util.TimeZone; import org.mariadb.jdbc.internal.ColumnType; import org.mariadb.jdbc.internal.io.output.PacketOutputStream; import org.mariadb.jdbc.util.Options; @@ -75,13 +76,13 @@ public class ZonedDateTimeParameter implements Cloneable, ParameterHolder { * Constructor. * * @param tz zone date time - * @param serverZoneId server session zoneId + * @param timezone server session timezone * @param fractionalSeconds must fractional Seconds be send to database. * @param options session options */ public ZonedDateTimeParameter( - ZonedDateTime tz, ZoneId serverZoneId, boolean fractionalSeconds, Options options) { - ZoneId zoneId = options.useLegacyDatetimeCode ? ZoneOffset.systemDefault() : serverZoneId; + ZonedDateTime tz, TimeZone timezone, boolean fractionalSeconds, Options options) { + ZoneId zoneId = timezone == null ? ZoneOffset.systemDefault() : timezone.toZoneId(); this.tz = tz.withZoneSameInstant(zoneId); this.fractionalSeconds = fractionalSeconds; } diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java index 2be182ace..993a21a6b 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java @@ -1146,7 +1146,7 @@ private void loadCalendar(final String srvTimeZone, final String srvSystemTimeZo throws SQLException { if (options.useLegacyDatetimeCode) { // legacy use client timezone - timeZone = Calendar.getInstance().getTimeZone(); + timeZone = null; } else { // use server time zone String tz = options.serverTimezone; @@ -1166,6 +1166,7 @@ private void loadCalendar(final String srvTimeZone, final String srvSystemTimeZo try { timeZone = Utils.getTimeZone(tz); + if (timeZone.equals(TimeZone.getDefault())) timeZone = null; } catch (SQLException e) { if (options.serverTimezone != null) { throw exceptionFactory.create( diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java index d875d79fc..020126887 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java @@ -1943,7 +1943,8 @@ private void cmdPrologue() throws SQLException { if (this.options.ensureSocketState) { // ensure that the socket buffer is empty before issuing new command. // (this doesn't concern pipelining commands). - // If data is present in socket, an error will be raised, throwing the content of socket data to permit + // If data is present in socket, an error will be raised, throwing the content of socket data + // to permit // identification of error. try { int avail = this.reader.getInputStream().available(); diff --git a/src/test/java/org/mariadb/jdbc/CancelTest.java b/src/test/java/org/mariadb/jdbc/CancelTest.java index 838f78b57..dc06e5bb0 100644 --- a/src/test/java/org/mariadb/jdbc/CancelTest.java +++ b/src/test/java/org/mariadb/jdbc/CancelTest.java @@ -69,7 +69,8 @@ public class CancelTest extends BaseTest { @Before public void cancelSupported() throws SQLException { requireMinimumVersion(5, 0); - Assume.assumeTrue(System.getenv("SKYSQL") == null && System.getenv("MAXSCALE_TEST_DISABLE") == null); + Assume.assumeTrue( + System.getenv("SKYSQL") == null && System.getenv("MAXSCALE_TEST_DISABLE") == null); } @Test diff --git a/src/test/java/org/mariadb/jdbc/DateTest.java b/src/test/java/org/mariadb/jdbc/DateTest.java index 66b544295..e76fa3b06 100644 --- a/src/test/java/org/mariadb/jdbc/DateTest.java +++ b/src/test/java/org/mariadb/jdbc/DateTest.java @@ -202,7 +202,7 @@ public void yearTest() throws SQLException { createTable("yeartest", "y1 year, y2 year(2)"); sharedConnection .createStatement() - .execute("insert into yeartest values (null, null), (1901, 70), (0, 0), " + "(2155, 69)"); + .execute("insert into yeartest values (null, null), (1901, 70), (0, 0), (2155, 69)"); Statement stmt = sharedConnection.createStatement(); ResultSet rs = stmt.executeQuery("select * from yeartest"); @@ -412,12 +412,9 @@ private void checkResult( assertEquals(rs.getTimestamp(1), currentTimeStamp); assertEquals(rs.getTimestamp(2), currentTimeStamp); assertEquals(rs.getTimestamp(3), new Timestamp(cal.getTimeInMillis())); - - assertEquals(rs.getDate(1), new Date(currentTimeStamp.getTime())); - assertEquals(rs.getDate(2), new Date(currentTimeStamp.getTime())); + assertEquals(rs.getDate(1).toString(), new Date(currentTimeStamp.getTime()).toString()); + assertEquals(rs.getDate(2).toString(), new Date(currentTimeStamp.getTime()).toString()); assertEquals(rs.getDate(3), dateWithoutTime); - assertEquals(rs.getTime(1), new Time(currentTimeStamp.getTime())); - assertEquals(rs.getTime(2), new Time(currentTimeStamp.getTime())); try { rs.getTime(3); fail(); diff --git a/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java b/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java index 0ccdf3467..5b9d4cce0 100644 --- a/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java +++ b/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java @@ -89,7 +89,6 @@ public void testLocalInfileInputStream() throws SQLException { InputStream inputStream = new ByteArrayInputStream(builder.getBytes()); ((MariaDbStatement) st).setLocalInfileInputStream(inputStream); - st.executeUpdate( "LOAD DATA LOCAL INFILE 'dummy.tsv' INTO TABLE LocalInfileInputStreamTest (id, test)"); diff --git a/src/test/java/org/mariadb/jdbc/LocalTimeTest.java b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java index d26fb875a..1b7a3a220 100644 --- a/src/test/java/org/mariadb/jdbc/LocalTimeTest.java +++ b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java @@ -135,7 +135,7 @@ public void localDateTimeTest() throws SQLException { Timestamp.valueOf("2000-12-31 01:02:03").getTime() + 123, rs.getTimestamp(1).getTime()); assertEquals(LocalTime.of(1, 2, 3, 123456000), rs.getObject(1, LocalTime.class)); assertEquals("01:02:03", rs.getTime(1).toString()); - assertEquals(Timestamp.valueOf("2000-12-31 01:02:03").getTime() + 123, rs.getTime(1).getTime()); + assertEquals(Timestamp.valueOf("1970-01-01 01:02:03").getTime() + 123, rs.getTime(1).getTime()); assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(1, LocalDate.class)); assertEquals("2000-12-31 02:03:04.0", rs.getString(2)); @@ -144,7 +144,7 @@ public void localDateTimeTest() throws SQLException { assertEquals(Timestamp.valueOf("2000-12-31 02:03:04").getTime(), rs.getTimestamp(2).getTime()); assertEquals(LocalTime.of(2, 3, 4, 0), rs.getObject(2, LocalTime.class)); assertEquals(Time.valueOf("02:03:04").toString(), rs.getTime(2).toString()); - assertEquals(Timestamp.valueOf("2000-12-31 02:03:04").getTime(), rs.getTime(2).getTime()); + assertEquals(Timestamp.valueOf("1970-01-01 02:03:04").getTime(), rs.getTime(2).getTime()); assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(2, LocalDate.class)); assertTrue(rs.next()); @@ -158,7 +158,7 @@ public void localDateTimeTest() throws SQLException { Timestamp.valueOf("1000-01-01 15:14:13").getTime() + 12, rs.getTimestamp(1).getTime()); assertEquals(LocalTime.of(15, 14, 13, 12340000), rs.getObject(1, LocalTime.class)); assertEquals(Time.valueOf("15:14:13").toString(), rs.getTime(1).toString()); - assertEquals(Timestamp.valueOf("1000-01-01 15:14:13.01234").getTime(), rs.getTime(1).getTime()); + assertEquals(Timestamp.valueOf("1970-01-01 15:14:13.01234").getTime(), rs.getTime(1).getTime()); assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(1, LocalDate.class)); assertEquals("1000-01-01 16:15:14.0", rs.getString(2)); @@ -168,7 +168,7 @@ public void localDateTimeTest() throws SQLException { assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").getTime(), rs.getTimestamp(2).getTime()); assertEquals(LocalTime.of(16, 15, 14, 0), rs.getObject(2, LocalTime.class)); assertEquals(Time.valueOf("16:15:14").toString(), rs.getTime(2).toString()); - assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").getTime(), rs.getTime(2).getTime()); + assertEquals(Timestamp.valueOf("1970-01-01 16:15:14").getTime(), rs.getTime(2).getTime()); assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(2, LocalDate.class)); assertTrue(rs.next()); @@ -180,7 +180,7 @@ public void localDateTimeTest() throws SQLException { assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").getTime(), rs.getTimestamp(1).getTime()); assertEquals(LocalTime.of(5, 4, 3, 0), rs.getObject(1, LocalTime.class)); assertEquals(Time.valueOf("05:04:03").toString(), rs.getTime(1).toString()); - assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").getTime(), rs.getTime(1).getTime()); + assertEquals(Timestamp.valueOf("1970-01-01 05:04:03").getTime(), rs.getTime(1).getTime()); assertEquals(LocalDate.of(9999, 12, 31), rs.getObject(1, LocalDate.class)); assertEquals("9999-12-31 06:05:04.0", rs.getString(2)); @@ -190,7 +190,7 @@ public void localDateTimeTest() throws SQLException { assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").getTime(), rs.getTimestamp(2).getTime()); assertEquals(LocalTime.of(6, 5, 4, 0), rs.getObject(2, LocalTime.class)); assertEquals(Time.valueOf("06:05:04").toString(), rs.getTime(2).toString()); - assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").getTime(), rs.getTime(2).getTime()); + assertEquals(Timestamp.valueOf("1970-01-01 06:05:04").getTime(), rs.getTime(2).getTime()); assertEquals(LocalDate.of(9999, 12, 31), rs.getObject(1, LocalDate.class)); assertFalse(rs.next()); diff --git a/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java b/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java index 5d40f3285..e687a9466 100644 --- a/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java +++ b/src/test/java/org/mariadb/jdbc/TimezoneDaylightSavingTimeTest.java @@ -517,8 +517,8 @@ private void testDayLight(boolean legacy) throws SQLException { assertTrue(rs1.getBoolean(3)); assertTrue(rs1.getBoolean(4)); - checkResult(legacy, true, connection); - checkResult(legacy, false, connection); + checkResult(legacy, false); + checkResult(legacy, true); } } @@ -527,236 +527,247 @@ private void testDayLight(boolean legacy) throws SQLException { * * @param legacy is in legacy mode * @param binaryProtocol binary protocol - * @param connection connection * @return current resultset * @throws SQLException if connection error occur. */ - public ResultSet checkResult(boolean legacy, boolean binaryProtocol, Connection connection) - throws SQLException { - ResultSet rs; - PreparedStatement pst; - if (binaryProtocol) { - pst = - connection.prepareStatement( - "SELECT * from daylight where 1 = ?", - ResultSet.TYPE_SCROLL_INSENSITIVE, - ResultSet.CONCUR_READ_ONLY); - } else { - MariaDbConnection mariaDbConnection = (MariaDbConnection) connection; - ExceptionFactory exceptionFactory = - ExceptionFactory.of((int) mariaDbConnection.getServerThreadId(), new Options()); - pst = - new ClientSidePreparedStatement( - mariaDbConnection, - "SELECT * from daylight where 1 = ?", - ResultSet.TYPE_SCROLL_INSENSITIVE, - ResultSet.CONCUR_READ_ONLY, - Statement.NO_GENERATED_KEYS, - exceptionFactory); - } - pst.setInt(1, 1); - rs = pst.executeQuery(); - - assertTrue(rs.next()); - - // test timestamp(6) - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getTimestamp(2))); - assertEquals( - "2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(2, Timestamp.class))); - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(2, Time.class))); - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(2, Date.class))); - assertEquals( - "2015-03-29T01:45:00.012+0100", - formatter.format(rs.getObject(2, Calendar.class).getTime())); - assertEquals( - "2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(2, java.util.Date.class))); - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getTime(2))); - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getDate(2))); - - // test time(6) - assertEquals("1970-01-01T01:45:00.000+0100", formatter.format(rs.getTimestamp(3))); - assertEquals( - "1970-01-01T01:45:00.000+0100", formatter.format(rs.getObject(3, Timestamp.class))); - assertEquals("1970-01-01T01:45:00.000+0100", formatter.format(rs.getObject(3, Time.class))); - assertEquals( - "1970-01-01T01:45:00.000+0100", - formatter.format(rs.getObject(3, Calendar.class).getTime())); - assertEquals( - "1970-01-01T01:45:00.000+0100", formatter.format(rs.getObject(3, java.util.Date.class))); - try { - formatter.format(rs.getObject(3, Date.class)); - fail(); - } catch (SQLException e) { - // expected exception - } - assertEquals("1970-01-01T01:45:00.000+0100", formatter.format(rs.getTime(3))); - assertEquals(2700000, rs.getTime(3).getTime()); - try { - formatter.format(rs.getDate(3)); - fail(); - } catch (SQLException e) { - // expected exception - } + public ResultSet checkResult(boolean legacy, boolean binaryProtocol) throws SQLException { + try (Connection connection = + setConnection( + "&useServerPrepStmts=" + + binaryProtocol + + "&useLegacyDatetimeCode=" + + legacy + + "&serverTimezone=Canada/Atlantic&sessionVariables=time_zone='Canada/Atlantic'")) { + ResultSet rs; + PreparedStatement pst; + if (binaryProtocol) { + pst = + connection.prepareStatement( + "SELECT * from daylight where 1 = ?", + ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); + } else { + MariaDbConnection mariaDbConnection = (MariaDbConnection) connection; + ExceptionFactory exceptionFactory = + ExceptionFactory.of((int) mariaDbConnection.getServerThreadId(), new Options()); + pst = + new ClientSidePreparedStatement( + mariaDbConnection, + "SELECT * from daylight where 1 = ?", + ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY, + Statement.NO_GENERATED_KEYS, + exceptionFactory); + } + pst.setInt(1, 1); + rs = pst.executeQuery(); - // test datetime(6) - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getTimestamp(4))); - assertEquals( - "2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(4, Timestamp.class))); - assertEquals( - "2015-03-29T01:45:00.012+0100", - formatter.format(rs.getObject(4, Calendar.class).getTime())); - assertEquals( - "2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(4, java.util.Date.class))); - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(4, Time.class))); - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(4, Date.class))); - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getTime(4))); - assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getDate(4))); - - // test date(6) - assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getTimestamp(5))); - assertEquals( - "2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(5, Timestamp.class))); - try { - formatter.format(rs.getObject(5, Time.class)); - fail(); - } catch (SQLException e) { - // expected exception - } - assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(5, Date.class))); - try { - formatter.format(rs.getTime(5)); - fail(); - } catch (SQLException e) { - // expected exception - } - assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getDate(5))); - assertEquals(new Date(2015 - 1900, 2, 29), rs.getDate(5)); - assertEquals(rs.getString(5), "2015-03-29"); + assertTrue(rs.next()); - assertTrue(rs.next()); - // test timestamp(6) - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getTimestamp(2))); - assertEquals( - "2015-03-29T03:15:00.012+0200", formatter.format(rs.getObject(2, Timestamp.class))); - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getObject(2, Time.class))); - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getObject(2, Date.class))); - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getTime(2))); - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getDate(2))); - - // test time(6) - assertEquals("1970-01-01T03:15:00.000+0100", formatter.format(rs.getTimestamp(3))); - assertEquals( - "1970-01-01T03:15:00.000+0100", formatter.format(rs.getObject(3, Timestamp.class))); - assertEquals("1970-01-01T03:15:00.000+0100", formatter.format(rs.getObject(3, Time.class))); - try { - formatter.format(rs.getObject(3, Date.class)); - fail(); - } catch (SQLException e) { - // expected exception - } - assertEquals("1970-01-01T03:15:00.000+0100", formatter.format(rs.getTime(3))); - assertEquals(8100000, rs.getTime(3).getTime()); - try { - formatter.format(rs.getDate(3)); - fail(); - } catch (SQLException e) { - // expected exception - } + // test timestamp(6) + assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getTimestamp(2))); + assertEquals( + "2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(2, Timestamp.class))); + assertEquals("1970-01-01T01:45:00.012+0100", formatter.format(rs.getObject(2, Time.class))); + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(2, Date.class))); + assertEquals( + "2015-03-29T01:45:00.012+0100", + formatter.format(rs.getObject(2, Calendar.class).getTime())); + assertEquals( + "2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(2, java.util.Date.class))); + assertEquals("1970-01-01T01:45:00.012+0100", formatter.format(rs.getTime(2))); + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getDate(2))); - // test datetime(6) - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getTimestamp(4))); - assertEquals( - "2015-03-29T03:15:00.012+0200", formatter.format(rs.getObject(4, Timestamp.class))); - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getObject(4, Time.class))); - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getObject(4, Date.class))); - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getTime(4))); - assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getDate(4))); - - // test date(6) - assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getTimestamp(5))); - assertEquals( - "2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(5, Timestamp.class))); - try { - formatter.format(rs.getObject(5, Time.class)); - } catch (SQLException e) { - // expected exception - } - assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(5, Date.class))); - try { - formatter.format(rs.getTime(5)); - } catch (SQLException e) { - // expected exception - } - assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getDate(5))); - assertEquals(new Date(2015 - 1900, 2, 29), rs.getDate(5)); - assertEquals(rs.getString(5), "2015-03-29"); - - assertTrue(rs.next()); - // test timestamp(6) - for (int i = 2; i < 6; i++) { - assertNull(rs.getTimestamp(i)); - assertNull(rs.getTime(i)); - assertNull(rs.getDate(i)); - assertNull(rs.getObject(i, Timestamp.class)); - assertNull(rs.getObject(i, Time.class)); - assertNull(rs.getObject(i, Date.class)); - assertNull(rs.getObject(i, Calendar.class)); - assertNull(rs.getObject(i, java.util.Date.class)); - } + // test time(6) + assertEquals("1970-01-01T01:45:00.000+0100", formatter.format(rs.getTimestamp(3))); + assertEquals( + "1970-01-01T01:45:00.000+0100", formatter.format(rs.getObject(3, Timestamp.class))); + assertEquals("1970-01-01T01:45:00.000+0100", formatter.format(rs.getObject(3, Time.class))); + assertEquals( + "1970-01-01T01:45:00.000+0100", + formatter.format(rs.getObject(3, Calendar.class).getTime())); + try { + formatter.format(rs.getObject(3, java.util.Date.class)); + fail(); + } catch (SQLException e) { + // expected exception + } - rs.first(); + try { + formatter.format(rs.getObject(3, Date.class)); + fail(); + } catch (SQLException e) { + // expected exception + } + assertEquals("1970-01-01T01:45:00.000+0100", formatter.format(rs.getTime(3))); + assertEquals(2700000, rs.getTime(3).getTime()); + try { + formatter.format(rs.getDate(3)); + fail(); + } catch (SQLException e) { + // expected exception + } - // additional tests for java 8 objects - assertEquals("2015-03-29T01:45:00.012340", rs.getTimestamp(2).toLocalDateTime().toString()); - assertEquals("2015-03-29T01:45:00.012340", rs.getObject(2, LocalDateTime.class).toString()); - if (legacy) { + // test datetime(6) + assertEquals("2015-03-29T01:45:00.012+0100", formatter.format(rs.getTimestamp(4))); assertEquals( - "2015-03-29T01:45:00.012340+01:00[Europe/Paris]", - rs.getObject(2, ZonedDateTime.class).toString()); + "2015-03-29T01:45:00.012+0100", formatter.format(rs.getObject(4, Timestamp.class))); assertEquals( - "2015-03-29T01:45:00.012340+01:00", rs.getObject(2, OffsetDateTime.class).toString()); - } else { + "2015-03-29T01:45:00.012+0100", + formatter.format(rs.getObject(4, Calendar.class).getTime())); assertEquals( - "2015-03-28T21:45:00.012340-03:00[Canada/Atlantic]", - rs.getObject(2, ZonedDateTime.class).toString()); + "2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(4, java.util.Date.class))); + assertEquals("1970-01-01T01:45:00.012+0100", formatter.format(rs.getObject(4, Time.class))); + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(4, Date.class))); + assertEquals("1970-01-01T01:45:00.012+0100", formatter.format(rs.getTime(4))); + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getDate(4))); + + // test date(6) + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getTimestamp(5))); assertEquals( - "2015-03-28T21:45:00.012340-03:00", rs.getObject(2, OffsetDateTime.class).toString()); - } - assertEquals("01:45:00.012340", rs.getObject(2, LocalTime.class).toString()); - assertEquals("2015-03-29", rs.getObject(2, LocalDate.class).toString()); - - assertTrue(rs.next()); - // additional tests for java 8 objects - assertEquals("2015-03-29T03:15:00.012340", rs.getTimestamp(2).toLocalDateTime().toString()); - assertEquals("2015-03-29T03:15:00.012340", rs.getObject(2, LocalDateTime.class).toString()); - if (legacy) { + "2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(5, Timestamp.class))); + try { + formatter.format(rs.getObject(5, Time.class)); + fail(); + } catch (SQLException e) { + // expected exception + } + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(5, Date.class))); + try { + formatter.format(rs.getTime(5)); + fail(); + } catch (SQLException e) { + // expected exception + } + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getDate(5))); + assertEquals(new Date(2015 - 1900, 2, 29), rs.getDate(5)); + assertEquals(rs.getString(5), "2015-03-29"); + + assertTrue(rs.next()); + // test timestamp(6) + assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getTimestamp(2))); assertEquals( - "2015-03-29T03:15:00.012340+02:00[Europe/Paris]", - rs.getObject(2, ZonedDateTime.class).toString()); + "2015-03-29T03:15:00.012+0200", formatter.format(rs.getObject(2, Timestamp.class))); + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getDate(2))); + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(2, Date.class))); + assertEquals("1970-01-01T03:15:00.012+0100", formatter.format(rs.getTime(2))); + assertEquals("1970-01-01T03:15:00.012+0100", formatter.format(rs.getObject(2, Time.class))); + + // test time(6) + assertEquals("1970-01-01T03:15:00.000+0100", formatter.format(rs.getTimestamp(3))); assertEquals( - "2015-03-29T03:15:00.012340+02:00", rs.getObject(2, OffsetDateTime.class).toString()); - } else { + "1970-01-01T03:15:00.000+0100", formatter.format(rs.getObject(3, Timestamp.class))); + assertEquals("1970-01-01T03:15:00.000+0100", formatter.format(rs.getObject(3, Time.class))); + try { + formatter.format(rs.getObject(3, Date.class)); + fail(); + } catch (SQLException e) { + // expected exception + } + assertEquals("1970-01-01T03:15:00.000+0100", formatter.format(rs.getTime(3))); + assertEquals(8100000, rs.getTime(3).getTime()); + try { + formatter.format(rs.getDate(3)); + fail(); + } catch (SQLException e) { + // expected exception + } + + // test datetime(6) + assertEquals("2015-03-29T03:15:00.012+0200", formatter.format(rs.getTimestamp(4))); assertEquals( - "2015-03-28T22:15:00.012340-03:00[Canada/Atlantic]", - rs.getObject(2, ZonedDateTime.class).toString()); + "2015-03-29T03:15:00.012+0200", formatter.format(rs.getObject(4, Timestamp.class))); + assertEquals("1970-01-01T03:15:00.012+0100", formatter.format(rs.getObject(4, Time.class))); + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(4, Date.class))); + assertEquals("1970-01-01T03:15:00.012+0100", formatter.format(rs.getTime(4))); + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getDate(4))); + + // test date(6) + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getTimestamp(5))); assertEquals( - "2015-03-28T22:15:00.012340-03:00", rs.getObject(2, OffsetDateTime.class).toString()); - } - assertEquals("03:15:00.012340", rs.getObject(2, LocalTime.class).toString()); - assertEquals("2015-03-29", rs.getObject(2, LocalDate.class).toString()); - - assertTrue(rs.next()); - // test timestamp(6) - for (int i = 2; i < 6; i++) { - assertNull(rs.getObject(i, LocalDateTime.class)); - assertNull(rs.getObject(i, OffsetDateTime.class)); - assertNull(rs.getObject(i, ZonedDateTime.class)); - assertNull(rs.getObject(i, LocalDate.class)); - assertNull(rs.getObject(i, LocalTime.class)); - assertNull(rs.getObject(i, OffsetTime.class)); - } + "2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(5, Timestamp.class))); + try { + formatter.format(rs.getObject(5, Time.class)); + } catch (SQLException e) { + // expected exception + } + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getObject(5, Date.class))); + try { + formatter.format(rs.getTime(5)); + } catch (SQLException e) { + // expected exception + } + assertEquals("2015-03-29T00:00:00.000+0100", formatter.format(rs.getDate(5))); + assertEquals(new Date(2015 - 1900, 2, 29), rs.getDate(5)); + assertEquals(rs.getString(5), "2015-03-29"); + + assertTrue(rs.next()); + // test timestamp(6) + for (int i = 2; i < 6; i++) { + assertNull(rs.getTimestamp(i)); + assertNull(rs.getTime(i)); + assertNull(rs.getDate(i)); + assertNull(rs.getObject(i, Timestamp.class)); + assertNull(rs.getObject(i, Time.class)); + assertNull(rs.getObject(i, Date.class)); + assertNull(rs.getObject(i, Calendar.class)); + assertNull(rs.getObject(i, java.util.Date.class)); + } + + rs.first(); + + // additional tests for java 8 objects + assertEquals("2015-03-29T01:45:00.012340", rs.getTimestamp(2).toLocalDateTime().toString()); + assertEquals("2015-03-29T01:45:00.012340", rs.getObject(2, LocalDateTime.class).toString()); + if (legacy) { + assertEquals( + "2015-03-29T01:45:00.012340+01:00[Europe/Paris]", + rs.getObject(2, ZonedDateTime.class).toString()); + assertEquals( + "2015-03-29T01:45:00.012340+01:00", rs.getObject(2, OffsetDateTime.class).toString()); + } else { + assertEquals( + "2015-03-28T21:45:00.012340-03:00[Canada/Atlantic]", + rs.getObject(2, ZonedDateTime.class).toString()); + assertEquals( + "2015-03-28T21:45:00.012340-03:00", rs.getObject(2, OffsetDateTime.class).toString()); + } + assertEquals("01:45:00.012340", rs.getObject(2, LocalTime.class).toString()); + assertEquals("2015-03-29", rs.getObject(2, LocalDate.class).toString()); - return rs; + assertTrue(rs.next()); + // additional tests for java 8 objects + assertEquals("2015-03-29T03:15:00.012340", rs.getTimestamp(2).toLocalDateTime().toString()); + assertEquals("2015-03-29T03:15:00.012340", rs.getObject(2, LocalDateTime.class).toString()); + if (legacy) { + assertEquals( + "2015-03-29T03:15:00.012340+02:00[Europe/Paris]", + rs.getObject(2, ZonedDateTime.class).toString()); + assertEquals( + "2015-03-29T03:15:00.012340+02:00", rs.getObject(2, OffsetDateTime.class).toString()); + } else { + assertEquals( + "2015-03-28T22:15:00.012340-03:00[Canada/Atlantic]", + rs.getObject(2, ZonedDateTime.class).toString()); + assertEquals( + "2015-03-28T22:15:00.012340-03:00", rs.getObject(2, OffsetDateTime.class).toString()); + } + assertEquals("03:15:00.012340", rs.getObject(2, LocalTime.class).toString()); + assertEquals("2015-03-29", rs.getObject(2, LocalDate.class).toString()); + + assertTrue(rs.next()); + // test timestamp(6) + for (int i = 2; i < 6; i++) { + assertNull(rs.getObject(i, LocalDateTime.class)); + assertNull(rs.getObject(i, OffsetDateTime.class)); + assertNull(rs.getObject(i, ZonedDateTime.class)); + assertNull(rs.getObject(i, LocalDate.class)); + assertNull(rs.getObject(i, LocalTime.class)); + assertNull(rs.getObject(i, OffsetTime.class)); + } + + return rs; + } } @Test diff --git a/src/test/java/org/mariadb/jdbc/TimezoneExplicitCalendarTest.java b/src/test/java/org/mariadb/jdbc/TimezoneExplicitCalendarTest.java index 316a335d6..d31dc56d1 100644 --- a/src/test/java/org/mariadb/jdbc/TimezoneExplicitCalendarTest.java +++ b/src/test/java/org/mariadb/jdbc/TimezoneExplicitCalendarTest.java @@ -92,6 +92,7 @@ public void testDateWithExplicitTimeZone() throws SQLException { ResultSet rs = st.executeQuery(); assertTrue(rs.next()); Calendar readCalendar = Calendar.getInstance(EUROPE_PARIS); + Date dd = rs.getDate(1, readCalendar); assertEquals(rs.getDate(1, readCalendar), epochInGmt); } } diff --git a/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java b/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java index be26d2287..fb0898d43 100644 --- a/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java +++ b/src/test/java/org/mariadb/jdbc/failover/MonoServerFailoverTest.java @@ -163,7 +163,8 @@ public void checkAutoReconnectDeconnection() throws Throwable { */ @Test public void isValidConnectionThatIsKilledExternally() throws Throwable { - Assume.assumeTrue(System.getenv("SKYSQL") == null && System.getenv("MAXSCALE_TEST_DISABLE") == null); + Assume.assumeTrue( + System.getenv("SKYSQL") == null && System.getenv("MAXSCALE_TEST_DISABLE") == null); try (Connection connection = getNewConnection()) { connection.setCatalog("mysql"); Protocol protocol = getProtocolFromConnection(connection); From ca8365ab8a02f867a3882af416ee218af0311b9c Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 24 Sep 2020 15:00:05 +0200 Subject: [PATCH 30/30] bump 2.7.0 version --- README.md | 4 ++-- pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ab3da3fa7..02b4901fd 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ or maven : org.mariadb.jdbc mariadb-java-client - 2.6.2 + 2.7.0 ``` @@ -46,7 +46,7 @@ Development snapshot are available on sonatype nexus repository org.mariadb.jdbc mariadb-java-client - 2.6.3-SNAPSHOT + 3.0.0-SNAPSHOT ``` diff --git a/pom.xml b/pom.xml index 1fc53e3e9..327aa3322 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ mariadb-java-client jar mariadb-java-client - 2.6.2 + 2.7.0 JDBC driver for MariaDB and MySQL https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/