Skip to content

Commit 173ddd3

Browse files
committed
feat: add firebird and sybase test and queries
1 parent 7a8c529 commit 173ddd3

File tree

19 files changed

+744
-30
lines changed

19 files changed

+744
-30
lines changed

community/flamingock-auditstore-sql/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ dependencies {
2020
testImplementation("org.mockito:mockito-inline:4.11.0")
2121
testImplementation("org.xerial:sqlite-jdbc:3.41.2.1")
2222
testImplementation("com.ibm.informix:jdbc:4.50.10")
23+
testImplementation("org.firebirdsql.jdbc:jaybird:4.0.10.java8")
24+
testImplementation("org.hsqldb:hsqldb:2.7.2")
2325
}
2426

2527
description = "SQL audit store implementation for distributed change auditing"

community/flamingock-auditstore-sql/src/main/java/io/flamingock/community/sql/internal/SqlAuditor.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ public void initialize() {
4747
Statement stmt = conn.createStatement()) {
4848
stmt.executeUpdate(dialectHelper.getCreateTableSqlString(auditTableName));
4949
} catch (SQLException e) {
50+
// Firebird throws an error when table already exists; ignore that specific case
51+
if (dialectHelper.getSqlDialect() == io.flamingock.internal.common.sql.SqlDialect.FIREBIRD) {
52+
int errorCode = e.getErrorCode();
53+
String sqlState = e.getSQLState();
54+
String msg = e.getMessage() != null ? e.getMessage().toLowerCase() : "";
55+
56+
if (errorCode == 335544351 || "42000".equals(sqlState) || msg.contains("already exists")) {
57+
return;
58+
}
59+
}
5060
throw new RuntimeException("Failed to initialize audit table", e);
5161
}
5262
}

