-
Notifications
You must be signed in to change notification settings - Fork 41
Description
It looks like there may be a bug when trying to set socket properties. When trying to connect via JDBC to an AS400 DB2 database, I set socket timeout and thread used, however I get the following exception:
Exception in thread "main" com.ibm.as400.access.ExtendedIllegalStateException: socketProperties: Property was not changed.
at com.ibm.as400.access.AS400.setSocketProperties(AS400.java:5210)
at com.ibm.as400.access.AS400JDBCDriver.prepareConnection(AS400JDBCDriver.java:1524)
at com.ibm.as400.access.AS400JDBCDriver.prepareConnection(AS400JDBCDriver.java:1577)
at com.ibm.as400.access.AS400JDBCDriver.prepareConnection(AS400JDBCDriver.java:1447)
at com.ibm.as400.access.AS400JDBCDriver.initializeConnection(AS400JDBCDriver.java:1370)
at com.ibm.as400.access.AS400JDBCDriver.connect(AS400JDBCDriver.java:517)
at com.ibm.as400.access.AS400JDBCDriver.connect(AS400JDBCDriver.java:322)
at com.ibm.as400.access.AS400JDBCDriver.connect(AS400JDBCDriver.java:295)
at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:681)
at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:190)
at org.example.Main.main(Main.java:18)
It looks like the first time AS400JDBCDriver.prepareConnection(...) is called, it works its way through the method, correctly setting the specified socket properties. ((AS400JDBCConnection)connection).setProperties(dataSourceUrl, jdProperties, as400); calls AS400JDBCConnectionImpl.setProperties, which calls AS400.connectService(...) which calls AS400.chooseImpl() which sets propertiesFrozen_ to true. After the properties are set, the following code is executed in the prepareConnection method:
if (as400.skipSignonServer_ && !vrmSet) {
try {
Statement s = connection.createStatement();
ResultSet rs = s.executeQuery("SELECT OS_VERSION,OS_RELEASE FROM SYSIBMADM.ENVSYSINFO");
if (rs.next()) {
int version = rs.getInt(1);
int release = rs.getInt(2);
as400.setVRM(version, release, 0);
}
rs.close();
s.close();
} catch (SQLException var13) {
}
connection.close();
return this.prepareConnection(as400, dataSourceUrl, jdProperties, true);
} else {
return connection;
}The first time around this will execute the first part of the if statement, getting the OS version etc and then calling this.prepareConnection(). When this method is executed for a second time, it fails when trying to run:
if (sockProps != null) {
as400.setSocketProperties(sockProps);
}This is because, the as400.setSocketProperties method has the following check:
if (socketProperties == null) {
throw new NullPointerException("socketProperties");
} else if (this.propertiesFrozen_) {
Trace.log(2, "Cannot set socket properties after connection has been made.");
throw new ExtendedIllegalStateException("socketProperties", 5);
} else {
this.socketProperties_.copyValues(socketProperties);
}The elseif part of the code above is executed because propertiesFrozen_ is now set to true from the first execution of prepareConnection. It feels like the issue perhaps lies around this code. The comments suggest that it is known that this flow doesn't work as intended.
This bug can be reproduced by running the following code (with correct host, port, username and password):
package org.example;
import java.sql.DriverManager;
import java.util.Properties;
public class Main {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.put("user", "<username>");
properties.put("password", "<password>");
properties.put("socket timeout", "3000");
properties.put("thread used", "false");
DriverManager.getConnection("jdbc:as400://<host>:<port>", properties);
System.out.println("Connected to AS400 database");
}
}Encountered on version 21.0.6 of JTOpen.