fix: database compatibility and plugin-not-found graceful degradation - #65
fix: database compatibility and plugin-not-found graceful degradation#65windy664 wants to merge 1 commit into
Conversation
Database compatibility improvements: - Replace ALTER TABLE IF NOT EXISTS with JDBC metadata checks for H2 compatibility - Add addColumnIfNotExists() and dropColumnIfExists() helper methods - Change address column from TEXT to VARCHAR(255) for UNIQUE constraint compatibility - Add null check for database connection in setup() - Throw RuntimeException on database setup failure instead of silent e.printStackTrace() Plugin-not-found graceful degradation: - UserConverter.readUser catches IllegalStateException from PluginUser.toUser - Base.getMails/getMail handle null sender/receiver with DummyMailUser fallback - Base.getMailTemplate(s) handle null sender with DummyMailUser fallback This prevents crashes when: - Using H2 database (default) instead of MySQL - Plugins that registered PluginMailUser are disabled/uninstalled - Database schema needs migration
|
Warning Review limit reached
Next review available in: 55 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request improves database robustness and compatibility by wrapping user conversion in a try-catch block, changing the address column type to VARCHAR(255), and refactoring table schema updates to use metadata-based helper methods (addColumnIfNotExists and dropColumnIfExists). It also adds fallback dummy users for null senders or receivers during mail loading. The review feedback suggests adding a null check for the database connection in reload() to prevent a potential NullPointerException, and utilizing try-with-resources in the new helper methods to avoid resource leaks of ResultSet objects.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| public void reload() { | ||
| try (Connection conn = getConnection()) { | ||
| var fallbackPreview = ItemStack.of(Material.STONE).serializeAsBytes(); |
There was a problem hiding this comment.
In reload(), if getConnection() returns null (for example, if the database connection fails), a NullPointerException will be thrown when addColumnIfNotExists attempts to call conn.getMetaData(). Adding a null check for conn in reload(), similar to the one in setup(), will handle connection failures gracefully.
| public void reload() { | |
| try (Connection conn = getConnection()) { | |
| var fallbackPreview = ItemStack.of(Material.STONE).serializeAsBytes(); | |
| public void reload() { | |
| try (Connection conn = getConnection()) { | |
| if (conn == null) { | |
| throw new SQLException("Failed to get database connection"); | |
| } | |
| var fallbackPreview = ItemStack.of(Material.STONE).serializeAsBytes(); |
| private void addColumnIfNotExists(Connection conn, String table, String column, String definition) throws SQLException { | ||
| try { | ||
| // 检查列是否存在(H2 默认大写存储标识符) | ||
| var rs = conn.getMetaData().getColumns(null, null, table.toUpperCase(), column.toUpperCase()); | ||
| if (!rs.next()) { | ||
| runner.execute(conn, "ALTER TABLE " + table + " ADD COLUMN " + column + " " + definition); | ||
| } | ||
| rs.close(); | ||
| } catch (SQLException e) { | ||
| // 如果表不存在或其他错误,忽略 | ||
| e.printStackTrace(); | ||
| } | ||
| } | ||
|
|
||
| private void dropColumnIfExists(Connection conn, String table, String column) { | ||
| try { | ||
| var rs = conn.getMetaData().getColumns(null, null, table.toUpperCase(), column.toUpperCase()); | ||
| if (rs.next()) { | ||
| runner.execute(conn, "ALTER TABLE " + table + " DROP COLUMN " + column); | ||
| } | ||
| rs.close(); | ||
| } catch (SQLException e) { | ||
| // 忽略错误 | ||
| } | ||
| } |
There was a problem hiding this comment.
In both addColumnIfNotExists and dropColumnIfExists, the ResultSet rs is opened but not closed using a try-with-resources block. If an exception is thrown during runner.execute, the ResultSet will leak. Additionally, addColumnIfNotExists declares throws SQLException in its signature, but it already catches SQLException internally and does not rethrow it, making the throws clause redundant. Refactoring both methods to use try-with-resources ensures resources are always closed properly and cleans up the redundant throws clause.
private void addColumnIfNotExists(Connection conn, String table, String column, String definition) {
try (var rs = conn.getMetaData().getColumns(null, null, table.toUpperCase(), column.toUpperCase())) {
if (!rs.next()) {
runner.execute(conn, "ALTER TABLE " + table + " ADD COLUMN " + column + " " + definition);
}
} catch (SQLException e) {
// 如果表不存在或其他错误,忽略
e.printStackTrace();
}
}
private void dropColumnIfExists(Connection conn, String table, String column) {
try (var rs = conn.getMetaData().getColumns(null, null, table.toUpperCase(), column.toUpperCase())) {
if (rs.next()) {
runner.execute(conn, "ALTER TABLE " + table + " DROP COLUMN " + column);
}
} catch (SQLException e) {
// 忽略错误
}
}
Summary
Fix database compatibility issues with H2 and add graceful degradation when plugins are not found.
Changes
Database Compatibility (H2)
ALTER TABLE IF NOT EXISTSwith JDBC metadata column checksaddColumnIfNotExists()anddropColumnIfExists()helper methodsaddresscolumn fromTEXTtoVARCHAR(255)for UNIQUE constraint compatibilitysetup()RuntimeExceptionon database setup failure instead of silente.printStackTrace()Plugin-Not-Found Graceful Degradation
When a plugin that registered a
PluginMailUseris not loaded:UserConverter.readUser:
IllegalStateExceptionfromPluginUser.toUser()nullinstead of crashingBase.getMails/getMail:
DummyMailUserwith "Unknown Sender/Receiver"Base.getMailTemplate(s):
DummyMailUserUse Cases
Testing
Tested with: