Community
Participate
Working Groups
Build Identifier: EclipseLink, version: Eclipse Persistence Services - 2.1.1.v20100817-r8050 Hi, I am trying to collect all insert, update and delete queries within a transaction. I have extended the DescriptorEventAdapter and try to capute the queries through overriding the postInsert, postUpdate and postDelete method. I am interested in the SQL + the parameters. My goal is some kind of transaction capture. So I am able to replay the transaction on another machine with writes exactly the same data into another database (schema is going to be the same). After a few tests I could see the following behaviour: First Call is: SQLCall(INSERT INTO HASHNODE (LEAF, VERSIONSNUMMER, HASH_DOKUMENT, HASH_TREENODE, HASH_ZEITSTEMPELKETTE, ZAEHLER, UUID, PARENT_UUID, DOKINFO_UUID, BAUM_UUID, ZEITSTEMPEL_UUID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)) which seems ok. Second call is according to event->query->queryMechanism->call: SQLCall(INSERT INTO HASHBAUM (ERSTELLT, HASHVERFAHREN, FINALISIERT, KARDINALITAET, VERSIONSNUMMER, UUID, RETIMESTAMP_UUID, ROOT_UUID, STAMTGRUPPE_UUID, REHASH_UUID, HASHBAUM_TYP) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)) with a event->query->modifyRow of DatabaseRecord( HASHBAUM.KARDINALITAET => 100 HASHBAUM.FINALISIERT => 2011-03-08 20:27:10.814 HASHBAUM.ERSTELLT => 2011-03-08 20:27:09.539 HASHBAUM.ROOT_UUID => 100f55a0-49ba-11e0-8234-00247e1610fe HASHBAUM.VERSIONSNUMMER => 1 HASHBAUM.HASHVERFAHREN => 2.16.840.1.101.3.4.2.1 HASHBAUM.STAMTGRUPPE_UUID => 3c2ed210-4969-11e0-a827-00247e1610fe) whereas the issued query on the database is EL Fine]: ClientSession(21702188)--Connection(12003823)--UPDATE HASHBAUM SET KARDINALITAET = ?, FINALISIERT = ?, ERSTELLT = ?, ROOT_UUID = ?, VERSIONSNUMMER = ?, HASHVERFAHREN = ?, STAMTGRUPPE_UUID = ? WHERE (UUID = ?) bind => [100, 2011-03-08 20:27:10.814, 2011-03-08 20:27:09.539, 100f55a0-49ba-11e0-8234-00247e1610fe, 1, 2.16.840.1.101.3.4.2.1, 3c2ed210-4969-11e0-a827-00247e1610fe, 0f96a330-49ba-11e0-8234-00247e1610fe] In effect this means that the executed call is another than the carried on in the queryMechanism object. But what I am not able to understand is why are the parameters right (the given parameters are not working with the INSERT query) Is this the right behaviour? Shouldn't event->query->queryMechanism->call be "UPDATE HASHBAUM SET KARDINALITAET = ?, FINALISIERT = ?, ERSTELLT = ?, ROOT_UUID = ?, VERSIONSNUMMER = ?, HASHVERFAHREN = ?, STAMTGRUPPE_UUID = ? WHERE (UUID = ?)"? I am using EclipseLink 2.1.1 (JPA) with Oracle WebLogic 10.3.3 Reproducible: Always
The following session-event-listener can capture all SQL without the parameter binding. Using some additional conditions on the query type the INSERT/UPDATE/DELETE within a TXN could be captured. public class SQLCaptureListener extends SessionEventAdapter { @Override public void postExecuteQuery(SessionEvent event) { DatabaseQuery query = (DatabaseQuery) event.getQuery(); String sql = query.getTranslatedSQLString(event.getSession(), query.getTranslationRow()); System.out.println("SQL: " + sql); } }
Here is a transactional example that captures all modify SQL in a UnitOfWork and logs it at the end. /** * Capture the modify SQL statements within a transaction and log them at the * end. * * @author dclarke * @since EclipseLink 2.2 */ public class CaptureTransactionSQL extends SessionEventAdapter { private static final String PROPERTY = CaptureTransactionSQL.class.getName(); @Override public void postExecuteQuery(SessionEvent event) { DatabaseQuery query = (DatabaseQuery) event.getQuery(); if (query.isModifyQuery() && event.getSession().isUnitOfWork()) { String sql = query.getTranslatedSQLString(event.getSession(), query.getTranslationRow()); getSQLStrings(event.getSession()).add(sql); } } @SuppressWarnings("unchecked") private List<String> getSQLStrings(Session session) { if (!session.getProperties().containsKey(PROPERTY)) { session.setProperty(PROPERTY, new ArrayList<String>()); } return (List<String>) session.getProperty(PROPERTY); } /** * Log the SQL statements. This could alternatively store them. */ @Override public void postCommitUnitOfWork(SessionEvent event) { System.out.println("POST COMMIT - LOG SQL:"); for (String sql : getSQLStrings(event.getSession())) { System.out.println("\t> " + sql); } } }
This fails when the query has arguments. I believe another fix is required for that but may be fine for what you described.
Thanks a lot for the quick response! I think that I have identified another problem. In the method ExpressionQueryMechanism(DatabaseQueryMechanism).insertObjectForWrite() the method updateForeignKeyFieldAfterInsert(WriteObjectQuery) is called. In which a new SQLUpdateStatement is created. After the creation of the statement the modifyRow of the previous InsertObjectQuery is set to the new SQLUpdateStatement-ModifyRow whereas the SQLCall is not replaced (See below). I think that the SQLCall should also be replaced. I think this is the reason for the previously described bug (The same code seems to be in the trunk version of EL). Current code in updateForeignKeyFieldAfterInsert(WriteObjectQuery): ... StatementQueryMechanism updateMechanism = new StatementQueryMechanism(writeQuery, updateStatement); writeQuery.setModifyRow(updateStatement.getModifyRow()); updateMechanism.updateObject(); ... Possible fix for updateForeignKeyFieldAfterInsert(WriteObjectQuery): ... StatementQueryMechanism updateMechanism = new StatementQueryMechanism(writeQuery, updateStatement); writeQuery.setModifyRow(updateStatement.getModifyRow()); // possible fix?? the new DatabaseSessionImpl() is also used in the toString() // of the class SQLStatement. Perhaps annother Session can be used writeQuery.setCall(updateStatement .buildCall( new DatabaseSessionImpl( new org.eclipse.persistence.sessions.DatabaseLogin() ) ); updateMechanism.updateObject(); ...
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink