diff --git a/apps/desktop/src/lib/databaseTableDataCapabilities.ts b/apps/desktop/src/lib/databaseTableDataCapabilities.ts index 2569b67b5..fb8ff40b2 100644 --- a/apps/desktop/src/lib/databaseTableDataCapabilities.ts +++ b/apps/desktop/src/lib/databaseTableDataCapabilities.ts @@ -62,6 +62,15 @@ const DATABASE_CAPABILITY_OVERRIDES: Partial transaction: false, }); + assert.deepEqual(getDatabaseCapability("jdbc").tableData, { + insert: false, + updateRequiresPrimaryKey: true, + deleteRequiresPrimaryKey: true, + requiresTransactionalTableForExistingRows: false, + transaction: false, + }); + assert.equal(getDatabaseCapability("oracle").syntheticKey, "oracle-rowid"); assert.equal(getDatabaseCapability("neo4j").syntheticKey, "neo4j-element-id"); }); diff --git a/packages/app-tests/tableEditing.test.ts b/packages/app-tests/tableEditing.test.ts index 66d22befa..ac03c7e2b 100644 --- a/packages/app-tests/tableEditing.test.ts +++ b/packages/app-tests/tableEditing.test.ts @@ -58,6 +58,7 @@ test("allows Hive table data editing even without declared primary keys", () => test("does not use transactional grid saves for Hive", () => { assert.equal(supportsDataGridTransaction("hive"), false); assert.equal(supportsDataGridTransaction("trino"), false); + assert.equal(supportsDataGridTransaction("jdbc"), false); assert.equal(supportsDataGridTransaction("postgres"), true); }); diff --git a/plugins/jdbc/src/main/java/app/dbx/jdbc/DbxJdbcPlugin.java b/plugins/jdbc/src/main/java/app/dbx/jdbc/DbxJdbcPlugin.java index 8627f4af7..8a97c45c9 100644 --- a/plugins/jdbc/src/main/java/app/dbx/jdbc/DbxJdbcPlugin.java +++ b/plugins/jdbc/src/main/java/app/dbx/jdbc/DbxJdbcPlugin.java @@ -206,7 +206,7 @@ public final class DbxJdbcPlugin { applyExecutionContext(connection, conn, database, schema); try (Statement statement = conn.createStatement()) { statement.setMaxRows(MAX_ROWS + 1); - boolean hasResultSet = statement.execute(sql); + boolean hasResultSet = statement.execute(trimStatementSql(sql)); ObjectNode result = MAPPER.createObjectNode(); ArrayNode columns = MAPPER.createArrayNode(); ArrayNode rows = MAPPER.createArrayNode(); @@ -243,6 +243,10 @@ public final class DbxJdbcPlugin { } } + private static String trimStatementSql(String sql) { + return sql == null ? "" : sql.trim().replaceFirst(";\\s*$", ""); + } + private static void applyExecutionContext(JsonNode connection, Connection conn, String database, String schema) throws SQLException { if (driverQuirks(connection).skipExecutionContext()) { return; diff --git a/plugins/jdbc/src/test/java/app/dbx/jdbc/DbxJdbcPluginTest.java b/plugins/jdbc/src/test/java/app/dbx/jdbc/DbxJdbcPluginTest.java index 88724aea7..dfa74f54a 100644 --- a/plugins/jdbc/src/test/java/app/dbx/jdbc/DbxJdbcPluginTest.java +++ b/plugins/jdbc/src/test/java/app/dbx/jdbc/DbxJdbcPluginTest.java @@ -47,6 +47,19 @@ final class DbxJdbcPluginTest { assertEquals("APP", response.path("result").path("rows").path(0).path(0).asText()); } + @Test + void executeQueryTrimsSingleTrailingSemicolon() throws Exception { + JsonNode response = request("executeQuery", """ + { + "connection": %s, + "sql": "SELECT 1 AS n;" + } + """.formatted(CONNECTION)); + + assertFalse(response.has("error"), response.toString()); + assertEquals(1, response.path("result").path("rows").path(0).path(0).asInt()); + } + @Test void driverQuirksDetectYashanJdbcUrl() throws Exception { JsonNode yashan = MAPPER.readTree("""