This is an automated email from the ASF dual-hosted git repository.

terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 9ef9566bd7f Add StatementManagerTest (#38992)
9ef9566bd7f is described below

commit 9ef9566bd7feedc9dfd55f17bc456fe3f95f43dd
Author: Liang Zhang <[email protected]>
AuthorDate: Sat Jul 4 18:39:34 2026 +0800

    Add StatementManagerTest (#38992)
---
 .../jdbc/core/statement/StatementManagerTest.java  | 211 +++++++++++++++++++++
 1 file changed, 211 insertions(+)

diff --git 
a/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/StatementManagerTest.java
 
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/StatementManagerTest.java
new file mode 100644
index 00000000000..7c8cd604fd6
--- /dev/null
+++ 
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/StatementManagerTest.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.driver.jdbc.core.statement;
+
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.executor.sql.context.ExecutionUnit;
+import org.apache.shardingsphere.infra.executor.sql.context.SQLUnit;
+import 
org.apache.shardingsphere.infra.executor.sql.execute.engine.ConnectionMode;
+import 
org.apache.shardingsphere.infra.executor.sql.prepare.driver.jdbc.StatementOption;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.internal.configuration.plugins.Plugins;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.sql.Statement;
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class StatementManagerTest {
+    
+    private static final String SQL = "SELECT 1";
+    
+    private static final DatabaseType DATABASE_TYPE = 
TypedSPILoader.getService(DatabaseType.class, "SQL92");
+    
+    private static final StatementOption STATEMENT_OPTION = new 
StatementOption(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, 
ResultSet.HOLD_CURSORS_OVER_COMMIT);
+    
+    private final StatementManager statementManager = new StatementManager();
+    
+    @Test
+    void assertCreateStorageResource() throws SQLException {
+        Connection connection = mock(Connection.class);
+        Statement expected = mock(Statement.class);
+        when(connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
ResultSet.CONCUR_READ_ONLY, 
ResultSet.HOLD_CURSORS_OVER_COMMIT)).thenReturn(expected);
+        Statement actual = statementManager.createStorageResource(connection, 
ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, DATABASE_TYPE);
+        assertThat(actual, is(expected));
+    }
+    
+    @Test
+    void assertCreateStorageResourceWithCreateStatementFallback() throws 
SQLException {
+        Connection connection = mock(Connection.class);
+        Statement expected = mock(Statement.class);
+        when(connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
ResultSet.CONCUR_READ_ONLY, 
ResultSet.HOLD_CURSORS_OVER_COMMIT)).thenThrow(SQLFeatureNotSupportedException.class);
+        when(connection.createStatement()).thenReturn(expected);
+        Statement actual = statementManager.createStorageResource(connection, 
ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, DATABASE_TYPE);
+        assertThat(actual, is(expected));
+    }
+    
+    @Test
+    void assertCreateStorageResourceThrowsSQLException() throws SQLException {
+        Connection connection = mock(Connection.class);
+        SQLException expected = new SQLException("foo_error");
+        when(connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
ResultSet.CONCUR_READ_ONLY, 
ResultSet.HOLD_CURSORS_OVER_COMMIT)).thenThrow(expected);
+        SQLException actual = assertThrows(SQLException.class, () -> 
statementManager.createStorageResource(connection, 
ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, DATABASE_TYPE));
+        assertThat(actual, is(expected));
+    }
+    
+    @Test
+    void assertCreateStorageResourceWithExecutionUnit() throws SQLException {
+        Connection connection = mock(Connection.class);
+        PreparedStatement expected = mockPreparedStatement(connection);
+        Statement actual = 
statementManager.createStorageResource(createExecutionUnit(), connection, 0, 
ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, DATABASE_TYPE);
+        assertThat(actual, is(expected));
+    }
+    
+    @Test
+    void assertCreateStorageResourceWithPrepareStatementFallback() throws 
SQLException {
+        Connection connection = mock(Connection.class);
+        PreparedStatement expected = mock(PreparedStatement.class);
+        when(connection.prepareStatement(SQL, ResultSet.TYPE_FORWARD_ONLY, 
ResultSet.CONCUR_READ_ONLY, 
ResultSet.HOLD_CURSORS_OVER_COMMIT)).thenThrow(SQLFeatureNotSupportedException.class);
+        when(connection.prepareStatement(SQL)).thenReturn(expected);
+        Statement actual = 
statementManager.createStorageResource(createExecutionUnit(), connection, 0, 
ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, DATABASE_TYPE);
+        assertThat(actual, is(expected));
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("generatedKeysOptions")
+    void assertCreateStorageResourceWithGeneratedKeys(final String name, final 
Connection connection, final StatementOption option, final PreparedStatement 
expected) throws SQLException {
+        Statement actual = 
statementManager.createStorageResource(createExecutionUnit(), connection, 0, 
ConnectionMode.CONNECTION_STRICTLY, option, DATABASE_TYPE);
+        assertThat(actual, is(expected));
+    }
+    
+    @Test
+    void assertCreateStorageResourceWithCachedStatement() throws SQLException {
+        Connection connection = mock(Connection.class);
+        ExecutionUnit executionUnit = createExecutionUnit();
+        PreparedStatement expected = mockPreparedStatement(connection);
+        when(expected.getConnection()).thenReturn(connection);
+        when(connection.isClosed()).thenReturn(false);
+        when(expected.isClosed()).thenReturn(false);
+        Statement actual = 
statementManager.createStorageResource(executionUnit, connection, 0, 
ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, DATABASE_TYPE);
+        assertThat(actual, is(expected));
+        assertThat(statementManager.createStorageResource(executionUnit, 
connection, 0, ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, 
DATABASE_TYPE), is(expected));
+    }
+    
+    @Test
+    void assertCreateStorageResourceWhenCachedConnectionClosed() throws 
SQLException {
+        Connection connection = mock(Connection.class);
+        PreparedStatement cached = mock(PreparedStatement.class);
+        PreparedStatement expected = mock(PreparedStatement.class);
+        when(connection.prepareStatement(SQL, ResultSet.TYPE_FORWARD_ONLY, 
ResultSet.CONCUR_READ_ONLY, 
ResultSet.HOLD_CURSORS_OVER_COMMIT)).thenReturn(cached, expected);
+        when(cached.getConnection()).thenReturn(connection);
+        when(connection.isClosed()).thenReturn(true);
+        ExecutionUnit executionUnit = createExecutionUnit();
+        assertThat(statementManager.createStorageResource(executionUnit, 
connection, 0, ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, 
DATABASE_TYPE), is(cached));
+        assertThat(statementManager.createStorageResource(executionUnit, 
connection, 0, ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, 
DATABASE_TYPE), is(expected));
+    }
+    
+    @Test
+    void assertCreateStorageResourceWhenCachedStatementClosed() throws 
SQLException {
+        Connection connection = mock(Connection.class);
+        PreparedStatement cached = mock(PreparedStatement.class);
+        PreparedStatement expected = mock(PreparedStatement.class);
+        when(connection.prepareStatement(SQL, ResultSet.TYPE_FORWARD_ONLY, 
ResultSet.CONCUR_READ_ONLY, 
ResultSet.HOLD_CURSORS_OVER_COMMIT)).thenReturn(cached, expected);
+        when(cached.getConnection()).thenReturn(connection);
+        when(connection.isClosed()).thenReturn(false);
+        when(cached.isClosed()).thenReturn(true);
+        ExecutionUnit executionUnit = createExecutionUnit();
+        assertThat(statementManager.createStorageResource(executionUnit, 
connection, 0, ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, 
DATABASE_TYPE), is(cached));
+        assertThat(statementManager.createStorageResource(executionUnit, 
connection, 0, ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, 
DATABASE_TYPE), is(expected));
+    }
+    
+    @Test
+    void assertClose() throws SQLException, ReflectiveOperationException {
+        Connection connection = mock(Connection.class);
+        PreparedStatement statement = mockPreparedStatement(connection);
+        
assertThat(statementManager.createStorageResource(createExecutionUnit(), 
connection, 0, ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, 
DATABASE_TYPE), is(statement));
+        statementManager.close();
+        assertTrue(getCachedStatements().isEmpty());
+    }
+    
+    @Test
+    void assertCloseWithSQLException() throws SQLException, 
ReflectiveOperationException {
+        Connection connection = mock(Connection.class);
+        PreparedStatement statement = mockPreparedStatement(connection);
+        SQLException expected = new SQLException("foo_error");
+        doThrow(expected).when(statement).close();
+        
assertThat(statementManager.createStorageResource(createExecutionUnit(), 
connection, 0, ConnectionMode.CONNECTION_STRICTLY, STATEMENT_OPTION, 
DATABASE_TYPE), is(statement));
+        SQLException actual = assertThrows(SQLException.class, 
statementManager::close);
+        assertThat(actual.getNextException(), is(expected));
+        assertTrue(getCachedStatements().isEmpty());
+    }
+    
+    private PreparedStatement mockPreparedStatement(final Connection 
connection) throws SQLException {
+        PreparedStatement result = mock(PreparedStatement.class);
+        when(connection.prepareStatement(SQL, ResultSet.TYPE_FORWARD_ONLY, 
ResultSet.CONCUR_READ_ONLY, 
ResultSet.HOLD_CURSORS_OVER_COMMIT)).thenReturn(result);
+        return result;
+    }
+    
+    private static Stream<Arguments> generatedKeysOptions() throws 
SQLException {
+        PreparedStatement generatedKeysStatement = 
mock(PreparedStatement.class);
+        PreparedStatement emptyColumnsStatement = 
mock(PreparedStatement.class);
+        PreparedStatement columnsStatement = mock(PreparedStatement.class);
+        String[] columns = {"id"};
+        return Stream.of(
+                Arguments.of("generated keys", 
mockGeneratedKeysConnection(generatedKeysStatement), new StatementOption(true), 
generatedKeysStatement),
+                Arguments.of("generated keys with empty columns", 
mockGeneratedKeysConnection(emptyColumnsStatement), new StatementOption(true, 
new String[0]), emptyColumnsStatement),
+                Arguments.of("generated keys with columns", 
mockGeneratedKeysConnection(columnsStatement, columns), new 
StatementOption(true, columns), columnsStatement));
+    }
+    
+    private static Connection mockGeneratedKeysConnection(final 
PreparedStatement statement) throws SQLException {
+        Connection result = mock(Connection.class);
+        when(result.prepareStatement(SQL, 
Statement.RETURN_GENERATED_KEYS)).thenReturn(statement);
+        return result;
+    }
+    
+    private static Connection mockGeneratedKeysConnection(final 
PreparedStatement statement, final String[] columns) throws SQLException {
+        Connection result = mock(Connection.class);
+        when(result.prepareStatement(SQL, columns)).thenReturn(statement);
+        return result;
+    }
+    
+    private ExecutionUnit createExecutionUnit() {
+        return new ExecutionUnit("foo_ds", new SQLUnit(SQL, 
Collections.emptyList()));
+    }
+    
+    @SuppressWarnings("unchecked")
+    private Map<?, Statement> getCachedStatements() throws 
ReflectiveOperationException {
+        return (Map<?, Statement>) 
Plugins.getMemberAccessor().get(StatementManager.class.getDeclaredField("cachedStatements"),
 statementManager);
+    }
+}

Reply via email to