Skip to content

Commit 0775dcd

Browse files
Fix createBackfillRevision to dynamically discover timestamp column name
1 parent fdf4ec8 commit 0775dcd

File tree

1 file changed

+35
-3
lines changed

1 file changed

+35
-3
lines changed

api/src/main/java/org/openmrs/util/EnversAuditTableInitializer.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,16 +222,18 @@ private static Integer tryBackfillEntity(Connection connection, String sourceTab
222222
}
223223

224224
/**
225-
* Creates a backfill revision entry in the revision entity table. Uses the REVTSTMP column which is
226-
* explicitly defined in Hibernate's RevisionMapping with @Column(name = "REVTSTMP").
225+
* Creates a backfill revision entry in the revision entity table. Dynamically discovers the
226+
* timestamp column name from JDBC metadata to avoid hardcoding Hibernate-version-specific names.
227227
*
228228
* @param connection JDBC connection
229229
* @param revisionTableName name of the revision entity table
230230
* @return the generated revision ID
231231
* @throws SQLException if the revision entry cannot be created
232232
*/
233233
static int createBackfillRevision(Connection connection, String revisionTableName) throws SQLException {
234-
String sql = "INSERT INTO " + requireSafeIdentifier(revisionTableName) + " (REVTSTMP) VALUES (?)";
234+
String timestampColumn = getRevisionTimestampColumn(connection, revisionTableName);
235+
String sql = "INSERT INTO " + requireSafeIdentifier(revisionTableName) + " ("
236+
+ requireSafeIdentifier(timestampColumn) + ") VALUES (?)";
235237
try (PreparedStatement pstmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
236238
pstmt.setLong(1, System.currentTimeMillis());
237239
pstmt.executeUpdate();
@@ -244,6 +246,36 @@ static int createBackfillRevision(Connection connection, String revisionTableNam
244246
throw new SQLException("Failed to create backfill revision entry in " + revisionTableName);
245247
}
246248

249+
/**
250+
* Discovers the timestamp column name in the revision entity table by finding the first BIGINT
251+
* column that is not the primary key. This avoids hardcoding Hibernate-version-specific names like
252+
* "REVTSTMP" which may differ across Hibernate versions.
253+
*
254+
* @param connection JDBC connection
255+
* @param revisionTableName name of the revision entity table
256+
* @return the timestamp column name, falling back to "REVTSTMP" if not found
257+
* @throws SQLException if metadata cannot be read
258+
*/
259+
static String getRevisionTimestampColumn(Connection connection, String revisionTableName) throws SQLException {
260+
DatabaseMetaData metaData = connection.getMetaData();
261+
String pkColumn = null;
262+
try (ResultSet pkRs = metaData.getPrimaryKeys(null, null, revisionTableName)) {
263+
if (pkRs.next()) {
264+
pkColumn = pkRs.getString("COLUMN_NAME");
265+
}
266+
}
267+
try (ResultSet colRs = metaData.getColumns(null, null, revisionTableName, null)) {
268+
while (colRs.next()) {
269+
String colName = colRs.getString("COLUMN_NAME");
270+
int dataType = colRs.getInt("DATA_TYPE");
271+
if (dataType == java.sql.Types.BIGINT && !colName.equalsIgnoreCase(pkColumn)) {
272+
return colName;
273+
}
274+
}
275+
}
276+
return "REVTSTMP";
277+
}
278+
247279
/**
248280
* Validates that a SQL identifier (table or column name) contains only safe characters, preventing
249281
* SQL injection when identifiers must be concatenated into queries.

0 commit comments

Comments
 (0)