We are trying to perform a simple POC to make use of the CQN feature with ADW and ATP. We are following the walkthrough example available at :
https://docs.oracle.com/en/
database/oracle/oracle-database/19/jjdbc/continuos-query-notification.html#GUID-17D0D7C5-77C9-420D-9D13-F668C1056792
When we run the following JAVA code, Database change registrations are getting created properly. We can see them getting created in USER_CHANGE_NOTIFICATION_REGS table . But we are not receiving any object change notifications.
Similar database setup and JAVA code works perfectly with oracle 19c Database installed locally. And we are receiving the notifications.
The ADW instance that we are using has been configured with Access type as Allow secure access from everywhere using mTLS authentication. Please let us know if you need more info about the ADW instance.
Database setup:
We used the administrator user to connect to the ADW instance and created another user, granted the CHANGE NOTIFICATION priviliges and created a test table for trying out the object change notification on it using this SQL
/* creating user and granting priviliges */
CREATE USER MAXTEST IDENTIFIED BY ********
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp
QUOTA UNLIMITED ON users;
GRANT CONNECT, CREATE TABLE, CREATE PROCEDURE, CREATE SEQUENCE TO MAXTEST;
GRANT CHANGE NOTIFICATION TO MAXTEST;
GRANT EXECUTE ON DBMS_CHANGE_NOTIFICATION TO MAXTEST;
/* creating table to be used for object change notification */
CREATE TABLE t1 (
id NUMBER,
description VARCHAR2(50),
CONSTRAINT t1_pk PRIMARY KEY (id)
);
INSERT INTO t1 (id, description) VALUES (1, 'One');
INSERT INTO t1 (id, description) VALUES (2, 'Two');
COMMIT;
JAVA code which works with locally installed oracle DB but now with ADW:
package com.oracle;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleDriver;
import oracle.jdbc.OracleStatement;
import oracle.jdbc.dcn.DatabaseChangeEvent;
import oracle.jdbc.dcn.DatabaseChangeListener;
import oracle.jdbc.dcn.DatabaseChangeRegistration;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DBChangeNotification
{
static final String USERNAME= "MAXTEST";
static final String PASSWORD= "********";
static String URL = "jdbc:oracle:thin:@phxdd1maxdldbpoc_high?TNS_ADMIN=/path/to/downloaded/wallet";
// static String URL = "jdbc:oracle:thin:@localhost:1521/ORCLCDB";
public static void main(String[] argv)
{
DBChangeNotification demo = new DBChangeNotification();
try
{
demo.run();
}
catch(SQLException mainSQLException )
{
mainSQLException.printStackTrace();
}
}
void run() throws SQLException
{
OracleConnection conn = connect();
Properties prop = new Properties();
prop.setProperty(OracleConnection.DCN_CLIENT_INIT_CONNECTION, "true");
prop.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS,"true");
DatabaseChangeRegistration dcr = conn.registerDatabaseChangeNotification(prop);
try
{
// add the listener:
DCNDemoListener list = new DCNDemoListener();
dcr.addListener(list);
// second step: add objects in the registration:
Statement stmt = conn.createStatement();
// associate the statement with the registration:
((OracleStatement)stmt).setDatabaseChangeRegistration(dcr);
ResultSet rs = stmt.executeQuery("select * from T1");
while (rs.next())
{}
System.out.println("Username is " + dcr.getUserName());
String[] tableNames = dcr.getTables();
for(int i=0;i<tableNames.length;i++)
System.out.println(tableNames[i]+" is part of the registration.");
rs.close();
stmt.close();
}
catch(SQLException ex)
{
// if an exception occurs, we need to close the registration in order
// to interrupt the thread otherwise it will be hanging around.
if(conn != null)
conn.unregisterDatabaseChangeNotification(dcr);
throw ex;
}
finally
{
try
{
// Note that we close the connection!
conn.close();
}
catch(Exception innerex){ innerex.printStackTrace(); }
}
// create an infinite loop to keep the application running and wait for notification
try {
while (true) {
System.out.println("Waiting Notifications");
Thread.sleep(5000);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
OracleConnection conn3 = connect();
conn3.unregisterDatabaseChangeNotification(dcr);
conn3.close();
}
}
/**
* Creates a connection the database.
*/
OracleConnection connect() throws SQLException
{
OracleDriver dr = new OracleDriver();
Properties prop = new Properties();
prop.setProperty("user", DBChangeNotification2.USERNAME);
prop.setProperty("password", DBChangeNotification2.PASSWORD);
return (OracleConnection)dr.connect(DBChangeNotification2.URL,prop);
}
}
/**
* DCN listener: it prints out the event details in stdout.
*/
class DCNDemoListener implements DatabaseChangeListener
{
public void onDatabaseChangeNotification(DatabaseChangeEvent e)
{
Thread t = Thread.currentThread();
System.out.println("DCNDemoListener: got an event ("+this+" running on thread "+t+")");
System.out.println(e.getEventType().toString());
System.out.println(e.toString());
}
}
When the application is running, I execute the following SQL to insert an entry in the table which is part being tracked by the registration.
INSERT INTO t1 VALUES (3, 'Three');
COMMIT;
Output when we run by connecting with the ADW instance - No notification received:
Username is MAXTEST
MAXTEST.T1 is part of the registration.
Waiting Notifications
Waiting Notifications
Waiting Notifications
Waiting Notifications
Waiting Notifications
Waiting Notifications
...
Output when connected with the local oracle 19c DB - Notification is received:
Username is MAXTEST
MAXTEST.T1 is part of the registration.
Waiting Notifications
Waiting Notifications
Waiting Notifications
Waiting Notifications
Waiting Notifications
DCNDemoListener: got an event (com.oracle.DCNDemoListener@4afd2e2f running on thread Thread[Thread-1,5,main])
OBJCHANGE
Registration ID : 1269
Notification version : 1
Event type : OBJCHANGE
Database name : ORCLCDB
Table Change Description (length=1)
operation=[INSERT], tableName=MAXTEST.T1, objectNumber=73636
Row Change Description (length=1):
ROW: operation=INSERT, ROWID=AAAR+kAAHAAAAFfAAA
Waiting Notifications
Waiting Notifications
...
Does this feature work with ADW/ATP ?
Are there any other configuration properties that should be setup when working with ADW ?
Is there something that we are missing here?
I had a chat to the PMs on this.
Currently *client* initiated CQN is supported on Autonomous
As per the docs:
To create a CQN registration, you can use either the PL/SQL interface or Oracle Call Interface (OCI). If you use the PL/SQL interface, the notification handler is a server-side PL/SQL stored procedure; if you use OCI, the notification handler is a client-side C callback procedure.
this means via OCI callback, so I suspect you might need to use a thick OCI-based driver for this.