I am currentliy experimenting with the native-image tool from GraalVM and the Oracle-driver. The source code compiles and generates an exe File without errors. But when I start the program it gets a java.lang.RuntimeException: Missing character set id 170 not loaded at image build time.
I am connecting to a database with characterset NLS_CHARACTERSET = EE8MSWIN1250.
When I use a database with NLS_CHARACTERSET = AL32UTF8 the connection works fine.
I am using GraalVM CE 21.0.0.2 (build 11.0.10+8-jvmci-21.0-b06 and ojdbc11-21.1.0.0.jar on a Windows 10 64bit Computer.
Below ist the error message and the source code. I used the sample code from https://github.com/oracle/oracle-db-examples/blob/master/java/jdbc/ConnectionSamples/DataSourceSample.java
Exception in thread "main" java.lang.RuntimeException: Missing character set id 170 not loaded at image build time at oracle.sql.CharacterSet.make(CharacterSet.java:121) at oracle.jdbc.driver.DBConversion.init(DBConversion.java:184) at oracle.jdbc.driver.DBConversion.(DBConversion.java:137) at oracle.jdbc.driver.T4CConnection.doCharSetNegotiation(T4CConnection.java:2607) at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:2176) at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:644) at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:1069) at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:90) at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:681) at oracle.jdbc.datasource.impl.OracleDataSource.getPhysicalConnection(OracleDataSource.java:569) at oracle.jdbc.datasource.impl.OracleDataSource.getConnection(OracleDataSource.java:355) at oracle.jdbc.datasource.impl.OracleDataSource.getConnectionInternal(OracleDataSource.java:2014) at oracle.jdbc.datasource.impl.OracleDataSource.getConnection(OracleDataSource.java:330) at oracle.jdbc.datasource.impl.OracleDataSource.getConnection(OracleDataSource.java:291) at DataSourceSample.main(DataSourceSample.java:24)
DataSourceSample.java
/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.*/
import java.sql.SQLException;
import java.util.Properties;
import oracle.jdbc.pool.OracleDataSource;
import oracle.jdbc.OracleConnection;
import java.sql.DatabaseMetaData;
public class DataSourceSample {
final static String DB_URL= "jdbc:oracle:thin:#****:1525/****";
final static String DB_USER = "****";
final static String DB_PASSWORD = "****";
public static void main(String args[]) throws SQLException {
Properties info = new Properties();
info.put(OracleConnection.CONNECTION_PROPERTY_USER_NAME, DB_USER);
info.put(OracleConnection.CONNECTION_PROPERTY_PASSWORD, DB_PASSWORD);
info.put(OracleConnection.CONNECTION_PROPERTY_DEFAULT_ROW_PREFETCH, "20");
OracleDataSource ods = new OracleDataSource();
ods.setURL(DB_URL);
ods.setConnectionProperties(info);
try (OracleConnection connection = (OracleConnection) ods.getConnection()) {
DatabaseMetaData dbmd = connection.getMetaData();
System.out.println("Driver Name: " + dbmd.getDriverName());
System.out.println("Driver Version: " + dbmd.getDriverVersion());
System.out.println("Default Row Prefetch Value is: " +
connection.getDefaultRowPrefetch());
System.out.println("Database Username is: " + connection.getUserName());
System.out.println();
}
}
}
I'm not 100% sure that it's the culprit, but here's the general idea about native image and charsets.
Native image doesn't include all possible charsets by default, you can configure it to do so by using the following option:
-H:+AddAllCharsets
Another possible option is to initialize the CharSet onject in a class that is configured to be initialized at build time of the native image. Then the charset object will be saved in the "image heap" and will be available at runtime.
Here's a sample application that illustrates this behavior: https://github.com/shelajev/workshop/tree/main/3
Of course it might be something different, but I think this should solve the problem you're experiencing.
with HikariCP it is possible to change Username and Password of the whole pool at runtime. You only have to set a poolName and set registerMbeans to true during the creation of the pool.
At runtime you could then use MXBeanProxy to change Username and password at runtime. It looks like this:
public void changeUser(HikariDataSource ds, String newUser, String newPassword) {
HikariConfigMXBean configBean = ds.getHikariConfigMXBean();
configBean.setUsername(user);
configBean.setPassword(password);
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName poolName= new ObjectName("com.zaxxer.hikari:type=Pool (" + dbKey + ")");
HikariPoolMXBean poolProxy = JMX.newMXBeanProxy(mBeanServer, poolName,
HikariPoolMXBean.class);
poolProxy.softEvictConnections();
}
But now I search some similar code for the Tomcat Connection Pool. Or another method to change username and password of Tomcat Connection Pool at runtime.
I hope somebody have an idea.
Since ConnectionCaching ist deprecated in ojdbc now, i would like to use the Oracle Universal Connection Pool.
The Problem here is that i need to to obtain a oracle.jdbc.OracleConnection from it. I tried casting and unwrapping but i does not work. How do i get one?
I need the OracleConnection.createARRAY() Method to call a stored Procedure.
From the api docs, if you are getting an instance of UniversalPooledConnection the underlying connection can be obtained from getPhysicalConnection:
getPhysicalConnection
java.lang.Object getPhysicalConnection()
Gets the physical connection
that this UniversalPooledConnection decorates.
Returns: The physical
connection. Never null.
Thanks #6ton. I made it like this:
/* missing all error handling and resource management*/
universalConnectionPoolManager = UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager();
poolDataSource = PoolDataSourceFactory.getPoolDataSource();
// setting up dataSource ....
poolDataSource.setConnectionPoolName(NAME);
universalConnectionPoolManager.createConnectionPool((UniversalConnectionPoolAdapter) poolDataSource);
universalConnectionPoolManager.startConnectionPool(NAME);
universalConnectionPool = universalConnectionPoolManager.getConnectionPool(NAME);
universalPooledConnection = universalConnectionPool.borrowConnection(universalConnectionPool.getConnectionRetrievalInfo());
physicalConnection = universalPooledConnection.getPhysicalConnection();
oracleConn = (OracleConnection) physicalConnection;
// ... query stuff
universalPooledConnection.heartbeat();
universalConnectionPool.returnConnection(universalPooledConnection);
universalConnectionPoolManager.destroyConnectionPool(NAME);
You can get the OracleConnection by using the unwrap method as shown below.
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
pds.setURL("jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(HOST=localhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=myorcldbservice)))");
pds.setUser("hr");
pds.setPassword("hr");
pds.setConnectionPoolName("JDBC_UCP_POOL");
pds.setInitialPoolSize(5);
pds.setMinPoolSize(5);
pds.setMaxPoolSize(10);
try (Connection conn = pds.getConnection()) {
OracleConnection oc = conn.unwrap(OracleConnection.class);
} catch (SQLException e) {
System.out.println("UCPSample - SQLException occurred : " + e.getMessage());
}
This question is related to Resque Mysql2::Error: User has exceeded the 'max_user_connections' resource (current value: 10)
I'm receiving the error "(User has exceeded the 'max_user_connections' resource (current value: 10))" when trying to insert a table into a MySql database.
I'm using this code to connect to the database :
#Configuration
public class MainConfig {
#Bean
public BasicDataSource dataSource() throws URISyntaxException {
URI dbUri = new URI(System.getenv("DATABASE_URL"));
String username = dbUri.getUserInfo().split(":")[0];
String password = dbUri.getUserInfo().split(":")[1];
String dbUrl = "jdbc:postgresql://" + dbUri.getHost() + ':' + dbUri.getPort() + dbUri.getPath();
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setUrl(dbUrl);
basicDataSource.setUsername(username);
basicDataSource.setPassword(password);
return basicDataSource;
}
}
whch is based on :
https://devcenter.heroku.com/articles/connecting-to-relational-databases-on-heroku-with-java#using-the-database_url-in-plain-jdbc
To fix this issue can I re-use this connection ?
I've tried updating the code above to re-use the same BasicDataSource but I receive error.
When I check the client connections here is what I see :
The amount of client connection decreases over time, it seems there is max number of connection that can be made within a specified time span ?
I may be wrong but I believe it is the database its self telling you that you have reached the limit. You can change it in the database options.
For a project I was working we used a connection pool and had a limit of 110 connections. This was based on a small size of users though.
Why java.sql.Connection cannot be cast to oracle.jdbc.OracleConnection in code below?
My main goal is to pass to Oracle connection new user name and save it in 'SESSION' table in for example 'osuser' column because I want to trace in DB user changes and display it in the table.
#Repository
public class AuditLogDAOImpl implements AuditLogDAO {
#PersistenceContext(unitName="myUnitName")
EntityManager em;
#Resource(name = "dataSource")
DataSource dataSource;
public void init() {
try {
Connection connection = DataSourceUtils.getConnection(dataSource);
OracleConnection oracleConnection = (OracleConnection) connection; //Here I got cast exception!
String metrics[] = new String[OracleConnection.END_TO_END_STATE_INDEX_MAX];
metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = "my_new_username";
oracleConnection.setEndToEndMetrics(metrics, (short) 0);
java.util.Properties props = new java.util.Properties();
props.put("osuser", "newValue");
oracleConnection.setClientInfo(props);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Here is error log:
10:42:29,251 INFO [STDOUT] org.jboss.resource.adapter.jdbc.jdk6.WrappedConnectionJDK6#bcc8cb
10:42:51,701 ERROR [STDERR] java.lang.ClassCastException: $Proxy286 cannot be cast to oracle.jdbc.OracleConnection
Generally I have 2 problem in this case:
why cast from Connection to OracleConnection fails and
what is the best way to implement my intend (I mean set the new user name to v$session.osuser in Oracle DB?
I work with Oracle 11g, Hibernate (using entity manager), data source via jndi.
Please help, thanks!
EDIT:
After some improvement the problem with casting still exists.
Improvement:
Connection connection = DataSourceUtils.getConnection(dataSource);
connection = ((org.jboss.resource.adapter.jdbc.WrappedConnection)connection).getUnderlyingConnection();
OracleConnection oracleConnection = (OracleConnection) connection;
Error:
java.lang.ClassCastException: $Proxy287 cannot be cast to org.jboss.resource.adapter.jdbc.WrappedConnection
The connection you are retrieving is probably a wrapped connection.
If you really need to get the underlying Oracle connection you should use:
if (connection.isWrapperFor(OracleConnection.class)){
OracleConnection oracleConnection= connection.unwrap(OracleConnection.class);
}else{
// recover, not an oracle connection
}
The isWrapperFor and unwrap methods are available since Java 1.6, and should be meaningfully implemented by the A/S connection wrappers.
The connection pool usually has a wrapper around the real connection instance, that's why your cast fails.
What you are doing wouldn't work anyway, because the parameters in the properties instance are only checked when the connection is established. As you have a connection that is already active, it won't change anything.
You need tou use DBMS_APPLICATION_INFO.SET_CLIENT_INFO() in order to change this for an existing connection.
This is just for people who come here via search on how to set metrics in OracleConnection, I spend great deal of time on this, so might help someone.
After you get your "connection" this should work:
DatabaseMetaData dmd = connection.getMetaData();
Connection metaDataConnection = null;
if(dmd != null)
{
metaDataConnection = dmd.getConnection();
}
if(!(metaDataConnection instanceof OracleConnection))
{
log.error("Connection is not instance of OracleConnection, returning");
return; /* Not connection u want */
}
OracleConnection oraConnection = (OracleConnection)metaDataConnection;
String[] metrics = new String[END_TO_END_STATE_INDEX_MAX]; // Do the rest below...
It works for me for OracleConnection, but I face diff issue when setting metrics:
short zero = 0;
oraConnection.setEndToEndMetrics(metrics, zero);
After proxying connection via my method where I set metrics few times, I get:
java.sql.SQLRecoverableException: No more data to read from socket
But I think it has to do with some Spring wiring inits or connection pool.
i had faced this issue when using spring to get connections. Typically , each layer adds a wrapper over the basic classes. i had just done connection.getClass().getName() to see the runtime type of the connection being retuned. It will be a Wrapper/proxy over which you can easily find the method to get the base OracleConnection type.
Try the following
I had encountered the same issue. We were using spring and it has a class called
NativeJdbcExtractor. It has many implementations and the following one works for TomCat. There is a specific implementation for Jboss called the JBossNativeJdbcExtractor
<bean id="jdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"></bean>
In your DAO you can inject the bean and use the following method
protected NativeJdbcExtractor jdbcExtractor;
Connection conn=jdbcExtractor.getNativeConnection(oracleConnection);
You can access the inner OracleObject inside a Wrapper, in this case the wrapper
type is NewProxyConnection:
( I've used it in my project, it Worked ...no mistery, just use reflection)
Field[] fieldsConn= connection.getClass().getDeclaredFields();
Object innerConnObject = getFieldByName(fieldsConn,"inner").get(connection);
if(innerConnObject instanceof OracleConnection ){
OracleConnection oracleConn = (OracleConnection)innerConnObject;
//OracleConnection unwrap = ((OracleConnection)innerConnObject).unwrap();
// now you have the OracleObject that the Wrapper
}
//Method: Set properties of the ooject accessible.
public static Field getFieldByName(Field[] campos, String name) {
Field f = null;
for (Field campo : campos) {
campo.setAccessible(true);
if (campo.getName().equals(name)) {
f = campo;
break;
}
}
return f;
}
Not sure if my situation is related, but with my project, simply changing a database configuration setting actually causes unwrap to fail!
I'm using the Play framework with Scala; this works for me only when logSql=false:
db.withConnection { implicit c =>
val oracleConnection = c.unwrap(classOf[OracleConnection])
}
(this is just the Scala version of unwrapping an OracleConnection)
When I set logSql=true, I get:
com.sun.proxy.$Proxy17 cannot be cast to oracle.jdbc.OracleConnection
java.lang.ClassCastException: com.sun.proxy.$Proxy17 cannot be cast to
oracle.jdbc.OracleConnection
So something about the logSql configuration can actually cause unwrap to fail. No idea why.
With either configuration, my connection object is:
HikariProxyConnection#1880261898 wrapping
oracle.jdbc.driver.T4CConnection#6b28f065
isWrapperFor(OracleConnection) is true in both cases
This happens with Hikari Connection Pool and Bone CP. Maybe it's a bug in Oracle JDBC?
Oracle JDBC Driver version according to MANIFEST.MF
Implementation-Version: 11.2.0.3.0
Repository-Id: JAVAVM_11.2.0.4.0_LINUX.X64_130711
After trial and error.
This way works:
DelegatingConnection delConnection = new DelegatingConnection(dbcpConnection);
oraConnection = (oracle.jdbc.OracleConnection)delConnection.getInnermostDelegate();
But this way returned a null pointer for oraConnection:
DelegatingConnection delConnection = (DelegatingConnection) dbcpConnection;
oraConnection = (oracle.jdbc.OracleConnection)delConnection.getInnermostDelegate();
The following worked to get around AQ's TopicConnection.getTopicSession => JMS-112
//DEBUG: Native DataSource : weblogic.jdbc.common.internal.RmiDataSource
con = DataSource.getConnection();
debug("Generic SQL Connection: " + con.toString());
//DEBUG: Generic Connection: weblogic.jdbc.wrapper.PoolConnection_oracle_jdbc_driver_T4CConnection
if (con != null && con.isWrapperFor(OracleConnection.class)) {
WebLogicNativeJdbcExtractor wlne = new WebLogicNativeJdbcExtractor();//org.springframework to the rescue!!
java.sql.Connection nativeCon = wlne.getNativeConnection(con);
this.oraConnection = (OracleConnection) nativeCon;
debug("Unwrapp SQL Connection: " + this.oraConnection.toString());
}
//DEBUG: Native Connection: oracle.jdbc.driver.T4CConnection รจ
Now I could use this in the AQ-Factory w/o JMS-112
try casting like below
WrappedConnectionJDK6 wc = (WrappedConnectionJDK6) connection;
connection = wc.getUnderlyingConnection();