From 1003c60d4b7060a0befded7d42839dc77b437b21 Mon Sep 17 00:00:00 2001 From: kolzeq Date: Wed, 7 Apr 2021 19:45:50 +0200 Subject: [PATCH] [misc] test coverage addition --- .../mariadb/jdbc/ClientPreparedStatement.java | 13 +- .../java/org/mariadb/jdbc/Configuration.java | 219 ++++++++++++++++-- .../java/org/mariadb/jdbc/Connection.java | 13 +- .../org/mariadb/jdbc/FunctionStatement.java | 3 +- .../java/org/mariadb/jdbc/HostAddress.java | 15 -- .../java/org/mariadb/jdbc/MariaDbClob.java | 9 +- .../org/mariadb/jdbc/MariaDbDataSource.java | 18 +- .../org/mariadb/jdbc/ParameterMetaData.java | 6 +- .../org/mariadb/jdbc/ProcedureStatement.java | 4 +- .../mariadb/jdbc/ServerPreparedStatement.java | 40 +--- src/main/java/org/mariadb/jdbc/Statement.java | 38 +-- .../java/org/mariadb/jdbc/client/Client.java | 2 + .../org/mariadb/jdbc/client/ClientImpl.java | 12 +- .../jdbc/client/MultiPrimaryClient.java | 5 + src/main/java/org/mariadb/jdbc/pool/Pool.java | 47 +--- .../java/org/mariadb/jdbc/pool/Pools.java | 16 +- src/test/java/org/mariadb/jdbc/Common.java | 8 +- .../mariadb/jdbc/integration/BlobTest.java | 27 ++- .../mariadb/jdbc/integration/ClobTest.java | 126 +++++++--- .../jdbc/integration/ConnectionTest.java | 2 +- .../jdbc/integration/FunctionTest.java | 32 +++ .../jdbc/integration/MultiQueriesTest.java | 23 ++ .../integration/ParameterMetaDataTest.java | 14 +- .../jdbc/integration/PoolDataSourceTest.java | 71 +++++- .../integration/PooledConnectionTest.java | 4 +- .../PreparedStatementMetadataTest.java | 2 + .../integration/PreparedStatementTest.java | 172 +++++++++++++- .../jdbc/integration/ProcedureTest.java | 33 +++ .../jdbc/integration/StatementTest.java | 58 ++++- .../jdbc/integration/codec/ClobCodecTest.java | 4 +- .../jdbc/unit/util/ConfigurationTest.java | 78 ++++++- .../jdbc/unit/util/constant/HaModeTest.java | 2 + 32 files changed, 901 insertions(+), 215 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/ClientPreparedStatement.java b/src/main/java/org/mariadb/jdbc/ClientPreparedStatement.java index 7780d24c2..35ede32f7 100644 --- a/src/main/java/org/mariadb/jdbc/ClientPreparedStatement.java +++ b/src/main/java/org/mariadb/jdbc/ClientPreparedStatement.java @@ -82,6 +82,7 @@ private List executeInternalPreparedBatch() throws SQLException { checkNotClosed(); long serverCapabilities = con.getContext().getServerCapabilities(); if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS + && batchParameters.size() > 1 && (serverCapabilities & Capabilities.MARIADB_CLIENT_STMT_BULK_OPERATIONS) > 0 && con.getContext().getConf().useBulkStmts()) { return executeBatchBulk(); @@ -406,9 +407,15 @@ public int[] executeBatch() throws SQLException { try { List res = executeInternalPreparedBatch(); results = res; - int[] updates = new int[res.size()]; - for (int i = 0; i < res.size(); i++) { - updates[i] = (int) ((OkPacket) res.get(i)).getAffectedRows(); + int[] updates = new int[batchParameters.size()]; + if (res.size() != batchParameters.size()) { + for (int i = 0; i < batchParameters.size(); i++) { + updates[i] = Statement.SUCCESS_NO_INFO; + } + } else { + for (int i = 0; i < Math.min(res.size(), batchParameters.size()); i++) { + updates[i] = (int) ((OkPacket) res.get(i)).getAffectedRows(); + } } currResult = results.remove(0); return updates; diff --git a/src/main/java/org/mariadb/jdbc/Configuration.java b/src/main/java/org/mariadb/jdbc/Configuration.java index 99e258962..98b57cc56 100644 --- a/src/main/java/org/mariadb/jdbc/Configuration.java +++ b/src/main/java/org/mariadb/jdbc/Configuration.java @@ -62,7 +62,7 @@ * jdbc:mariadb://address=(type=master)(host=master1),address=(port=3307)(type=slave)(host=slave1)/database?user=greg&password=pass} *
*/ -public class Configuration implements Cloneable { +public class Configuration { private static final Pattern URL_PARAMETER = Pattern.compile("(\\/([^\\?]*))?(\\?(.+))*", Pattern.DOTALL); @@ -155,6 +155,132 @@ public class Configuration implements Cloneable { private Configuration() {} + private Configuration( + String user, + String password, + String database, + List addresses, + HaMode haMode, + Properties nonMappedOptions, + String timezone, + boolean autocommit, + TransactionIsolation transactionIsolation, + int defaultFetchSize, + int maxQuerySizeToLog, + boolean pinGlobalTxToPhysicalConnection, + String geometryDefaultType, + String socketFactory, + Integer connectTimeout, + String pipe, + String localSocket, + boolean tcpKeepAlive, + boolean tcpAbortiveClose, + String localSocketAddress, + int socketTimeout, + boolean useReadAheadInput, + String tlsSocketType, + SslMode sslMode, + String serverSslCert, + String keyStore, + String keyStorePassword, + String keyStoreType, + String enabledSslCipherSuites, + String enabledSslProtocolSuites, + boolean allowMultiQueries, + boolean allowLocalInfile, + boolean useCompression, + boolean useAffectedRows, + boolean useBulkStmts, + boolean cachePrepStmts, + int prepStmtCacheSize, + boolean useServerPrepStmts, + CredentialPlugin credentialType, + String sessionVariables, + String connectionAttributes, + String servicePrincipalName, + boolean blankTableNameMeta, + boolean tinyInt1isBit, + boolean yearIsDateType, + boolean dumpQueriesOnException, + boolean includeInnodbStatusInDeadlockExceptions, + boolean includeThreadDumpInDeadlockExceptions, + int retriesAllDown, + String galeraAllowedState, + boolean transactionReplay, + boolean pool, + String poolName, + int maxPoolSize, + int minPoolSize, + Integer maxIdleTime, + boolean registerJmxPool, + int poolValidMinDelay, + boolean useResetConnection, + String serverRsaPublicKeyFile, + boolean allowPublicKeyRetrieval) { + this.user = user; + this.password = password; + this.database = database; + this.addresses = addresses; + this.haMode = haMode; + this.nonMappedOptions = nonMappedOptions; + this.timezone = timezone; + this.autocommit = autocommit; + this.transactionIsolation = transactionIsolation; + this.defaultFetchSize = defaultFetchSize; + this.maxQuerySizeToLog = maxQuerySizeToLog; + this.pinGlobalTxToPhysicalConnection = pinGlobalTxToPhysicalConnection; + this.geometryDefaultType = geometryDefaultType; + this.socketFactory = socketFactory; + this.connectTimeout = connectTimeout; + this.pipe = pipe; + this.localSocket = localSocket; + this.tcpKeepAlive = tcpKeepAlive; + this.tcpAbortiveClose = tcpAbortiveClose; + this.localSocketAddress = localSocketAddress; + this.socketTimeout = socketTimeout; + this.useReadAheadInput = useReadAheadInput; + this.tlsSocketType = tlsSocketType; + this.sslMode = sslMode; + this.serverSslCert = serverSslCert; + this.keyStore = keyStore; + this.keyStorePassword = keyStorePassword; + this.keyStoreType = keyStoreType; + this.enabledSslCipherSuites = enabledSslCipherSuites; + this.enabledSslProtocolSuites = enabledSslProtocolSuites; + this.allowMultiQueries = allowMultiQueries; + this.allowLocalInfile = allowLocalInfile; + this.useCompression = useCompression; + this.useAffectedRows = useAffectedRows; + this.useBulkStmts = useBulkStmts; + this.cachePrepStmts = cachePrepStmts; + this.prepStmtCacheSize = prepStmtCacheSize; + this.useServerPrepStmts = useServerPrepStmts; + this.credentialType = credentialType; + this.sessionVariables = sessionVariables; + this.connectionAttributes = connectionAttributes; + this.servicePrincipalName = servicePrincipalName; + this.blankTableNameMeta = blankTableNameMeta; + this.tinyInt1isBit = tinyInt1isBit; + this.yearIsDateType = yearIsDateType; + this.dumpQueriesOnException = dumpQueriesOnException; + this.includeInnodbStatusInDeadlockExceptions = includeInnodbStatusInDeadlockExceptions; + this.includeThreadDumpInDeadlockExceptions = includeThreadDumpInDeadlockExceptions; + this.retriesAllDown = retriesAllDown; + this.galeraAllowedState = galeraAllowedState; + this.transactionReplay = transactionReplay; + this.pool = pool; + this.poolName = poolName; + this.maxPoolSize = maxPoolSize; + this.minPoolSize = minPoolSize; + this.maxIdleTime = maxIdleTime; + this.registerJmxPool = registerJmxPool; + this.poolValidMinDelay = poolValidMinDelay; + this.useResetConnection = useResetConnection; + this.serverRsaPublicKeyFile = serverRsaPublicKeyFile; + this.allowPublicKeyRetrieval = allowPublicKeyRetrieval; + this.initialUrl = buildUrl(this); + } + private Configuration( String database, List addresses, @@ -299,6 +425,18 @@ private Configuration( if (keyStorePassword != null) this.keyStorePassword = keyStorePassword; if (keyStoreType != null) this.keyStoreType = keyStoreType; + // ************************************************************* + // host primary check + // ************************************************************* + boolean first = true; + for (HostAddress host : addresses) { + boolean primary = haMode != HaMode.REPLICATION || first; + if (host.primary == null) { + host.primary = primary; + } + first = false; + } + // ************************************************************* // option value verification // ************************************************************* @@ -320,12 +458,6 @@ private Configuration( } } - public void updateAuth(String user, String password) { - this.user = user; - this.password = password; - buildUrl(this); - } - /** * Tell if mariadb driver accept url string. (Correspond to interface * java.jdbc.Driver.acceptsURL() method) @@ -512,10 +644,69 @@ private static HaMode parseHaMode(String url, int separator) { } } - public Configuration clone(String username, String password) throws CloneNotSupportedException { - Configuration conf = (Configuration) super.clone(); - conf.updateAuth(username, password); - return conf; + public Configuration clone(String username, String password) { + return new Configuration( + username, + password, + this.database, + this.addresses, + this.haMode, + this.nonMappedOptions, + this.timezone, + this.autocommit, + this.transactionIsolation, + this.defaultFetchSize, + this.maxQuerySizeToLog, + this.pinGlobalTxToPhysicalConnection, + this.geometryDefaultType, + this.socketFactory, + this.connectTimeout, + this.pipe, + this.localSocket, + this.tcpKeepAlive, + this.tcpAbortiveClose, + this.localSocketAddress, + this.socketTimeout, + this.useReadAheadInput, + this.tlsSocketType, + this.sslMode, + this.serverSslCert, + this.keyStore, + this.keyStorePassword, + this.keyStoreType, + this.enabledSslCipherSuites, + this.enabledSslProtocolSuites, + this.allowMultiQueries, + this.allowLocalInfile, + this.useCompression, + this.useAffectedRows, + this.useBulkStmts, + this.cachePrepStmts, + this.prepStmtCacheSize, + this.useServerPrepStmts, + this.credentialType, + this.sessionVariables, + this.connectionAttributes, + this.servicePrincipalName, + this.blankTableNameMeta, + this.tinyInt1isBit, + this.yearIsDateType, + this.dumpQueriesOnException, + this.includeInnodbStatusInDeadlockExceptions, + this.includeThreadDumpInDeadlockExceptions, + this.retriesAllDown, + this.galeraAllowedState, + this.transactionReplay, + this.pool, + this.poolName, + this.maxPoolSize, + this.minPoolSize, + this.maxIdleTime, + this.registerJmxPool, + this.poolValidMinDelay, + this.useResetConnection, + this.serverRsaPublicKeyFile, + this.allowPublicKeyRetrieval); } public String database() { @@ -1062,14 +1253,12 @@ public Builder haMode(HaMode haMode) { return this; } - public Builder addresses(String host, int port) { - this._addresses = new ArrayList<>(); + public Builder addHost(String host, int port) { this._addresses.add(HostAddress.from(host, port)); return this; } - public Builder addresses(String host, int port, boolean master) { - this._addresses = new ArrayList<>(); + public Builder addHost(String host, int port, boolean master) { this._addresses.add(HostAddress.from(host, port, master)); return this; } diff --git a/src/main/java/org/mariadb/jdbc/Connection.java b/src/main/java/org/mariadb/jdbc/Connection.java index ff0f6a6c1..fcb1a2f29 100644 --- a/src/main/java/org/mariadb/jdbc/Connection.java +++ b/src/main/java/org/mariadb/jdbc/Connection.java @@ -75,8 +75,12 @@ public Connection(Configuration conf, ReentrantLock lock, Client client) throws this.exceptionFactory = client.getExceptionFactory().setConnection(this); this.client = client; Context context = this.client.getContext(); - this.canUseServerTimeout = context.getVersion().versionGreaterOrEqual(10, 1, 2); - this.canUseServerMaxRows = context.getVersion().versionGreaterOrEqual(10, 3, 0); + this.canUseServerTimeout = + context.getVersion().isMariaDBServer() + && context.getVersion().versionGreaterOrEqual(10, 1, 2); + this.canUseServerMaxRows = + context.getVersion().isMariaDBServer() + && context.getVersion().versionGreaterOrEqual(10, 3, 0); this.defaultFetchSize = context.getConf().defaultFetchSize(); } @@ -456,7 +460,6 @@ public CallableStatement prepareCall(String sql, int resultSetType, int resultSe if (isFunction) { return new FunctionStatement( this, - poolConnection, database, databaseAndProcedure, (arguments == null) ? "()" : arguments, @@ -734,8 +737,8 @@ public boolean isWrapperFor(Class iface) throws SQLException { return iface.isInstance(this); } - public HostAddress getHostAddress() { - return client.getHostAddress(); + public int getWaitTimeout() { + return client.getWaitTimeout(); } public Client getClient() { diff --git a/src/main/java/org/mariadb/jdbc/FunctionStatement.java b/src/main/java/org/mariadb/jdbc/FunctionStatement.java index 3073dc272..5250befcc 100644 --- a/src/main/java/org/mariadb/jdbc/FunctionStatement.java +++ b/src/main/java/org/mariadb/jdbc/FunctionStatement.java @@ -30,7 +30,6 @@ public class FunctionStatement extends BaseCallableStatement implements Callable public FunctionStatement( Connection con, - MariaDbPoolConnection poolConnection, String databaseName, String procedureName, String arguments, @@ -41,7 +40,7 @@ public FunctionStatement( int resultSetConcurrency) throws SQLException { super( - "SELECT " + procedureName + ((arguments == null) ? "()" : arguments), + "SELECT " + procedureName + arguments, con, lock, databaseName, diff --git a/src/main/java/org/mariadb/jdbc/HostAddress.java b/src/main/java/org/mariadb/jdbc/HostAddress.java index 55438a3be..39b1f610c 100644 --- a/src/main/java/org/mariadb/jdbc/HostAddress.java +++ b/src/main/java/org/mariadb/jdbc/HostAddress.java @@ -32,8 +32,6 @@ public class HostAddress { public String host; public int port; public Boolean primary; - public int cacheMaxAllowedPacket; - public int waitTimeout; /** * Constructor. @@ -120,19 +118,6 @@ private static int getPort(String portString) throws SQLException { } } - public int getCacheMaxAllowedPacket() { - return cacheMaxAllowedPacket; - } - - public int getWaitTimeout() { - return waitTimeout; - } - - public void setCache(int cacheMaxAllowedPacket, int waitTimeout) { - this.cacheMaxAllowedPacket = cacheMaxAllowedPacket; - this.waitTimeout = waitTimeout; - } - private static HostAddress parseParameterHostAddress(String str, HaMode haMode, boolean first) throws SQLException { String host = null; diff --git a/src/main/java/org/mariadb/jdbc/MariaDbClob.java b/src/main/java/org/mariadb/jdbc/MariaDbClob.java index 6a8165387..31f538eb7 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbClob.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbClob.java @@ -153,7 +153,7 @@ private int utf8Position(int charPosition) { pos += 2; } else if (byteValue < 0xF0) { pos += 3; - } else if (byteValue < 0xF8) { + } else { pos += 4; } } @@ -207,7 +207,7 @@ public long length() { int pos = offset; // set ASCII (<= 127 chars) - while (len < length && data[pos] >= 0) { + while (len < length && data[pos] > 0) { len++; pos++; } @@ -216,6 +216,10 @@ public long length() { while (pos < offset + length) { byte firstByte = data[pos++]; if (firstByte < 0) { + System.out.println(firstByte); + System.out.println(firstByte >> 4); + System.out.println(firstByte >> 5); + System.out.println(firstByte & 30); if (firstByte >> 5 != -2 || (firstByte & 30) == 0) { if (firstByte >> 4 == -2) { if (pos + 1 < offset + length) { @@ -265,6 +269,7 @@ public void truncate(final long truncateLen) { byte firstByte = data[pos++]; if (firstByte < 0) { if (firstByte >> 5 != -2 || (firstByte & 30) == 0) { + System.out.println(firstByte >> 4 ); if (firstByte >> 4 == -2) { if (pos + 1 < offset + length) { pos += 2; diff --git a/src/main/java/org/mariadb/jdbc/MariaDbDataSource.java b/src/main/java/org/mariadb/jdbc/MariaDbDataSource.java index 08a7e0d1c..bbd47b110 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbDataSource.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbDataSource.java @@ -70,12 +70,8 @@ public Connection getConnection() throws SQLException { */ @Override public Connection getConnection(String username, String password) throws SQLException { - try { - Configuration conf = this.conf.clone(username, password); - return Driver.connect(conf); - } catch (CloneNotSupportedException cloneNotSupportedException) { - throw new SQLException(cloneNotSupportedException); - } + Configuration conf = this.conf.clone(username, password); + return Driver.connect(conf); } /** @@ -191,12 +187,8 @@ public PooledConnection getPooledConnection() throws SQLException { @Override public PooledConnection getPooledConnection(String username, String password) throws SQLException { - try { - Configuration conf = this.conf.clone(username, password); - org.mariadb.jdbc.Connection connection = Driver.connect(conf); - return new MariaDbPoolConnection(connection); - } catch (CloneNotSupportedException cloneNotSupportedException) { - throw new SQLException(cloneNotSupportedException); - } + Configuration conf = this.conf.clone(username, password); + org.mariadb.jdbc.Connection connection = Driver.connect(conf); + return new MariaDbPoolConnection(connection); } } diff --git a/src/main/java/org/mariadb/jdbc/ParameterMetaData.java b/src/main/java/org/mariadb/jdbc/ParameterMetaData.java index 786f6756d..225e6449e 100644 --- a/src/main/java/org/mariadb/jdbc/ParameterMetaData.java +++ b/src/main/java/org/mariadb/jdbc/ParameterMetaData.java @@ -44,11 +44,7 @@ private void checkIndex(int index) throws SQLException { @Override public int isNullable(int idx) throws SQLException { checkIndex(idx); - if (params[idx - 1].isNullable()) { - return java.sql.ParameterMetaData.parameterNullable; - } else { - return java.sql.ParameterMetaData.parameterNoNulls; - } + return java.sql.ParameterMetaData.parameterNullable; } /** diff --git a/src/main/java/org/mariadb/jdbc/ProcedureStatement.java b/src/main/java/org/mariadb/jdbc/ProcedureStatement.java index fbb68cc72..ba0d11f45 100644 --- a/src/main/java/org/mariadb/jdbc/ProcedureStatement.java +++ b/src/main/java/org/mariadb/jdbc/ProcedureStatement.java @@ -62,13 +62,13 @@ public boolean isFunction() { protected void handleParameterOutput() throws SQLException { // output result-set is the last result-set // or in case finishing with an OK_PACKET, just the one before - for (int i = 1; i <= 2; i++) { + for (int i = 1; i <= Math.min(this.results.size(), 2); i++) { Completion compl = this.results.get(this.results.size() - i); if (compl instanceof Result && (((Result) compl).isOutputParameter())) { this.outputResult = (Result) compl; + this.outputResult.next(); this.results.remove(this.results.size() - i); } } - this.outputResult.next(); } } diff --git a/src/main/java/org/mariadb/jdbc/ServerPreparedStatement.java b/src/main/java/org/mariadb/jdbc/ServerPreparedStatement.java index 458921d29..074755c78 100644 --- a/src/main/java/org/mariadb/jdbc/ServerPreparedStatement.java +++ b/src/main/java/org/mariadb/jdbc/ServerPreparedStatement.java @@ -80,29 +80,15 @@ protected void executeInternal() throws SQLException { String cmd = escapeTimeout(sql); if (prepareResult == null) prepareResult = con.getContext().getPrepareCache().get(cmd, this); try { - if (prepareResult == null) { + long serverCapabilities = con.getContext().getServerCapabilities(); + if (prepareResult == null && (serverCapabilities & Capabilities.MARIADB_CLIENT_STMT_BULK_OPERATIONS) > 0) { try { - long serverCapabilities = con.getContext().getServerCapabilities(); - if ((serverCapabilities & Capabilities.MARIADB_CLIENT_STMT_BULK_OPERATIONS) > 0) { - executePipeline(cmd); - } else { - executeStandard(cmd); - } + executePipeline(cmd); } catch (BatchUpdateException b) { throw (SQLException) b.getCause(); } } else { - ExecutePacket execute = new ExecutePacket(prepareResult, parameters, cmd, this); - results = - con.getClient() - .execute( - execute, - this, - fetchSize, - maxRows, - resultSetConcurrency, - resultSetType, - closeOnCompletion); + executeStandard(cmd); } } finally { lock.unlock(); @@ -159,10 +145,9 @@ private void executeStandard(String cmd) throws SQLException { private List executeInternalPreparedBatch() throws SQLException { checkNotClosed(); String cmd = escapeTimeout(sql); - if (prepareResult == null) prepareResult = con.getContext().getPrepareCache().get(cmd, this); - long serverCapabilities = con.getContext().getServerCapabilities(); - if ((serverCapabilities & Capabilities.MARIADB_CLIENT_STMT_BULK_OPERATIONS) > 0 + if (batchParameters.size() > 1 + && (serverCapabilities & Capabilities.MARIADB_CLIENT_STMT_BULK_OPERATIONS) > 0 && (!con.getContext().getConf().allowLocalInfile() || (serverCapabilities & Capabilities.LOCAL_FILES) == 0)) { return con.getContext().getConf().useBulkStmts() @@ -182,13 +167,15 @@ private List executeInternalPreparedBatch() throws SQLException { */ private List executeBatchBulk(String cmd) throws SQLException { ClientMessage[] packets; + if (prepareResult == null) prepareResult = con.getContext().getPrepareCache().get(cmd, this); if (prepareResult == null) { packets = new ClientMessage[] { new PreparePacket(cmd), new BulkExecutePacket(null, batchParameters, cmd, this) }; } else { - packets = new ClientMessage[] {new BulkExecutePacket(null, batchParameters, cmd, this)}; + packets = + new ClientMessage[] {new BulkExecutePacket(prepareResult, batchParameters, cmd, this)}; } try { List res = @@ -222,6 +209,7 @@ private List executeBatchBulk(String cmd) throws SQLException { * @throws SQLException if Command error */ private List executeBatchPipeline(String cmd) throws SQLException { + if (prepareResult == null) prepareResult = con.getContext().getPrepareCache().get(cmd, this); // server is 10.2+, permitting to execute last prepare with (-1) statement id. // Server send prepare, followed by execute, in one exchange. int maxCmd = 250; @@ -575,7 +563,7 @@ public int[] executeBatch() throws SQLException { updates[i] = Statement.SUCCESS_NO_INFO; } } else { - for (int i = 0; i < res.size(); i++) { + for (int i = 0; i < Math.min(res.size(), batchParameters.size()); i++) { updates[i] = (int) ((OkPacket) res.get(i)).getAffectedRows(); } } @@ -627,7 +615,7 @@ public void close() throws SQLException { super.close(); } - protected void resetPrepare() { + public void reset() { lock.lock(); try { prepareResult = null; @@ -635,8 +623,4 @@ protected void resetPrepare() { lock.unlock(); } } - - public void reset() { - prepareResult = null; - } } diff --git a/src/main/java/org/mariadb/jdbc/Statement.java b/src/main/java/org/mariadb/jdbc/Statement.java index 30d68355c..1d53d22cf 100644 --- a/src/main/java/org/mariadb/jdbc/Statement.java +++ b/src/main/java/org/mariadb/jdbc/Statement.java @@ -1026,7 +1026,7 @@ public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { protected String escapeTimeout(final String sql) throws SQLException { String escapedSql = escape ? NativeSql.parse(sql, con.getContext()) : sql; if (queryTimeout != 0 && canUseServerTimeout) { - if (canUseServerMaxRows && maxRows > 0 && con.getContext().getVersion().isMariaDBServer()) { + if (canUseServerMaxRows && maxRows > 0) { return "SET STATEMENT max_statement_time=" + queryTimeout + ", SQL_SELECT_LIMIT=" @@ -1036,7 +1036,7 @@ protected String escapeTimeout(final String sql) throws SQLException { } return "SET STATEMENT max_statement_time=" + queryTimeout + " FOR " + escapedSql; } - if (canUseServerMaxRows && maxRows > 0 && con.getContext().getVersion().isMariaDBServer()) { + if (canUseServerMaxRows && maxRows > 0) { return "SET STATEMENT SQL_SELECT_LIMIT=" + maxRows + " FOR " + escapedSql; } return escapedSql; @@ -1449,18 +1449,28 @@ public List executeInternalBatchPipeline() throws SQLException { public List executeInternalBatchStandard() throws SQLException { List results = new ArrayList<>(); - for (int i = 0; i < batchQueries.size(); i++) { - results.addAll( - con.getClient() - .execute( - new QueryPacket(batchQueries.get(i)), - this, - 0, - 0L, - ResultSet.CONCUR_READ_ONLY, - ResultSet.TYPE_FORWARD_ONLY, - closeOnCompletion)); + try { + for (int i = 0; i < batchQueries.size(); i++) { + results.addAll( + con.getClient() + .execute( + new QueryPacket(batchQueries.get(i)), + this, + 0, + 0L, + ResultSet.CONCUR_READ_ONLY, + ResultSet.TYPE_FORWARD_ONLY, + closeOnCompletion)); + } + return results; + } catch (SQLException sqle) { + int[] updateCounts = new int[batchQueries.size()]; + for (int i = 0; i < Math.min(results.size(), updateCounts.length); i++) { + Completion completion = results.get(i); + updateCounts[i] = + completion instanceof OkPacket ? (int) ((OkPacket) completion).getAffectedRows() : 0; + } + throw new BatchUpdateException(sqle.getMessage(), updateCounts, sqle); } - return results; } } diff --git a/src/main/java/org/mariadb/jdbc/client/Client.java b/src/main/java/org/mariadb/jdbc/client/Client.java index e4f5d2087..80546e0ec 100644 --- a/src/main/java/org/mariadb/jdbc/client/Client.java +++ b/src/main/java/org/mariadb/jdbc/client/Client.java @@ -77,6 +77,8 @@ void readStreamingResults( void setReadOnly(boolean readOnly) throws SQLException; + int getWaitTimeout(); + int getSocketTimeout(); void setSocketTimeout(int milliseconds) throws SQLException; diff --git a/src/main/java/org/mariadb/jdbc/client/ClientImpl.java b/src/main/java/org/mariadb/jdbc/client/ClientImpl.java index 11ad380a0..3e8acd2fd 100644 --- a/src/main/java/org/mariadb/jdbc/client/ClientImpl.java +++ b/src/main/java/org/mariadb/jdbc/client/ClientImpl.java @@ -79,6 +79,7 @@ public class ClientImpl implements Client, AutoCloseable { private org.mariadb.jdbc.Statement streamStmt = null; private ClientMessage streamMsg = null; private int socketTimeout; + private int waitTimeout; protected Context context; public ClientImpl( @@ -336,10 +337,8 @@ private void postConnectionQueries() throws SQLException { // read max allowed packet Result result = (Result) res.get(1); result.next(); - if (hostAddress != null) { - hostAddress.setCache( - Integer.parseInt(result.getString(1)), Integer.parseInt(result.getString(2))); - } + + waitTimeout = Integer.parseInt(result.getString(2)); writer.setMaxAllowedPacket(Integer.parseInt(result.getString(1))); if (hostAddress != null @@ -786,6 +785,11 @@ private void closeSocket() { } } + @Override + public int getWaitTimeout() { + return waitTimeout; + } + public boolean isClosed() { return closed; } diff --git a/src/main/java/org/mariadb/jdbc/client/MultiPrimaryClient.java b/src/main/java/org/mariadb/jdbc/client/MultiPrimaryClient.java index a65d8003e..d06595d64 100644 --- a/src/main/java/org/mariadb/jdbc/client/MultiPrimaryClient.java +++ b/src/main/java/org/mariadb/jdbc/client/MultiPrimaryClient.java @@ -456,6 +456,11 @@ public void setSocketTimeout(int milliseconds) throws SQLException { } } + @Override + public int getWaitTimeout() { + return currentClient.getWaitTimeout(); + } + @Override public boolean isClosed() { return closed; diff --git a/src/main/java/org/mariadb/jdbc/pool/Pool.java b/src/main/java/org/mariadb/jdbc/pool/Pool.java index f278d356c..e06eba66e 100644 --- a/src/main/java/org/mariadb/jdbc/pool/Pool.java +++ b/src/main/java/org/mariadb/jdbc/pool/Pool.java @@ -160,10 +160,10 @@ private void removeIdleTimeoutConnection() { boolean shouldBeReleased = false; Connection con = item.getConnection(); - if (con.getHostAddress().getWaitTimeout() > 0) { + if (con.getWaitTimeout() > 0) { // idle time is reaching server @@wait_timeout - if (idleTime > TimeUnit.SECONDS.toNanos(con.getHostAddress().getWaitTimeout() - 45)) { + if (idleTime > TimeUnit.SECONDS.toNanos(con.getWaitTimeout() - 45)) { shouldBeReleased = true; } @@ -396,22 +396,16 @@ public InternalPoolConnection getPoolConnection() throws SQLException { */ public InternalPoolConnection getPoolConnection(String username, String password) throws SQLException { - - try { - - if ((conf.user() != null ? conf.user().equals(username) : username == null) - && (conf.password() != null ? conf.password().equals(password) : password == null)) { - return getPoolConnection(); - } - - Configuration tmpConf = conf.clone(username, password); - return new InternalPoolConnection(Driver.connect(tmpConf)); - - } catch (CloneNotSupportedException cloneException) { - // cannot occur - throw new SQLException( - "Error getting connection, parameters cannot be cloned", cloneException); + if (username == null + ? conf.user() == null + : username.equals(conf.user()) && password == null + ? conf.password() == null + : password.equals(conf.password())) { + return getPoolConnection(); } + + Configuration tmpConf = conf.clone(username, password); + return new InternalPoolConnection(Driver.connect(tmpConf)); } private String generatePoolTag(int poolIndex) { @@ -503,25 +497,6 @@ public String getPoolTag() { return poolTag; } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - - Pool pool = (Pool) obj; - - return poolTag.equals(pool.poolTag); - } - - @Override - public int hashCode() { - return poolTag.hashCode(); - } - @Override public long getActiveConnections() { return totalConnection.get() - idleConnections.size(); diff --git a/src/main/java/org/mariadb/jdbc/pool/Pools.java b/src/main/java/org/mariadb/jdbc/pool/Pools.java index bf8c852d5..9578a7215 100644 --- a/src/main/java/org/mariadb/jdbc/pool/Pools.java +++ b/src/main/java/org/mariadb/jdbc/pool/Pools.java @@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger; import org.mariadb.jdbc.Configuration; -public class Pools { +public final class Pools { private static final AtomicInteger poolIndex = new AtomicInteger(); private static final Map poolMap = new ConcurrentHashMap<>(); @@ -117,12 +117,14 @@ public static void close(String poolName) { } private static void shutdownExecutor() { - poolExecutor.shutdown(); - try { - poolExecutor.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException interrupted) { - // eat + if (poolExecutor != null) { + poolExecutor.shutdown(); + try { + poolExecutor.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException interrupted) { + // eat + } + poolExecutor = null; } - poolExecutor = null; } } diff --git a/src/test/java/org/mariadb/jdbc/Common.java b/src/test/java/org/mariadb/jdbc/Common.java index cbc7d1c01..1ecaf8250 100644 --- a/src/test/java/org/mariadb/jdbc/Common.java +++ b/src/test/java/org/mariadb/jdbc/Common.java @@ -44,6 +44,8 @@ public class Common { public static Connection sharedConn; public static Connection sharedConnBinary; public static String hostname; + public static String user; + public static String password; public static TcpProxy proxy; public static String mDefUrl; private static Instant initialTest; @@ -62,14 +64,16 @@ public class Common { defaultOther = get("DB_OTHER", prop); } hostname = get("DB_HOST", prop); + user = get("DB_USER", prop); + password = get("DB_PASSWORD", prop); mDefUrl = String.format( "jdbc:mariadb://%s:%s/%s?user=%s&password=%s&%s", hostname, get("DB_PORT", prop), get("DB_DATABASE", prop), - get("DB_USER", prop), - get("DB_PASSWORD", prop), + user, + password, defaultOther); } catch (IOException io) { diff --git a/src/test/java/org/mariadb/jdbc/integration/BlobTest.java b/src/test/java/org/mariadb/jdbc/integration/BlobTest.java index 084f31841..91f6ad579 100644 --- a/src/test/java/org/mariadb/jdbc/integration/BlobTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/BlobTest.java @@ -150,7 +150,13 @@ public void setBytes() throws SQLException { final byte[] bytes = new byte[] {0, 1, 2, 3, 4, 5}; final byte[] otherBytes = new byte[] {10, 11, 12, 13}; - MariaDbBlob blob = new MariaDbBlob(new byte[] {0, 1, 2, 3, 4, 5}); + MariaDbBlob blob = new MariaDbBlob(new byte[0]); + blob.setBytes(1, new byte[0]); + assertEquals(0, blob.length()); + blob.setBytes(1, new byte[0], 0, 0); + assertEquals(0, blob.length()); + + blob = new MariaDbBlob(new byte[] {0, 1, 2, 3, 4, 5}); blob.setBytes(2, otherBytes); assertArrayEquals(new byte[] {0, 10, 11, 12, 13, 5}, blob.getBytes(1, 6)); @@ -283,6 +289,8 @@ public void truncate() throws SQLException { MariaDbBlob blob = new MariaDbBlob(bytes); blob.truncate(20); assertArrayEquals(bytes, blob.getBytes(1, 6)); + blob.truncate(-5); + assertArrayEquals(bytes, blob.getBytes(1, 6)); blob.truncate(5); assertArrayEquals(new byte[] {0, 1, 2, 3, 4, 0, 0}, blob.getBytes(1, 7)); blob.truncate(0); @@ -312,4 +320,21 @@ public void expectedErrors() { assertThrowsContains( IllegalArgumentException.class, () -> new MariaDbBlob(null, 0, 2), "byte array is null"); } + + @Test + public void equal() { + MariaDbBlob blob = new MariaDbBlob(bytes); + assertEquals(blob, blob); + assertEquals(new MariaDbBlob(bytes), blob); + assertNotEquals("", blob); + byte[] bytes = new byte[] {5, 1, 2, 3, 4, 5}; + assertNotEquals(new MariaDbBlob(bytes), blob); + assertNotEquals(new MariaDbBlob(new byte[] {5, 1}), blob); + } + + @Test + public void hashCodeTest() { + MariaDbBlob blob = new MariaDbBlob(bytes); + assertEquals(-859797942, blob.hashCode()); + } } diff --git a/src/test/java/org/mariadb/jdbc/integration/ClobTest.java b/src/test/java/org/mariadb/jdbc/integration/ClobTest.java index 301da9906..b9ad17352 100644 --- a/src/test/java/org/mariadb/jdbc/integration/ClobTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/ClobTest.java @@ -35,27 +35,27 @@ public class ClobTest extends Common { - private final byte[] bytes = "abcdešŸ™fgh".getBytes(StandardCharsets.UTF_8); + private final byte[] bytes = "abcĀ£dešŸ™fgh".getBytes(StandardCharsets.UTF_8); @Test public void length() throws SQLException { MariaDbClob clob = new MariaDbClob(bytes); - assertEquals(10, clob.length()); + assertEquals(11, clob.length()); MariaDbClob clob2 = new MariaDbClob(bytes, 2, 3); - assertEquals(3, clob2.length()); + assertEquals(2, clob2.length()); } @Test public void getSubString() throws SQLException { MariaDbClob clob = new MariaDbClob(bytes); - assertEquals("abcdešŸ™", clob.getSubString(1, 7)); - assertEquals("abcdešŸ™fgh", clob.getSubString(1, 20)); - assertEquals("abcdešŸ™fgh", clob.getSubString(1, (int) clob.length())); + assertEquals("abcĀ£dešŸ™", clob.getSubString(1, 8)); + assertEquals("abcĀ£dešŸ™fgh", clob.getSubString(1, 21)); + assertEquals("abcĀ£dešŸ™fgh", clob.getSubString(1, (int) clob.length())); assertEquals("ab", clob.getSubString(1, 2)); - assertEquals("šŸ™", clob.getSubString(6, 2)); + assertEquals("šŸ™", clob.getSubString(7, 2)); - MariaDbClob clob2 = new MariaDbClob(bytes, 4, 6); + MariaDbClob clob2 = new MariaDbClob(bytes, 6, 6); assertEquals("ešŸ™f", clob2.getSubString(1, 20)); assertEquals("šŸ™f", clob2.getSubString(2, 3)); @@ -71,26 +71,26 @@ public void getSubString() throws SQLException { @Test public void getCharacterStream() throws SQLException { MariaDbClob clob = new MariaDbClob(bytes); - assureReaderEqual("abcdešŸ™", clob.getCharacterStream(1, 7)); - assureReaderEqual("abcdešŸ™fgh", clob.getCharacterStream(1, 10)); + assureReaderEqual("abcĀ£dešŸ™", clob.getCharacterStream(1, 8)); + assureReaderEqual("abcĀ£dešŸ™fgh", clob.getCharacterStream(1, 11)); try { - assureReaderEqual("abcdešŸ™fgh", clob.getCharacterStream(1, 20)); + assureReaderEqual("abcĀ£dešŸ™fgh", clob.getCharacterStream(1, 20)); fail("must have throw exception, length > to number of characters"); } catch (SQLException sqle) { // normal error } - assureReaderEqual("bcdešŸ™", clob.getCharacterStream(2, 7)); + assureReaderEqual("bcĀ£dešŸ™", clob.getCharacterStream(2, 7)); MariaDbClob clob2 = new MariaDbClob(bytes, 2, 9); - assureReaderEqual("cdešŸ™fg", clob2.getCharacterStream(1, 7)); + assureReaderEqual("cĀ£dešŸ™", clob2.getCharacterStream(1, 6)); try { - assureReaderEqual("cdešŸ™fg", clob2.getCharacterStream(1, 20)); + assureReaderEqual("cĀ£dešŸ™fg", clob2.getCharacterStream(1, 20)); fail("must have throw exception, length > to number of characters"); } catch (SQLException sqle) { // normal error } - assureReaderEqual("ešŸ™f", clob2.getCharacterStream(3, 5)); + assureReaderEqual("dešŸ™", clob2.getCharacterStream(3, 4)); } private void assureReaderEqual(String expectedStr, Reader reader) { @@ -127,22 +127,22 @@ public void setCharacterStream() throws SQLException, IOException { @Test public void position() throws SQLException { MariaDbClob clob = new MariaDbClob(bytes); - assertEquals(4, clob.position("de", 2)); - assertEquals(4, clob.position((Clob) new MariaDbClob("de".getBytes()), 2)); + assertEquals(5, clob.position("de", 2)); + assertEquals(5, clob.position((Clob) new MariaDbClob("de".getBytes()), 2)); clob = new MariaDbClob(bytes, 2, 10); - assertEquals(4, clob.position("šŸ™", 2)); + assertEquals(5, clob.position("šŸ™", 2)); } @Test public void setString() throws SQLException { - final byte[] bytes = "abcdešŸ™fgh".getBytes(StandardCharsets.UTF_8); + final byte[] bytes = "abcdĀ£ešŸ™fgh".getBytes(StandardCharsets.UTF_8); final MariaDbClob clob = new MariaDbClob(bytes); - assureReaderEqual("abcdešŸ™", clob.getCharacterStream(1, 7)); + assureReaderEqual("abcdĀ£ešŸ™", clob.getCharacterStream(1, 8)); clob.setString(2, "zuv"); - assertEquals("azuvešŸ™", clob.getSubString(1, 7)); + assertEquals("azuvĀ£ešŸ™", clob.getSubString(1, 8)); clob.setString(9, "zzz"); - assertEquals("azuvešŸ™fgzzz", clob.getSubString(1, 12)); + assertEquals("azuvĀ£ešŸ™fzzz", clob.getSubString(1, 12)); MariaDbClob clob2 = new MariaDbClob("abcdešŸ™fgh".getBytes(StandardCharsets.UTF_8), 2, 9); assureReaderEqual("cdešŸ™fg", clob2.getCharacterStream(1, 7)); @@ -154,6 +154,8 @@ public void setString() throws SQLException { String ss = clob2.getSubString(1, 12); assertEquals("czgšŸ™fgzzz", clob2.getSubString(1, 12)); + assertThrowsContains( + SQLException.class, () -> clob2.setString(2, "abcd", 2, -2), "len must be > 0"); clob2.setString(2, "abcd", 2, 2); assertEquals("ccdšŸ™f", clob2.getSubString(1, 6)); clob2.setString(2, "opml", 3, 200); @@ -218,6 +220,49 @@ public void setAsciiStream() throws SQLException, IOException { assertArrayEquals(bytes, b); } + @Test + public void wrongUtf8() { + final byte[] utf8Wrong2bytes = new byte[] {0x08, (byte) 0xFF, (byte) 0x6F, (byte) 0x6F}; + final byte[] utf8Wrong3bytes = + new byte[] {0x07, (byte) 0x0a, (byte) 0xff, (byte) 0x6F, (byte) 0x6F}; + final byte[] utf8Wrong4bytes = + new byte[] {0x10, (byte) 0x20, (byte) 0x0a, (byte) 0xff, (byte) 0x6F, (byte) 0x6F}; + + assertThrowsContains( + UncheckedIOException.class, + () -> new MariaDbClob(utf8Wrong2bytes).length(), + "invalid UTF8"); + assertThrowsContains( + UncheckedIOException.class, + () -> new MariaDbClob(new byte[] {(byte)225}).length(), + "invalid UTF8"); + + assertThrowsContains( + UncheckedIOException.class, + () -> new MariaDbClob(utf8Wrong3bytes).length(), + "invalid UTF8"); + assertThrowsContains( + UncheckedIOException.class, + () -> new MariaDbClob(utf8Wrong4bytes).length(), + "invalid UTF8"); + assertThrowsContains( + UncheckedIOException.class, + () -> new MariaDbClob(new byte[] {(byte)225}).truncate(2), + "invalid UTF8"); + assertThrowsContains( + UncheckedIOException.class, + () -> new MariaDbClob(utf8Wrong2bytes).truncate(2), + "invalid UTF8"); + assertThrowsContains( + UncheckedIOException.class, + () -> new MariaDbClob(utf8Wrong3bytes).truncate(3), + "invalid UTF8"); + assertThrowsContains( + UncheckedIOException.class, + () -> new MariaDbClob(utf8Wrong4bytes).truncate(4), + "invalid UTF8"); + } + @Test public void setBinaryStream() throws SQLException, IOException { final byte[] bytes = "abcdešŸ™fgh".getBytes(StandardCharsets.UTF_8); @@ -286,28 +331,30 @@ public void setBinaryStreamOffset() throws SQLException, IOException { public void truncate() throws SQLException { MariaDbClob clob = new MariaDbClob(bytes); clob.truncate(20); - assertEquals("abcdešŸ™f", clob.getSubString(1, 8)); + assertEquals("abcĀ£dešŸ™f", clob.getSubString(1, 9)); clob.truncate(8); - assertEquals("abcdešŸ™f", clob.getSubString(1, 8)); - assertEquals("abcdešŸ™", clob.getSubString(1, 7)); + assertEquals("abcĀ£dešŸ™", clob.getSubString(1, 9)); + assertEquals("abcĀ£dešŸ™", clob.getSubString(1, 8)); clob.truncate(7); - assertEquals("abcdešŸ™", clob.getSubString(1, 8)); + assertEquals("abcĀ£deļæ½", clob.getSubString(1, 9)); clob.truncate(6); - assertEquals("abcdeļæ½", clob.getSubString(1, 8)); + assertEquals("abcĀ£de", clob.getSubString(1, 9)); clob.truncate(4); - assertEquals("abcd", clob.getSubString(1, 7)); + assertEquals("abcĀ£", clob.getSubString(1, 8)); + clob.truncate(3); + assertEquals("abc", clob.getSubString(1, 8)); clob.truncate(0); - assertEquals("", clob.getSubString(1, 7)); + assertEquals("", clob.getSubString(1, 8)); - MariaDbClob clob2 = new MariaDbClob("abcdešŸ™fgh".getBytes(StandardCharsets.UTF_8), 2, 8); + MariaDbClob clob2 = new MariaDbClob("abcĀ£dešŸ™fgh".getBytes(StandardCharsets.UTF_8), 2, 10); clob2.truncate(20); - assertEquals("cdešŸ™f", clob2.getSubString(1, 8)); + assertEquals("cĀ£dešŸ™f", clob2.getSubString(1, 9)); clob2.truncate(6); - assertEquals("cdešŸ™f", clob2.getSubString(1, 8)); + assertEquals("cĀ£dešŸ™", clob2.getSubString(1, 9)); clob2.truncate(5); - assertEquals("cdešŸ™", clob2.getSubString(1, 8)); + assertEquals("cĀ£deļæ½", clob2.getSubString(1, 9)); clob2.truncate(4); - assertEquals("cdeļæ½", clob2.getSubString(1, 8)); + assertEquals("cĀ£de", clob2.getSubString(1, 9)); clob2.truncate(0); assertEquals("", clob2.getSubString(1, 7)); } @@ -362,4 +409,15 @@ public void clobLength() throws Exception { } } } + + @Test + public void equal() { + MariaDbClob clob = new MariaDbClob(bytes); + assertEquals(clob, clob); + assertEquals(new MariaDbClob(bytes), clob); + assertNotEquals("", clob); + byte[] bytes = "AbcĀ£dešŸ™fgh".getBytes(StandardCharsets.UTF_8); + assertNotEquals(new MariaDbClob(bytes), clob); + assertNotEquals(new MariaDbClob("Abc".getBytes(StandardCharsets.UTF_8)), clob); + } } diff --git a/src/test/java/org/mariadb/jdbc/integration/ConnectionTest.java b/src/test/java/org/mariadb/jdbc/integration/ConnectionTest.java index f2d150e32..063994b6b 100644 --- a/src/test/java/org/mariadb/jdbc/integration/ConnectionTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/ConnectionTest.java @@ -756,7 +756,7 @@ public void various() throws SQLException { assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, sharedConn.getHoldability()); sharedConn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT); assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, sharedConn.getHoldability()); - assertNotNull(sharedConn.getHostAddress()); + assertNotEquals(0, sharedConn.getWaitTimeout()); } @Test diff --git a/src/test/java/org/mariadb/jdbc/integration/FunctionTest.java b/src/test/java/org/mariadb/jdbc/integration/FunctionTest.java index d9abb4266..b4ecda519 100644 --- a/src/test/java/org/mariadb/jdbc/integration/FunctionTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/FunctionTest.java @@ -26,6 +26,7 @@ import java.sql.*; import org.junit.jupiter.api.Test; import org.mariadb.jdbc.Common; +import org.mariadb.jdbc.Connection; import org.mariadb.jdbc.Statement; public class FunctionTest extends Common { @@ -53,4 +54,35 @@ public void basicFunction() throws SQLException { assertEquals(6, callableStatement.getInt(1)); } } + + @Test + public void functionWithoutArg() throws SQLException { + functionWithoutArg(sharedConn); + functionWithoutArg(sharedConnBinary); + } + + private void functionWithoutArg(Connection con) throws SQLException { + Statement stmt = con.createStatement(); + stmt.execute("DROP FUNCTION IF EXISTS no_arg_function"); + stmt.execute("CREATE FUNCTION no_arg_function () RETURNS DOUBLE DETERMINISTIC RETURN RAND();"); + try (CallableStatement callableStatement = con.prepareCall("{? = call no_arg_function()}")) { + callableStatement.registerOutParameter(1, JDBCType.DOUBLE); + callableStatement.execute(); + callableStatement.getDouble(1); + assertThrowsContains( + SQLException.class, + () -> callableStatement.registerOutParameter(2, JDBCType.DOUBLE), + " wrong parameter index 2"); + } + + try (CallableStatement callableStatement = con.prepareCall("{? = call no_arg_function()}")) { + callableStatement.execute(); + callableStatement.getDouble(1); + } + + try (CallableStatement callableStatement = con.prepareCall("{? = call no_arg_function}")) { + callableStatement.execute(); + callableStatement.getDouble(1); + } + } } diff --git a/src/test/java/org/mariadb/jdbc/integration/MultiQueriesTest.java b/src/test/java/org/mariadb/jdbc/integration/MultiQueriesTest.java index b94a7111b..ea01a8224 100644 --- a/src/test/java/org/mariadb/jdbc/integration/MultiQueriesTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/MultiQueriesTest.java @@ -93,6 +93,12 @@ public void allowMultiQueriesFetchTest() throws SQLException { assertTrue(resultSet.next()); assertEquals("a", resultSet.getString(2)); } while (stmt.getMoreResults()); + + stmt.executeQuery( + "SELECT * from AllowMultiQueriesTest;SELECT * from AllowMultiQueriesTest;"); + ResultSet rs = stmt.executeQuery("SELECT 1"); + rs.next(); + assertEquals(1, rs.getInt(1)); } try (Statement statement = connection.createStatement()) { statement.execute("SELECT 1"); @@ -100,6 +106,23 @@ public void allowMultiQueriesFetchTest() throws SQLException { } } + @Test + public void quitWhileStreaming() throws SQLException { + Connection connection = createCon("&allowMultiQueries=true"); + Statement stmt = connection.createStatement(); + stmt.setFetchSize(1); + stmt.executeQuery( + "DO 2;SELECT * from AllowMultiQueriesTest;SELECT * from AllowMultiQueriesTest; DO 1; SELECT 2"); + connection.abort(Runnable::run); + + connection = createCon("&allowMultiQueries=true"); + stmt = connection.createStatement(); + stmt.setFetchSize(1); + stmt.executeQuery( + "DO 2;DO 1;SELECT * from AllowMultiQueriesTest"); + connection.abort(Runnable::run); + } + @Test public void allowMultiQueriesFetchKeepTest() throws SQLException { try (Connection connection = createCon("&allowMultiQueries=true")) { diff --git a/src/test/java/org/mariadb/jdbc/integration/ParameterMetaDataTest.java b/src/test/java/org/mariadb/jdbc/integration/ParameterMetaDataTest.java index ad78407ab..2b819d6d0 100644 --- a/src/test/java/org/mariadb/jdbc/integration/ParameterMetaDataTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/ParameterMetaDataTest.java @@ -64,12 +64,14 @@ private void parameterMetaDataTypeNotAvailable(org.mariadb.jdbc.Connection con, try (PreparedStatement prepStmt = con.prepareStatement(query)) { ParameterMetaData parameterMetaData = prepStmt.getParameterMetaData(); assertEquals(2, parameterMetaData.getParameterCount()); - try { - parameterMetaData.getParameterType(1); - fail("must have thrown an error"); - } catch (SQLException sqle) { - assertTrue(sqle instanceof SQLFeatureNotSupportedException); - } + assertThrowsContains( + SQLException.class, + () -> parameterMetaData.getParameterType(1), + "Getting parameter type metadata are not supported"); + assertThrowsContains( + SQLException.class, () -> parameterMetaData.isNullable(-1), "Wrong index position"); + assertThrowsContains( + SQLException.class, () -> parameterMetaData.isNullable(3), "Wrong index position"); } } diff --git a/src/test/java/org/mariadb/jdbc/integration/PoolDataSourceTest.java b/src/test/java/org/mariadb/jdbc/integration/PoolDataSourceTest.java index 0ba4ddc7a..f5afbe3f4 100644 --- a/src/test/java/org/mariadb/jdbc/integration/PoolDataSourceTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/PoolDataSourceTest.java @@ -35,6 +35,8 @@ import javax.management.MBeanInfo; import javax.management.MBeanServer; import javax.management.ObjectName; +import javax.sql.ConnectionPoolDataSource; +import javax.sql.PooledConnection; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; @@ -96,6 +98,13 @@ public void testDataSource() throws SQLException { try (Connection connection = ds.getConnection("poolUser", "!Passw0rd3Works")) { assertEquals(connection.isValid(0), true); } + + PooledConnection poolCon = ds.getPooledConnection(); + assertEquals(poolCon.getConnection().isValid(0), true); + poolCon.close(); + poolCon = ds.getPooledConnection("poolUser", "!Passw0rd3Works"); + assertEquals(poolCon.getConnection().isValid(0), true); + poolCon.close(); } } @@ -536,8 +545,6 @@ public void ensureClosed() throws Throwable { @Test public void wrongUrlHandling() throws SQLException { - - int initialConnection = getCurrentConnections(); try (MariaDbPoolDataSource pool = new MariaDbPoolDataSource( "jdbc:mariadb://unknownHost/db?user=wrong&maxPoolSize=10&connectTimeout=500")) { @@ -548,7 +555,7 @@ public void wrongUrlHandling() throws SQLException { } catch (SQLException sqle) { assertTrue( (System.currentTimeMillis() - start) >= 500 - && (System.currentTimeMillis() - start) < 700, + && (System.currentTimeMillis() - start) < 800, "timeout does not correspond to option. Elapsed time:" + (System.currentTimeMillis() - start)); assertTrue( @@ -596,4 +603,62 @@ public static int getCurrentConnections() { return -1; } } + + @Test + public void poolWithUser() throws SQLException { + try (MariaDbPoolDataSource pool = + new MariaDbPoolDataSource(mDefUrl + "&maxPoolSize=1&poolName=myPool")) { + long threadId = 0; + try (Connection conn = pool.getConnection()) { + conn.isValid(1); + threadId = ((org.mariadb.jdbc.Connection) conn).getThreadId(); + } + + try (Connection conn = pool.getConnection(user, password)) { + conn.isValid(1); + assertEquals(threadId, ((org.mariadb.jdbc.Connection) conn).getThreadId()); + } + try (Connection conn = pool.getConnection("poolUser", "!Passw0rd3Works")) { + conn.isValid(1); + assertNotEquals(threadId, ((org.mariadb.jdbc.Connection) conn).getThreadId()); + } + } + } + + @Test + public void various() throws SQLException { + assertThrowsContains( + SQLException.class, + () -> new MariaDbPoolDataSource("jdbc:notMariadb"), + "Wrong mariaDB url"); + try (MariaDbPoolDataSource pool = + new MariaDbPoolDataSource(mDefUrl + "&maxPoolSize=1&poolName=myPool&connectTimeout=2000")) { + assertNotNull(pool.unwrap(org.mariadb.jdbc.MariaDbPoolDataSource.class)); + assertNotNull(pool.unwrap(ConnectionPoolDataSource.class)); + assertThrowsContains( + SQLException.class, + () -> pool.unwrap(String.class), + "Datasource is not a wrapper for java.lang.String"); + assertTrue(pool.isWrapperFor(org.mariadb.jdbc.MariaDbPoolDataSource.class)); + assertTrue(pool.isWrapperFor(ConnectionPoolDataSource.class)); + assertFalse(pool.isWrapperFor(String.class)); + pool.setLogWriter(null); + assertNull(pool.getLogWriter()); + assertNull(pool.getParentLogger()); + assertEquals(2, pool.getLoginTimeout()); + pool.setLoginTimeout(4); + assertEquals(4, pool.getLoginTimeout()); + } + } + + @Test + public void pools() throws SQLException { + // ensure all are closed + Pools.close(); + Pools.close(null); + new MariaDbPoolDataSource(mDefUrl + "&maxPoolSize=1&poolName=myPool"); + Pools.close("myPool"); + new MariaDbPoolDataSource(mDefUrl + "&maxPoolSize=1&poolName=myPool"); + Pools.close(); + } } diff --git a/src/test/java/org/mariadb/jdbc/integration/PooledConnectionTest.java b/src/test/java/org/mariadb/jdbc/integration/PooledConnectionTest.java index 00d56c317..6393a510a 100644 --- a/src/test/java/org/mariadb/jdbc/integration/PooledConnectionTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/PooledConnectionTest.java @@ -107,7 +107,9 @@ public void testPoolFailover() throws Exception { @Test public void testPoolKillConnection() throws Exception { Assumptions.assumeTrue( - !"skysql".equals(System.getenv("srv")) && !"skysql-ha".equals(System.getenv("srv"))); + !"maxscale".equals(System.getenv("srv")) + && !"skysql".equals(System.getenv("srv")) + && !"skysql-ha".equals(System.getenv("srv"))); try (MariaDbPoolDataSource ds = new MariaDbPoolDataSource(mDefUrl + "&maxPoolSize=1")) { InternalPoolConnection pc = ds.getPooledConnection(); org.mariadb.jdbc.Connection conn = pc.getConnection(); diff --git a/src/test/java/org/mariadb/jdbc/integration/PreparedStatementMetadataTest.java b/src/test/java/org/mariadb/jdbc/integration/PreparedStatementMetadataTest.java index 3c9fa0112..fd12a186b 100644 --- a/src/test/java/org/mariadb/jdbc/integration/PreparedStatementMetadataTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/PreparedStatementMetadataTest.java @@ -48,6 +48,8 @@ private void execute(Connection conn) throws SQLException { try (PreparedStatement prep = conn.prepareStatement("SELECT * FROM prepareMeta")) { ResultSetMetaData meta = prep.getMetaData(); assertEquals(2, meta.getColumnCount()); + meta = prep.getMetaData(); + assertEquals(2, meta.getColumnCount()); } } } diff --git a/src/test/java/org/mariadb/jdbc/integration/PreparedStatementTest.java b/src/test/java/org/mariadb/jdbc/integration/PreparedStatementTest.java index 0b3fc50de..12992608f 100644 --- a/src/test/java/org/mariadb/jdbc/integration/PreparedStatementTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/PreparedStatementTest.java @@ -38,6 +38,7 @@ public static void drop() throws SQLException { stmt.execute("DROP TABLE IF EXISTS prepare1"); stmt.execute("DROP TABLE IF EXISTS prepare2"); stmt.execute("DROP TABLE IF EXISTS prepare3"); + stmt.execute("DROP TABLE IF EXISTS prepare4"); } @BeforeAll @@ -47,6 +48,8 @@ public static void beforeAll2() throws SQLException { stmt.execute("CREATE TABLE prepare1 (t1 int not null primary key auto_increment, t2 int)"); stmt.execute("CREATE TABLE prepare2 (t1 int not null primary key auto_increment, t2 int)"); stmt.execute("CREATE TABLE prepare3 (t1 LONGTEXT, t2 LONGTEXT, t3 LONGTEXT, t4 LONGTEXT)"); + stmt.execute("CREATE TABLE prepare4 (t1 int)"); + stmt.execute("INSERT INTO prepare4 VALUES (1),(2),(3),(4),(5)"); } @Test @@ -100,6 +103,10 @@ private void execute(Connection conn) throws SQLException { preparedStatement.setInt(2, 10); assertFalse(preparedStatement.execute()); + + ParameterMetaData paramMeta = preparedStatement.getParameterMetaData(); + paramMeta.getParameterTypeName(1); + // verification ResultSet rs = stmt.executeQuery("SELECT * FROM prepare1"); assertTrue(rs.next()); @@ -148,10 +155,15 @@ private void execute(Connection conn) throws SQLException { @Test public void executeWithoutAllParameters() throws SQLException { - Statement stmt = sharedConn.createStatement(); + executeWithoutAllParameters(sharedConn); + executeWithoutAllParameters(sharedConnBinary); + } + + public void executeWithoutAllParameters(Connection con) throws SQLException { + Statement stmt = con.createStatement(); stmt.execute("TRUNCATE prepare1"); try (PreparedStatement preparedStatement = - sharedConn.prepareStatement("INSERT INTO prepare1(t1, t2) VALUES (?,?)")) { + con.prepareStatement("INSERT INTO prepare1(t1, t2) VALUES (?,?)")) { preparedStatement.setInt(2, 10); assertThrowsContains( SQLException.class, @@ -302,11 +314,155 @@ public void closeOnCompletion() throws SQLException { @Test public void executeBatch() throws SQLException { - Statement stmt = sharedConn.createStatement(); +// executeBatch(sharedConn); + executeBatch(sharedConnBinary); +// try (Connection con = createCon("allowLocalInfile=true")) { +// executeBatch(con); +// } +// try (Connection con = createCon("allowLocalInfile=true&useServerPrepStmts=true")) { +// executeBatch(con); +// } + } + + private void executeBatch(Connection con) throws SQLException { + Statement stmt = con.createStatement(); stmt.execute("TRUNCATE prepare1"); - stmt.execute("INSERT INTO prepare1(t1, t2) VALUES (5,10), (40,20), (127,45)"); try (PreparedStatement preparedStatement = - sharedConn.prepareStatement("SELECT * FROM prepare1 WHERE t1 > ?")) { + con.prepareStatement("INSERT INTO prepare1(t1, t2) VALUES (?,?)")) { + + try (PreparedStatement preparedStatement2 = + con.prepareStatement("INSERT INTO prepare1(t1, t2) VALUES (?,?)")) { + preparedStatement2.setInt(1, 15); + preparedStatement2.setInt(2, 110); + preparedStatement2.addBatch(); + preparedStatement2.executeBatch(); + } + + int[] res = preparedStatement.executeBatch(); + assertEquals(0, res.length); + preparedStatement.setInt(1, 5); + preparedStatement.setInt(2, 10); + preparedStatement.addBatch(); + res = preparedStatement.executeBatch(); + assertEquals(1, res.length); + res = preparedStatement.executeBatch(); + assertEquals(0, res.length); + } + + + try (PreparedStatement preparedStatement = + con.prepareStatement("INSERT INTO prepare1(t1, t2) VALUES (?,?)")) { + preparedStatement.setInt(1, 40); + preparedStatement.setInt(2, 20); + preparedStatement.addBatch(); + preparedStatement.setInt(1, 127); + preparedStatement.setInt(2, 45); + preparedStatement.addBatch(); + int[] res = preparedStatement.executeBatch(); + assertEquals(2, res.length); + } + + try (PreparedStatement preparedStatement = + con.prepareStatement("SELECT * FROM prepare1 WHERE t1 > ?")) { + preparedStatement.setInt(1, 20); + ResultSet rs = preparedStatement.executeQuery(); + assertTrue(rs.next()); + assertEquals(40, rs.getInt(1)); + assertEquals(20, rs.getInt(2)); + assertTrue(rs.next()); + assertEquals(127, rs.getInt(1)); + assertEquals(45, rs.getInt(2)); + assertFalse(rs.next()); + } + } + + @Test + public void executeBatchMultiple() throws SQLException { + try (Connection con = createCon("allowMultiQueries&useBulkStmts=false")) { + executeBatchMultiple(con); + } + } + + private void executeBatchMultiple(Connection con) throws SQLException { + Statement stmt = con.createStatement(); + stmt.execute("TRUNCATE prepare1"); + try (PreparedStatement preparedStatement = + con.prepareStatement("INSERT INTO prepare1(t1, t2) VALUES (?,?);DO 1")) { + int[] res = preparedStatement.executeBatch(); + assertEquals(0, res.length); + preparedStatement.setInt(1, 5); + preparedStatement.setInt(2, 10); + preparedStatement.addBatch(); + res = preparedStatement.executeBatch(); + assertEquals(1, res.length); + res = preparedStatement.executeBatch(); + assertEquals(0, res.length); + } + + try (PreparedStatement preparedStatement = + con.prepareStatement("INSERT INTO prepare1(t1, t2) VALUES (?,?);DO 1")) { + preparedStatement.setInt(1, 40); + preparedStatement.setInt(2, 20); + preparedStatement.addBatch(); + preparedStatement.setInt(1, 127); + preparedStatement.setInt(2, 45); + preparedStatement.addBatch(); + int[] res = preparedStatement.executeBatch(); + assertEquals(2, res.length); + } + + try (PreparedStatement preparedStatement = + con.prepareStatement("SELECT * FROM prepare1 WHERE t1 > ?")) { + preparedStatement.setInt(1, 20); + ResultSet rs = preparedStatement.executeQuery(); + assertTrue(rs.next()); + assertEquals(40, rs.getInt(1)); + assertEquals(20, rs.getInt(2)); + assertTrue(rs.next()); + assertEquals(127, rs.getInt(1)); + assertEquals(45, rs.getInt(2)); + assertFalse(rs.next()); + } + } + + @Test + public void executeLargeBatch() throws SQLException { + executeLargeBatch(sharedConn); + executeLargeBatch(sharedConnBinary); + try (Connection con = createCon("allowLocalInfile=true")) { + executeLargeBatch(con); + } + try (Connection con = createCon("allowLocalInfile=true&useServerPrepStmts=true")) { + executeLargeBatch(con); + } + } + + private void executeLargeBatch(Connection con) throws SQLException { + Statement stmt = con.createStatement(); + stmt.execute("TRUNCATE prepare1"); + try (PreparedStatement preparedStatement = + con.prepareStatement("INSERT INTO prepare1(t1, t2) VALUES (?,?)")) { + preparedStatement.executeLargeBatch(); + preparedStatement.setInt(1, 5); + preparedStatement.setInt(2, 10); + preparedStatement.addBatch(); + preparedStatement.executeLargeBatch(); + preparedStatement.executeLargeBatch(); + } + + try (PreparedStatement preparedStatement = + con.prepareStatement("INSERT INTO prepare1(t1, t2) VALUES (?,?)")) { + preparedStatement.setInt(1, 40); + preparedStatement.setInt(2, 20); + preparedStatement.addBatch(); + preparedStatement.setInt(1, 127); + preparedStatement.setInt(2, 45); + preparedStatement.addBatch(); + preparedStatement.executeLargeBatch(); + } + + try (PreparedStatement preparedStatement = + con.prepareStatement("SELECT * FROM prepare1 WHERE t1 > ?")) { preparedStatement.setInt(1, 20); ResultSet rs = preparedStatement.executeQuery(); assertTrue(rs.next()); @@ -485,13 +641,12 @@ public void moreRowLimitedResults() throws SQLException { } private void moreRowLimitedResults(Connection con) throws SQLException { - Assumptions.assumeTrue(isMariaDBServer()); Statement stmt = con.createStatement(); stmt.execute("DROP PROCEDURE IF EXISTS multi"); stmt.setFetchSize(3); stmt.setMaxRows(5); stmt.execute( - "CREATE PROCEDURE multi() BEGIN SELECT * from seq_1_to_10; SELECT * FROM seq_1_to_1000;SELECT 2; END"); + "CREATE PROCEDURE multi() BEGIN SELECT * from prepare4; SELECT * FROM prepare4;SELECT 2; END"); stmt.execute("CALL multi()"); Assertions.assertTrue(stmt.getMoreResults()); ResultSet rs = stmt.getResultSet(); @@ -502,6 +657,7 @@ private void moreRowLimitedResults(Connection con) throws SQLException { Assertions.assertEquals(6, i); stmt.setFetchSize(3); PreparedStatement prep = con.prepareStatement("CALL multi()"); + prep.setMaxRows(20); rs = prep.executeQuery(); Assertions.assertFalse(rs.isClosed()); prep.setFetchSize(0); // force more result to load all remaining result-set @@ -696,6 +852,8 @@ private void largeMaxRows(Connection con) throws SQLException { assertEquals(i, rs.getInt(1)); } assertEquals(50, i); + prep.setQueryTimeout(0); + prep.setQueryTimeout(0); } } diff --git a/src/test/java/org/mariadb/jdbc/integration/ProcedureTest.java b/src/test/java/org/mariadb/jdbc/integration/ProcedureTest.java index cb1ecc930..235a33565 100644 --- a/src/test/java/org/mariadb/jdbc/integration/ProcedureTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/ProcedureTest.java @@ -32,6 +32,9 @@ import java.util.Calendar; import java.util.HashMap; import java.util.Map; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mariadb.jdbc.Common; import org.mariadb.jdbc.MariaDbBlob; @@ -40,12 +43,37 @@ public class ProcedureTest extends Common { + @AfterAll + public static void drop() throws SQLException { + Statement stmt = sharedConn.createStatement(); + stmt.execute("DROP TABLE IF EXISTS procedure_test"); + } + + @BeforeAll + public static void beforeAll2() throws SQLException { + drop(); + Statement stmt = sharedConn.createStatement(); + stmt.execute("CREATE TABLE procedure_test (t0 int)"); + } + @Test public void wrongCall() throws SQLException { assertThrowsContains( SQLException.class, () -> sharedConn.prepareCall("SELECT ?"), "invalid callable syntax"); } + @Test + public void prepInsert() throws SQLException { + Statement st = sharedConn.createStatement(); + st.execute("DROP PROCEDURE IF EXISTS prep_proc2"); + st.execute("CREATE PROCEDURE prep_proc2 (IN t1 INT) BEGIN \n" + "INSERT INTO procedure_test(t0) VALUE (t1);\n" + "END"); + + try (PreparedStatement stmt = sharedConn.prepareCall("CALL prep_proc2(?)")) { + stmt.setInt(1, 1); + stmt.execute(); + } + } + @Test public void prep() throws SQLException { Statement st = sharedConn.createStatement(); @@ -89,6 +117,7 @@ public void basicProcedure() throws Throwable { stmt.execute("DROP PROCEDURE IF EXISTS basic_proc"); stmt.execute( "CREATE PROCEDURE basic_proc (IN t1 INT, INOUT t2 INT unsigned, OUT t3 INT, IN t4 INT, OUT t5 VARCHAR(20), OUT t6 TIMESTAMP, OUT t7 blob) BEGIN \n" + + "SELECT 1;\n" + "set t3 = t1 * t4;\n" + "set t2 = t2 * t1;\n" + "set t5 = 'http://test';\n" @@ -111,6 +140,10 @@ public void basicProcedure() throws Throwable { callableStatement.registerOutParameter(6, JDBCType.TIMESTAMP); callableStatement.registerOutParameter(7, JDBCType.TIMESTAMP); checkResults(callableStatement); + ParameterMetaData meta = callableStatement.getParameterMetaData(); + + assertEquals("INT", meta.getParameterTypeName(1)); + assertEquals("VARCHAR", meta.getParameterTypeName(5)); callableStatement.registerOutParameter(2, Types.INTEGER); callableStatement.registerOutParameter(3, Types.INTEGER); diff --git a/src/test/java/org/mariadb/jdbc/integration/StatementTest.java b/src/test/java/org/mariadb/jdbc/integration/StatementTest.java index 8577c190d..4a19863a3 100644 --- a/src/test/java/org/mariadb/jdbc/integration/StatementTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/StatementTest.java @@ -106,6 +106,7 @@ public void execute() throws SQLException { stmt.close(); } + @Test public void executeGenerated() throws SQLException { Statement stmt = sharedConn.createStatement(); @@ -451,6 +452,19 @@ public void queryTimeout() throws Exception { "Query execution was interrupted (max_statement_time exceeded)"); } + @Test + public void smallQueryTimeout() throws Exception { + Statement stmt = sharedConn.createStatement(); + stmt.setQueryTimeout(1); + stmt.execute("SELECT 1"); + + stmt.setMaxRows(1); + stmt.execute("SELECT 1"); + + stmt.setQueryTimeout(0); + stmt.execute("SELECT 1"); + } + @Test public void escaping() throws Exception { try (Connection con = @@ -603,6 +617,20 @@ public void fetchUnFinishedOtherStatement() throws SQLException { assertFalse(rs2.next()); } + @Test + public void fetchUnfinished() throws SQLException { + Assumptions.assumeTrue(isMariaDBServer()); + Statement stmt = sharedConn.createStatement(); + stmt.setFetchSize(1); + stmt.executeQuery("select * FROM seq_1_to_20"); + assertFalse(stmt.getMoreResults()); + + Statement stmt2 = sharedConn.createStatement(); + ResultSet rs = stmt2.executeQuery("SELECT 1"); + rs.next(); + assertEquals(1, rs.getInt(1)); + } + @Test public void fetchClose() throws SQLException { Assumptions.assumeTrue(isMariaDBServer()); @@ -617,6 +645,7 @@ public void fetchClose() throws SQLException { } stmt.close(); assertTrue(rs.isClosed()); + stmt.close(); Statement stmt2 = sharedConn.createStatement(); ResultSet rs2 = stmt2.executeQuery("select * FROM seq_1_to_1000"); @@ -629,7 +658,16 @@ public void fetchClose() throws SQLException { @Test public void executeBatchBasic() throws SQLException { - Statement stmt = sharedConn.createStatement(); + executeBatchBasic(sharedConn); + try (Connection con = createCon("allowLocalInfile=true")) { + executeBatchBasic(con); + } + } + + private void executeBatchBasic(Connection con) throws SQLException { + Statement stmt = con.createStatement(); + assertArrayEquals(new int[0], stmt.executeBatch()); + stmt.clearBatch(); stmt.execute("DROP TABLE IF EXISTS executeBatchBasic"); stmt.execute( "CREATE TABLE executeBatchBasic (t1 int not null primary key auto_increment, t2 int)"); @@ -652,7 +690,8 @@ public void executeBatchBasic() throws SQLException { stmt.clearBatch(); ret = stmt.executeBatch(); Assertions.assertArrayEquals(new int[0], ret); - + assertArrayEquals(new int[0], stmt.executeBatch()); + stmt.addBatch("INSERT INTO executeLargeBatchBasic(t2) VALUES (57)"); stmt.addBatch("WRONG QUERY"); assertThrowsContains( BatchUpdateException.class, @@ -662,7 +701,16 @@ public void executeBatchBasic() throws SQLException { @Test public void executeLargeBatchBasic() throws SQLException { - Statement stmt = sharedConn.createStatement(); + executeLargeBatchBasic(sharedConn); + try (Connection con = createCon("allowLocalInfile=true")) { + executeLargeBatchBasic(con); + } + } + + private void executeLargeBatchBasic(Connection con) throws SQLException { + Statement stmt = con.createStatement(); + assertArrayEquals(new long[0], stmt.executeLargeBatch()); + stmt.clearBatch(); stmt.execute("DROP TABLE IF EXISTS executeLargeBatchBasic"); stmt.execute( "CREATE TABLE executeLargeBatchBasic (t1 int not null primary key auto_increment, t2 int)"); @@ -678,7 +726,9 @@ public void executeLargeBatchBasic() throws SQLException { stmt.clearBatch(); ret = stmt.executeLargeBatch(); Assertions.assertArrayEquals(new long[0], ret); - + ret = stmt.executeLargeBatch(); + Assertions.assertArrayEquals(new long[0], ret); + stmt.addBatch("INSERT INTO executeLargeBatchBasic(t2) VALUES (57)"); stmt.addBatch("WRONG QUERY"); assertThrowsContains( BatchUpdateException.class, diff --git a/src/test/java/org/mariadb/jdbc/integration/codec/ClobCodecTest.java b/src/test/java/org/mariadb/jdbc/integration/codec/ClobCodecTest.java index 314184e48..950623870 100644 --- a/src/test/java/org/mariadb/jdbc/integration/codec/ClobCodecTest.java +++ b/src/test/java/org/mariadb/jdbc/integration/codec/ClobCodecTest.java @@ -743,7 +743,7 @@ private void sendParam(Connection con) throws SQLException { stmt.execute("TRUNCATE TABLE ClobParamCodec"); try (PreparedStatement prep = con.prepareStatement("INSERT INTO ClobParamCodec(t1) VALUES (?)")) { - prep.setClob(1, new MariaDbClob("ešŸŒŸ1".getBytes(StandardCharsets.UTF_8))); + prep.setClob(1, new MariaDbClob("ešŸŒŸĀ£1".getBytes(StandardCharsets.UTF_8))); prep.execute(); prep.setClob(1, (Clob) null); prep.execute(); @@ -808,7 +808,7 @@ private void sendParam(Connection con) throws SQLException { con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE) .executeQuery("SELECT * FROM ClobParamCodec"); assertTrue(rs.next()); - assertEquals("ešŸŒŸ1", rs.getString(2)); + assertEquals("ešŸŒŸĀ£1", rs.getString(2)); rs.updateClob(2, new MariaDbClob("fšŸŒŸ10".getBytes(StandardCharsets.UTF_8))); rs.updateRow(); assertEquals("fšŸŒŸ10", rs.getString(2)); diff --git a/src/test/java/org/mariadb/jdbc/unit/util/ConfigurationTest.java b/src/test/java/org/mariadb/jdbc/unit/util/ConfigurationTest.java index 472668a43..ddfdc3b8e 100644 --- a/src/test/java/org/mariadb/jdbc/unit/util/ConfigurationTest.java +++ b/src/test/java/org/mariadb/jdbc/unit/util/ConfigurationTest.java @@ -71,7 +71,7 @@ public void testUrl() throws SQLException { Configuration conf = new Configuration.Builder() .database("DB") - .addresses("local", 3306, true) + .addHost("local", 3306, true) .haMode(HaMode.REPLICATION) .build(); assertEquals( @@ -100,7 +100,7 @@ public void testUrl() throws SQLException { conf = new Configuration.Builder() .database("DB") - .addresses("local", 3306, true) + .addHost("local", 3306, true) .haMode(HaMode.REPLICATION) .socketTimeout(50) .build(); @@ -111,7 +111,33 @@ public void testUrl() throws SQLException { conf = new Configuration.Builder() .database("DB") - .addresses("local", 3306, true) + .addHost("local", 3306) + .addHost("local", 3307) + .addHost("local", 3308) + .haMode(HaMode.REPLICATION) + .socketTimeout(50) + .build(); + assertEquals( + "jdbc:mariadb:replication://address=(host=local)(port=3306)(type=primary),address=(host=local)(port=3307)(type=replica),address=(host=local)(port=3308)(type=replica)/DB?socketTimeout=50", + conf.initialUrl()); + + conf = + new Configuration.Builder() + .database("DB") + .addHost("local", 3306) + .addHost("local", 3307) + .addHost("local", 3308) + .haMode(HaMode.LOADBALANCE) + .socketTimeout(50) + .build(); + assertEquals( + "jdbc:mariadb:loadbalance://address=(host=local)(port=3306)(type=primary),address=(host=local)(port=3307)(type=primary),address=(host=local)(port=3308)(type=primary)/DB?socketTimeout=50", + conf.initialUrl()); + + conf = + new Configuration.Builder() + .database("DB") + .addHost("local", 3306, true) .haMode(HaMode.REPLICATION) .autocommit(false) .build(); @@ -429,6 +455,52 @@ public void testJdbcParserParameter() throws SQLException { assertEquals(HostAddress.from("master1", 3306, true), conf.addresses().get(0)); assertEquals(HostAddress.from("master2", 3307, true), conf.addresses().get(1)); assertEquals(HostAddress.from("slave1", 3308, false), conf.addresses().get(2)); + + url = + "jdbc:mariadb://address=(port=3306)(host=master1),address=(port=3307)" + + "(host=master2),address=(host=master3)(port=3308)/database?user=greg&password=pass"; + conf = org.mariadb.jdbc.Configuration.parse(url); + assertEquals("database", conf.database()); + assertEquals("greg", conf.user()); + assertEquals("pass", conf.password()); + assertEquals(3, conf.addresses().size()); + assertEquals(HostAddress.from("master1", 3306, true), conf.addresses().get(0)); + assertEquals(HostAddress.from("master2", 3307, true), conf.addresses().get(1)); + assertEquals(HostAddress.from("master3", 3308, true), conf.addresses().get(2)); + + url = + "jdbc:mariadb:replication://address=(port=3306)(host=master1),address=(port=3307)" + + "(host=slave1),address=(host=slave2)(port=3308)/database?user=greg&password=pass"; + conf = org.mariadb.jdbc.Configuration.parse(url); + assertEquals("database", conf.database()); + assertEquals("greg", conf.user()); + assertEquals("pass", conf.password()); + assertEquals(3, conf.addresses().size()); + assertEquals(HostAddress.from("master1", 3306, true), conf.addresses().get(0)); + assertEquals(HostAddress.from("slave1", 3307, false), conf.addresses().get(1)); + assertEquals(HostAddress.from("slave2", 3308, false), conf.addresses().get(2)); + } + + @Test + public void address() { + assertEquals("address=(host=test)(port=3306)", HostAddress.from("test", 3306).toString()); + assertEquals( + "address=(host=test)(port=3306)(type=replica)", + HostAddress.from("test", 3306, false).toString()); + assertEquals( + "address=(host=test)(port=3306)(type=primary)", + HostAddress.from("test", 3306, true).toString()); + } + + @Test + public void equal() { + HostAddress host = HostAddress.from("test", 3306); + assertEquals(host, host); + assertEquals(HostAddress.from("test", 3306), host); + assertNotEquals("", host); + + assertNotEquals(HostAddress.from("test", 3306, true), host); + assertNotEquals(HostAddress.from("test", 3306, false), host); } @Test diff --git a/src/test/java/org/mariadb/jdbc/unit/util/constant/HaModeTest.java b/src/test/java/org/mariadb/jdbc/unit/util/constant/HaModeTest.java index 082b82efe..7d58e78c6 100644 --- a/src/test/java/org/mariadb/jdbc/unit/util/constant/HaModeTest.java +++ b/src/test/java/org/mariadb/jdbc/unit/util/constant/HaModeTest.java @@ -10,6 +10,7 @@ import org.mariadb.jdbc.plugin.authentication.AuthenticationPluginLoader; import org.mariadb.jdbc.plugin.credential.CredentialPluginLoader; import org.mariadb.jdbc.plugin.tls.TlsSocketPluginLoader; +import org.mariadb.jdbc.pool.Pools; import org.mariadb.jdbc.util.CharsetEncodingLength; import org.mariadb.jdbc.util.NativeSql; import org.mariadb.jdbc.util.Security; @@ -34,6 +35,7 @@ public void instantiateStaticOnlyClass() { TlsSocketPluginLoader tp = new TlsSocketPluginLoader(); LoggerHelper lh = new LoggerHelper(); ConnectionHelper ch = new ConnectionHelper(); + Pools p = new Pools(); } @Test