From cb615b36080da516b1b16fc28a264451e51637d3 Mon Sep 17 00:00:00 2001 From: Aaron3S Date: Thu, 31 Jul 2025 15:02:41 +0800 Subject: [PATCH] feat: support oracle distinct sub query --- .../datasource/base/BaseSQLActuator.java | 3 +- .../chen/framework/utils/PageUtils.java | 55 ++++++++++++------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/backend/framework/src/main/java/org/jumpserver/chen/framework/datasource/base/BaseSQLActuator.java b/backend/framework/src/main/java/org/jumpserver/chen/framework/datasource/base/BaseSQLActuator.java index 00abfde..26ebde9 100644 --- a/backend/framework/src/main/java/org/jumpserver/chen/framework/datasource/base/BaseSQLActuator.java +++ b/backend/framework/src/main/java/org/jumpserver/chen/framework/datasource/base/BaseSQLActuator.java @@ -2,7 +2,6 @@ import com.alibaba.druid.DbType; import com.alibaba.druid.pool.DruidPooledConnection; -import com.alibaba.druid.sql.PagerUtils; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; @@ -232,7 +231,7 @@ public int count(SQLExecutePlan plan) throws SQLException { if (limit > 0) { return -1; } - var countSQL = PagerUtils.count(plan.getSourceSQL(), plan.getDruidDbType()); + var countSQL = PageUtils.count(plan.getSourceSQL(), plan.getDruidDbType()); try (Statement stmt = plan.createStatement()) { var resultSet = stmt.executeQuery(countSQL); if (resultSet.next()) { diff --git a/backend/framework/src/main/java/org/jumpserver/chen/framework/utils/PageUtils.java b/backend/framework/src/main/java/org/jumpserver/chen/framework/utils/PageUtils.java index 025ee63..ad24e8b 100644 --- a/backend/framework/src/main/java/org/jumpserver/chen/framework/utils/PageUtils.java +++ b/backend/framework/src/main/java/org/jumpserver/chen/framework/utils/PageUtils.java @@ -429,46 +429,59 @@ private static boolean limitMySqlQueryBlock(SQLSelectQueryBlock queryBlock, DbTy } private static String count(SQLSelect select, DbType dbType) { + // 去除 ORDER BY if (select.getOrderBy() != null) { - select.setOrderBy((SQLOrderBy) null); + select.setOrderBy(null); } SQLSelectQuery query = select.getQuery(); - clearOrderBy(query); + clearOrderBy(query); // 自定义的清理嵌套子查询中的 ORDER BY 的方法 + if (query instanceof SQLSelectQueryBlock) { - SQLSelectItem countItem = createCountItem(dbType); SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query; List selectList = queryBlock.getSelectList(); + int distinctOption = queryBlock.getDistionOption(); + + // 情况 1: 存在 GROUP BY,需用子查询 if (queryBlock.getGroupBy() != null && queryBlock.getGroupBy().getItems().size() > 0) { - if (queryBlock.getSelectList().size() == 1 && ((SQLSelectItem) queryBlock.getSelectList().get(0)).getExpr() instanceof SQLAllColumnExpr) { - queryBlock.getSelectList().clear(); - queryBlock.getSelectList().add(new SQLSelectItem(new SQLIntegerExpr(1))); + if (selectList.size() == 1 && selectList.get(0).getExpr() instanceof SQLAllColumnExpr) { + selectList.clear(); + selectList.add(new SQLSelectItem(new SQLIntegerExpr(1))); } - return createCountUseSubQuery(select, dbType); - } else { - int option = queryBlock.getDistionOption(); - if (option == 2 && selectList.size() >= 1) { - SQLAggregateExpr countExpr = new SQLAggregateExpr("COUNT", SQLAggregateOption.DISTINCT); + } - for (int i = 0; i < selectList.size(); ++i) { - countExpr.addArgument(((SQLSelectItem) selectList.get(i)).getExpr()); + // 情况 2: DISTINCT 情况下,Oracle 特别处理 + if (distinctOption == SQLSetQuantifier.DISTINCT) { + if (dbType == DbType.oracle && ( + selectList.size() > 1 || + (selectList.size() == 1 && selectList.get(0).getExpr() instanceof SQLAllColumnExpr) + )) { + // SELECT DISTINCT * 或多字段,Oracle 不支持直接 count(distinct ...) + return createCountUseSubQuery(select, dbType); + } else { + // 只有一个字段,Oracle 支持 count(distinct col) + SQLAggregateExpr countExpr = new SQLAggregateExpr("COUNT", SQLAggregateOption.DISTINCT); + for (SQLSelectItem item : selectList) { + countExpr.addArgument(item.getExpr()); } - selectList.clear(); - queryBlock.setDistionOption(0); + queryBlock.setDistionOption(0); // 去除 DISTINCT queryBlock.addSelectItem(countExpr); - } else { - selectList.clear(); - selectList.add(countItem); + return SQLUtils.toSQLString(select, dbType); } - - return SQLUtils.toSQLString(select, dbType); } + + // 情况 3: 非 DISTINCT,无 GROUP BY,直接 count(*) + selectList.clear(); + selectList.add(createCountItem(dbType)); + return SQLUtils.toSQLString(select, dbType); + } else if (query instanceof SQLUnionQuery) { + // UNION 情况统一使用子查询 return createCountUseSubQuery(select, dbType); } else { - throw new IllegalStateException(); + throw new IllegalStateException("不支持的 SQL 查询类型: " + query.getClass().getName()); } }