community/flamingock-auditstore-sql/src/main/java/io/flamingock/community/sql/internal/SqlAuditorDialectHelper.java

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ public String getCreateTableSqlString(String tableName) {
3636
case MARIADB:
3737
case H2:
3838
case HSQLDB:
39-
case FIREBIRD:
4039
return String.format(
4140
"CREATE TABLE IF NOT EXISTS %s (" +
4241
"id %s PRIMARY KEY, " +
@@ -60,6 +59,30 @@ public String getCreateTableSqlString(String tableName) {
6059
"transaction_flag %s, " +
6160
"system_change %s" +
6261
")", tableName, getAutoIncrementType(), getClobType(), getBigIntType(), getClobType(), getBooleanType(), getBooleanType());
62+
case FIREBIRD:
63+
return String.format(
64+
"CREATE TABLE %s (" +
65+
"id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " +
66+
"execution_id VARCHAR(255), " +
67+
"stage_id VARCHAR(255), " +
68+
"task_id VARCHAR(255), " +
69+
"author VARCHAR(255), " +
70+
"created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " +
71+
"state VARCHAR(255), " +
72+
"class_name VARCHAR(255), " +
73+
"method_name VARCHAR(255), " +
74+
"metadata BLOB SUB_TYPE TEXT, " +
75+
"execution_millis BIGINT, " +
76+
"execution_hostname VARCHAR(255), " +
77+
"error_trace BLOB SUB_TYPE TEXT, " +
78+
"type VARCHAR(50), " +
79+
"tx_type VARCHAR(50), " +
80+
"target_system_id VARCHAR(255), " +
81+
"order_col VARCHAR(50), " +
82+
"recovery_strategy VARCHAR(50), " +
83+
"transaction_flag SMALLINT, " +
84+
"system_change SMALLINT" +
85+
")", tableName);
6386
case POSTGRESQL:
6487
return String.format(
6588
"CREATE TABLE IF NOT EXISTS %s (" +
@@ -86,7 +109,6 @@ public String getCreateTableSqlString(String tableName) {
86109
")", tableName);
87110

88111
case SQLSERVER:
89-
case SYBASE:
90112
return String.format(
91113
"IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='%s' AND xtype='U') " +
92114
"CREATE TABLE %s (" +
@@ -111,6 +133,35 @@ public String getCreateTableSqlString(String tableName) {
111133
"transaction_flag %s, " +
112134
"system_change %s" +
113135
")", tableName, tableName, getAutoIncrementType(), getClobType(), getBigIntType(), getClobType(), getBooleanType(), getBooleanType());
136+
case SYBASE:
137+
return String.format(
138+
"IF NOT EXISTS (SELECT 1 FROM sysobjects WHERE name='%s' AND type='U') " +
139+
"BEGIN " +
140+
" EXEC('CREATE TABLE %s (" +
141+
" id BIGINT IDENTITY PRIMARY KEY, " +
142+
" execution_id VARCHAR(255), " +
143+
" stage_id VARCHAR(255), " +
144+
" task_id VARCHAR(255), " +
145+
" author VARCHAR(255), " +
146+
" created_at DATETIME, " +
147+
" state VARCHAR(32), " +
148+
" class_name VARCHAR(255), " +
149+
" method_name VARCHAR(255), " +
150+
" metadata TEXT, " +
151+
" execution_millis BIGINT, " +
152+
" execution_hostname VARCHAR(255), " +
153+
" error_trace TEXT, " +
154+
" type VARCHAR(64), " +
155+
" tx_type VARCHAR(64), " +
156+
" target_system_id VARCHAR(255), " +
157+
" order_col VARCHAR(255), " +
158+
" recovery_strategy VARCHAR(64), " +
159+
" transaction_flag BIT NOT NULL, " +
160+
" system_change BIT NOT NULL" +
161+
" )') " +
162+
"END",
163+
tableName, tableName
164+
);
114165
case ORACLE:
115166
return String.format(
116167
"BEGIN EXECUTE IMMEDIATE 'CREATE TABLE %s (" +

community/flamingock-auditstore-sql/src/main/java/io/flamingock/community/sql/internal/SqlLockDialectHelper.java

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,20 @@ public String getCreateTableSqlString(String tableName) {
4444
"owner VARCHAR(255)," +
4545
"expires_at TIMESTAMP" +
4646
")", tableName);
47+
case FIREBIRD:
48+
return String.format(
49+
"CREATE TABLE %s (" +
50+
"lock_key VARCHAR(255) PRIMARY KEY, " +
51+
"status VARCHAR(32), " +
52+
"owner VARCHAR(255), " +
53+
"expires_at TIMESTAMP" +
54+
")",
55+
tableName);
4756
case MYSQL:
4857
case MARIADB:
4958
case SQLITE:
5059
case H2:
5160
case HSQLDB:
52-
case FIREBIRD:
5361
return String.format(
5462
"CREATE TABLE IF NOT EXISTS %s (" +
5563
"`key` VARCHAR(255) PRIMARY KEY," +
@@ -58,7 +66,6 @@ public String getCreateTableSqlString(String tableName) {
5866
"expires_at TIMESTAMP" +
5967
")", tableName);
6068
case SQLSERVER:
61-
case SYBASE:
6269
return String.format(
6370
"IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='%s' AND xtype='U') " +
6471
"CREATE TABLE %s (" +
@@ -67,6 +74,19 @@ public String getCreateTableSqlString(String tableName) {
6774
"owner VARCHAR(255)," +
6875
"expires_at DATETIME" +
6976
")", tableName, tableName);
77+
case SYBASE:
78+
return String.format(
79+
"IF NOT EXISTS (SELECT 1 FROM sysobjects WHERE name='%s' AND type='U') " +
80+
"BEGIN " +
81+
" EXEC('CREATE TABLE %s (" +
82+
" lock_key VARCHAR(255) NOT NULL PRIMARY KEY, " +
83+
" status VARCHAR(32), " +
84+
" owner VARCHAR(255), " +
85+
" expires_at DATETIME" +
86+
" )') " +
87+
"END",
88+
tableName, tableName
89+
);
7090
case ORACLE:
7191
return String.format(
7292
"BEGIN EXECUTE IMMEDIATE 'CREATE TABLE %s (" +
@@ -106,12 +126,19 @@ public String getSelectLockSqlString(String tableName) {
106126
// Select lock_key as the first column (getLockEntry expects rs.getString(1) to be the key)
107127
return String.format("SELECT lock_key, status, owner, expires_at FROM %s WHERE lock_key = ?", tableName);
108128
case SQLSERVER:
109-
case SYBASE:
110129
return String.format("SELECT [key], status, owner, expires_at FROM %s WITH (UPDLOCK, ROWLOCK) WHERE [key] = ?", tableName);
111-
case ORACLE:
130+
case SYBASE:
131+
return String.format(
132+
"SELECT lock_key, status, owner, expires_at " +
133+
"FROM %s HOLDLOCK " +
134+
"WHERE lock_key = ?",
135+
tableName
136+
); case ORACLE:
112137
return String.format("SELECT \"key\", status, owner, expires_at FROM %s WHERE \"key\" = ? FOR UPDATE", tableName);
113138
case INFORMIX:
114139
return String.format("SELECT lock_key, status, owner, expires_at FROM %s WHERE lock_key = ?", tableName);
140+
case FIREBIRD:
141+
return String.format("SELECT lock_key, status, owner, expires_at FROM %s WHERE lock_key = ?", tableName);
115142
default:
116143
return String.format("SELECT `key`, status, owner, expires_at FROM %s WHERE `key` = ?", tableName);
117144
}
@@ -135,7 +162,6 @@ public String getInsertOrUpdateLockSqlString(String tableName) {
135162
"INSERT OR REPLACE INTO %s (`key`, status, owner, expires_at) VALUES (?, ?, ?, ?)",
136163
tableName);
137164
case SQLSERVER:
138-
case SYBASE:
139165
return String.format(
140166
"BEGIN TRANSACTION; " +
141167
"UPDATE %s SET status = ?, owner = ?, expires_at = ? WHERE [key] = ?; " +
@@ -145,6 +171,17 @@ public String getInsertOrUpdateLockSqlString(String tableName) {
145171
"END; " +
146172
"COMMIT TRANSACTION;",
147173
tableName, tableName);
174+
case SYBASE:
175+
return String.format(
176+
"BEGIN TRAN " +
177+
"UPDATE %s SET status = ?, owner = ?, expires_at = ? WHERE lock_key = ?; " +
178+
"IF @@ROWCOUNT = 0 " +
179+
"BEGIN " +
180+
" INSERT INTO %s (lock_key, status, owner, expires_at) VALUES (?, ?, ?, ?); " +
181+
"END " +
182+
"COMMIT TRAN",
183+
tableName, tableName
184+
);
148185
case ORACLE:
149186
return String.format(
150187
"MERGE INTO %s t USING (SELECT ? AS \"key\", ? AS status, ? AS owner, ? AS expires_at FROM dual) s " +
@@ -166,9 +203,7 @@ public String getInsertOrUpdateLockSqlString(String tableName) {
166203
"WHEN NOT MATCHED THEN INSERT (lock_key, status, owner, expires_at) VALUES (src.lock_key, src.status, src.owner, src.expires_at)",
167204
tableName);
168205
case FIREBIRD:
169-
return String.format(
170-
"UPDATE OR INSERT INTO %s (`key`, status, owner, expires_at) VALUES (?, ?, ?, ?) MATCHING (`key`)",
171-
tableName);
206+
return String.format("UPDATE " + tableName + " SET status = ?, owner = ?, expires_at = ? WHERE lock_key = ?", tableName);
172207
case INFORMIX:
173208
// Informix doesn't support ON DUPLICATE KEY UPDATE
174209
// Use a procedural approach similar to SQL Server
@@ -190,6 +225,9 @@ public String getDeleteLockSqlString(String tableName) {
190225
if (sqlDialect == SqlDialect.INFORMIX || sqlDialect == SqlDialect.DB2) {
191226
return String.format("DELETE FROM %s WHERE lock_key = ?", tableName);
192227
}
228+
if (sqlDialect == SqlDialect.FIREBIRD) {
229+
return String.format("DELETE FROM %s WHERE lock_key = ?", tableName);
230+
}
193231
return String.format("DELETE FROM %s WHERE `key` = ?", tableName);
194232
}
195233

@@ -247,7 +285,7 @@ public void upsertLockEntry(Connection conn, String tableName, String key, Strin
247285
return;
248286
}
249287

250-
if (getSqlDialect() == SqlDialect.SQLSERVER || getSqlDialect() == SqlDialect.SYBASE) {
288+
if (getSqlDialect() == SqlDialect.SQLSERVER) {
251289
// For SQL Server/Sybase, use Statement and format SQL
252290
try (Statement stmt = conn.createStatement()) {
253291
String formattedSql = sql
@@ -264,6 +302,42 @@ public void upsertLockEntry(Connection conn, String tableName, String key, Strin
264302
return;
265303
}
266304

305+
if (sqlDialect == SqlDialect.FIREBIRD) {
306+
String updateSql = getInsertOrUpdateLockSqlString(tableName);
307+
try (PreparedStatement ps = conn.prepareStatement(updateSql)) {
308+
ps.setString(1, LockStatus.LOCK_HELD.name());
309+
ps.setString(2, owner);
310+
ps.setTimestamp(3, Timestamp.valueOf(expiresAt));
311+
ps.setString(4, key);
312+
int updated = ps.executeUpdate();
313+
if (updated == 0) {
314+
String insertSql = "INSERT INTO " + tableName + " (lock_key, status, owner, expires_at) VALUES (?, ?, ?, ?)";
315+
try (PreparedStatement ins = conn.prepareStatement(insertSql)) {
316+
ins.setString(1, key);
317+
ins.setString(2, LockStatus.LOCK_HELD.name());
318+
ins.setString(3, owner);
319+
ins.setTimestamp(4, Timestamp.valueOf(expiresAt));
320+
ins.executeUpdate();
321+
}
322+
}
323+
}
324+
return;
325+
}
326+
327+
if (sqlDialect == SqlDialect.SYBASE) {
328+
// The lock was already deleted in acquireLockQuery for Sybase
329+
try (PreparedStatement insert = conn.prepareStatement(
330+
"INSERT INTO " + tableName + " (lock_key, status, owner, expires_at) VALUES (?, ?, ?, ?)")) {
331+
insert.setString(1, key);
332+
insert.setString(2, LockStatus.LOCK_HELD.name());
333+
insert.setString(3, owner);
334+
insert.setTimestamp(4, Timestamp.valueOf(expiresAt));
335+
insert.executeUpdate();
336+
}
337+
return;
338+
}
339+
340+
267341
// Default case for other dialects
268342
try (PreparedStatement ps = conn.prepareStatement(sql)) {
269343
ps.setString(1, key);

0 commit comments

Comments
 (0)