Commit 38e88b02f52e8b4fa143a74f64d7c6408c89d387
1 parent
61b0624a
🐛修复数据权限,不支持隐式内连接的问题
Showing
3 changed files
with
421 additions
and
123 deletions
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptor.java
| @@ -18,7 +18,6 @@ import net.sf.jsqlparser.expression.operators.conditional.OrExpression; | @@ -18,7 +18,6 @@ import net.sf.jsqlparser.expression.operators.conditional.OrExpression; | ||
| 18 | import net.sf.jsqlparser.expression.operators.relational.ExistsExpression; | 18 | import net.sf.jsqlparser.expression.operators.relational.ExistsExpression; |
| 19 | import net.sf.jsqlparser.expression.operators.relational.ExpressionList; | 19 | import net.sf.jsqlparser.expression.operators.relational.ExpressionList; |
| 20 | import net.sf.jsqlparser.expression.operators.relational.InExpression; | 20 | import net.sf.jsqlparser.expression.operators.relational.InExpression; |
| 21 | -import net.sf.jsqlparser.expression.operators.relational.ItemsList; | ||
| 22 | import net.sf.jsqlparser.schema.Table; | 21 | import net.sf.jsqlparser.schema.Table; |
| 23 | import net.sf.jsqlparser.statement.delete.Delete; | 22 | import net.sf.jsqlparser.statement.delete.Delete; |
| 24 | import net.sf.jsqlparser.statement.select.*; | 23 | import net.sf.jsqlparser.statement.select.*; |
| @@ -37,7 +36,7 @@ import java.util.concurrent.ConcurrentHashMap; | @@ -37,7 +36,7 @@ import java.util.concurrent.ConcurrentHashMap; | ||
| 37 | 36 | ||
| 38 | /** | 37 | /** |
| 39 | * 数据权限拦截器,通过 {@link DataPermissionRule} 数据权限规则,重写 SQL 的方式来实现 | 38 | * 数据权限拦截器,通过 {@link DataPermissionRule} 数据权限规则,重写 SQL 的方式来实现 |
| 40 | - * 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, Table)} 方法 | 39 | + * 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, List)} 方法 |
| 41 | * | 40 | * |
| 42 | * 整体的代码实现上,参考 {@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor} 实现。 | 41 | * 整体的代码实现上,参考 {@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor} 实现。 |
| 43 | * 所以每次 MyBatis Plus 升级时,需要 Review 下其具体的实现是否有变更! | 42 | * 所以每次 MyBatis Plus 升级时,需要 Review 下其具体的实现是否有变更! |
| @@ -53,8 +52,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -53,8 +52,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 53 | private final MappedStatementCache mappedStatementCache = new MappedStatementCache(); | 52 | private final MappedStatementCache mappedStatementCache = new MappedStatementCache(); |
| 54 | 53 | ||
| 55 | @Override // SELECT 场景 | 54 | @Override // SELECT 场景 |
| 56 | - public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, | ||
| 57 | - RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { | 55 | + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { |
| 58 | // 获得 Mapper 对应的数据权限的规则 | 56 | // 获得 Mapper 对应的数据权限的规则 |
| 59 | List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId()); | 57 | List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId()); |
| 60 | if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过 | 58 | if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过 |
| @@ -68,12 +66,14 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -68,12 +66,14 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 68 | // 处理 SQL | 66 | // 处理 SQL |
| 69 | mpBs.sql(parserSingle(mpBs.sql(), null)); | 67 | mpBs.sql(parserSingle(mpBs.sql(), null)); |
| 70 | } finally { | 68 | } finally { |
| 69 | + // 添加是否需要重写的缓存 | ||
| 71 | addMappedStatementCache(ms); | 70 | addMappedStatementCache(ms); |
| 71 | + // 清空上下文 | ||
| 72 | ContextHolder.clear(); | 72 | ContextHolder.clear(); |
| 73 | } | 73 | } |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | - @Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景 | 76 | + @Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景(因为 INSERT 不需要数据权限) |
| 77 | public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { | 77 | public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { |
| 78 | PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); | 78 | PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); |
| 79 | MappedStatement ms = mpSh.mappedStatement(); | 79 | MappedStatement ms = mpSh.mappedStatement(); |
| @@ -92,7 +92,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -92,7 +92,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 92 | // 处理 SQL | 92 | // 处理 SQL |
| 93 | mpBs.sql(parserMulti(mpBs.sql(), null)); | 93 | mpBs.sql(parserMulti(mpBs.sql(), null)); |
| 94 | } finally { | 94 | } finally { |
| 95 | + // 添加是否需要重写的缓存 | ||
| 95 | addMappedStatementCache(ms); | 96 | addMappedStatementCache(ms); |
| 97 | + // 清空上下文 | ||
| 96 | ContextHolder.clear(); | 98 | ContextHolder.clear(); |
| 97 | } | 99 | } |
| 98 | } | 100 | } |
| @@ -107,24 +109,6 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -107,24 +109,6 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 107 | } | 109 | } |
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | - protected void processSelectBody(SelectBody selectBody) { | ||
| 111 | - if (selectBody == null) { | ||
| 112 | - return; | ||
| 113 | - } | ||
| 114 | - if (selectBody instanceof PlainSelect) { | ||
| 115 | - processPlainSelect((PlainSelect) selectBody); | ||
| 116 | - } else if (selectBody instanceof WithItem) { | ||
| 117 | - WithItem withItem = (WithItem) selectBody; | ||
| 118 | - processSelectBody(withItem.getSubSelect().getSelectBody()); | ||
| 119 | - } else { | ||
| 120 | - SetOperationList operationList = (SetOperationList) selectBody; | ||
| 121 | - List<SelectBody> selectBodys = operationList.getSelects(); | ||
| 122 | - if (CollectionUtils.isNotEmpty(selectBodys)) { | ||
| 123 | - selectBodys.forEach(this::processSelectBody); | ||
| 124 | - } | ||
| 125 | - } | ||
| 126 | - } | ||
| 127 | - | ||
| 128 | /** | 112 | /** |
| 129 | * update 语句处理 | 113 | * update 语句处理 |
| 130 | */ | 114 | */ |
| @@ -142,28 +126,77 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -142,28 +126,77 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 142 | delete.setWhere(this.builderExpression(delete.getWhere(), delete.getTable())); | 126 | delete.setWhere(this.builderExpression(delete.getWhere(), delete.getTable())); |
| 143 | } | 127 | } |
| 144 | 128 | ||
| 129 | + // ========== 和 TenantLineInnerInterceptor 一致的逻辑 ========== | ||
| 130 | + | ||
| 131 | + protected void processSelectBody(SelectBody selectBody) { | ||
| 132 | + if (selectBody == null) { | ||
| 133 | + return; | ||
| 134 | + } | ||
| 135 | + if (selectBody instanceof PlainSelect) { | ||
| 136 | + processPlainSelect((PlainSelect) selectBody); | ||
| 137 | + } else if (selectBody instanceof WithItem) { | ||
| 138 | + WithItem withItem = (WithItem) selectBody; | ||
| 139 | + processSelectBody(withItem.getSubSelect().getSelectBody()); | ||
| 140 | + } else { | ||
| 141 | + SetOperationList operationList = (SetOperationList) selectBody; | ||
| 142 | + List<SelectBody> selectBodyList = operationList.getSelects(); | ||
| 143 | + if (CollectionUtils.isNotEmpty(selectBodyList)) { | ||
| 144 | + selectBodyList.forEach(this::processSelectBody); | ||
| 145 | + } | ||
| 146 | + } | ||
| 147 | + } | ||
| 148 | + | ||
| 145 | /** | 149 | /** |
| 146 | * 处理 PlainSelect | 150 | * 处理 PlainSelect |
| 147 | */ | 151 | */ |
| 148 | protected void processPlainSelect(PlainSelect plainSelect) { | 152 | protected void processPlainSelect(PlainSelect plainSelect) { |
| 149 | - FromItem fromItem = plainSelect.getFromItem(); | ||
| 150 | - Expression where = plainSelect.getWhere(); | ||
| 151 | - processWhereSubSelect(where); | ||
| 152 | - if (fromItem instanceof Table) { | ||
| 153 | - Table fromTable = (Table) fromItem; | ||
| 154 | - plainSelect.setWhere(builderExpression(where, fromTable)); | ||
| 155 | - } else { | ||
| 156 | - processFromItem(fromItem); | ||
| 157 | - } | ||
| 158 | //#3087 github | 153 | //#3087 github |
| 159 | List<SelectItem> selectItems = plainSelect.getSelectItems(); | 154 | List<SelectItem> selectItems = plainSelect.getSelectItems(); |
| 160 | if (CollectionUtils.isNotEmpty(selectItems)) { | 155 | if (CollectionUtils.isNotEmpty(selectItems)) { |
| 161 | selectItems.forEach(this::processSelectItem); | 156 | selectItems.forEach(this::processSelectItem); |
| 162 | } | 157 | } |
| 158 | + | ||
| 159 | + // 处理 where 中的子查询 | ||
| 160 | + Expression where = plainSelect.getWhere(); | ||
| 161 | + processWhereSubSelect(where); | ||
| 162 | + | ||
| 163 | + // 处理 fromItem | ||
| 164 | + FromItem fromItem = plainSelect.getFromItem(); | ||
| 165 | + List<Table> list = processFromItem(fromItem); | ||
| 166 | + List<Table> mainTables = new ArrayList<>(list); | ||
| 167 | + | ||
| 168 | + // 处理 join | ||
| 163 | List<Join> joins = plainSelect.getJoins(); | 169 | List<Join> joins = plainSelect.getJoins(); |
| 164 | if (CollectionUtils.isNotEmpty(joins)) { | 170 | if (CollectionUtils.isNotEmpty(joins)) { |
| 165 | - processJoins(joins); | 171 | + mainTables = processJoins(mainTables, joins); |
| 172 | + } | ||
| 173 | + | ||
| 174 | + // 当有 mainTable 时,进行 where 条件追加 | ||
| 175 | + if (CollectionUtils.isNotEmpty(mainTables)) { | ||
| 176 | + plainSelect.setWhere(builderExpression(where, mainTables)); | ||
| 177 | + } | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + private List<Table> processFromItem(FromItem fromItem) { | ||
| 181 | + // 处理括号括起来的表达式 | ||
| 182 | + while (fromItem instanceof ParenthesisFromItem) { | ||
| 183 | + fromItem = ((ParenthesisFromItem) fromItem).getFromItem(); | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + List<Table> mainTables = new ArrayList<>(); | ||
| 187 | + // 无 join 时的处理逻辑 | ||
| 188 | + if (fromItem instanceof Table) { | ||
| 189 | + Table fromTable = (Table) fromItem; | ||
| 190 | + mainTables.add(fromTable); | ||
| 191 | + } else if (fromItem instanceof SubJoin) { | ||
| 192 | + // SubJoin 类型则还需要添加上 where 条件 | ||
| 193 | + List<Table> tables = processSubJoin((SubJoin) fromItem); | ||
| 194 | + mainTables.addAll(tables); | ||
| 195 | + } else { | ||
| 196 | + // 处理下 fromItem | ||
| 197 | + processOtherFromItem(fromItem); | ||
| 166 | } | 198 | } |
| 199 | + return mainTables; | ||
| 167 | } | 200 | } |
| 168 | 201 | ||
| 169 | /** | 202 | /** |
| @@ -191,7 +224,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -191,7 +224,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 191 | return; | 224 | return; |
| 192 | } | 225 | } |
| 193 | if (where instanceof FromItem) { | 226 | if (where instanceof FromItem) { |
| 194 | - processFromItem((FromItem) where); | 227 | + processOtherFromItem((FromItem) where); |
| 195 | return; | 228 | return; |
| 196 | } | 229 | } |
| 197 | if (where.toString().indexOf("SELECT") > 0) { | 230 | if (where.toString().indexOf("SELECT") > 0) { |
| @@ -204,9 +237,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -204,9 +237,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 204 | } else if (where instanceof InExpression) { | 237 | } else if (where instanceof InExpression) { |
| 205 | // in | 238 | // in |
| 206 | InExpression expression = (InExpression) where; | 239 | InExpression expression = (InExpression) where; |
| 207 | - ItemsList itemsList = expression.getRightItemsList(); | ||
| 208 | - if (itemsList instanceof SubSelect) { | ||
| 209 | - processSelectBody(((SubSelect) itemsList).getSelectBody()); | 240 | + Expression inExpression = expression.getRightExpression(); |
| 241 | + if (inExpression instanceof SubSelect) { | ||
| 242 | + processSelectBody(((SubSelect) inExpression).getSelectBody()); | ||
| 210 | } | 243 | } |
| 211 | } else if (where instanceof ExistsExpression) { | 244 | } else if (where instanceof ExistsExpression) { |
| 212 | // exists | 245 | // exists |
| @@ -239,7 +272,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -239,7 +272,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 239 | * <p>支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..)<p> | 272 | * <p>支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..)<p> |
| 240 | * <p> fixed gitee pulls/141</p> | 273 | * <p> fixed gitee pulls/141</p> |
| 241 | * | 274 | * |
| 242 | - * @param function 函数 | 275 | + * @param function |
| 243 | */ | 276 | */ |
| 244 | protected void processFunction(Function function) { | 277 | protected void processFunction(Function function) { |
| 245 | ExpressionList parameters = function.getParameters(); | 278 | ExpressionList parameters = function.getParameters(); |
| @@ -257,22 +290,19 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -257,22 +290,19 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 257 | /** | 290 | /** |
| 258 | * 处理子查询等 | 291 | * 处理子查询等 |
| 259 | */ | 292 | */ |
| 260 | - protected void processFromItem(FromItem fromItem) { | ||
| 261 | - if (fromItem instanceof SubJoin) { | ||
| 262 | - SubJoin subJoin = (SubJoin) fromItem; | ||
| 263 | - if (subJoin.getJoinList() != null) { | ||
| 264 | - processJoins(subJoin.getJoinList()); | ||
| 265 | - } | ||
| 266 | - if (subJoin.getLeft() != null) { | ||
| 267 | - processFromItem(subJoin.getLeft()); | ||
| 268 | - } | ||
| 269 | - } else if (fromItem instanceof SubSelect) { | 293 | + protected void processOtherFromItem(FromItem fromItem) { |
| 294 | + // 去除括号 | ||
| 295 | + while (fromItem instanceof ParenthesisFromItem) { | ||
| 296 | + fromItem = ((ParenthesisFromItem) fromItem).getFromItem(); | ||
| 297 | + } | ||
| 298 | + | ||
| 299 | + if (fromItem instanceof SubSelect) { | ||
| 270 | SubSelect subSelect = (SubSelect) fromItem; | 300 | SubSelect subSelect = (SubSelect) fromItem; |
| 271 | if (subSelect.getSelectBody() != null) { | 301 | if (subSelect.getSelectBody() != null) { |
| 272 | processSelectBody(subSelect.getSelectBody()); | 302 | processSelectBody(subSelect.getSelectBody()); |
| 273 | } | 303 | } |
| 274 | } else if (fromItem instanceof ValuesList) { | 304 | } else if (fromItem instanceof ValuesList) { |
| 275 | - logger.debug("Perform a subquery, if you do not give us feedback"); | 305 | + logger.debug("Perform a subQuery, if you do not give us feedback"); |
| 276 | } else if (fromItem instanceof LateralSubSelect) { | 306 | } else if (fromItem instanceof LateralSubSelect) { |
| 277 | LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem; | 307 | LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem; |
| 278 | if (lateralSubSelect.getSubSelect() != null) { | 308 | if (lateralSubSelect.getSubSelect() != null) { |
| @@ -285,74 +315,175 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | @@ -285,74 +315,175 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme | ||
| 285 | } | 315 | } |
| 286 | 316 | ||
| 287 | /** | 317 | /** |
| 318 | + * 处理 sub join | ||
| 319 | + * | ||
| 320 | + * @param subJoin subJoin | ||
| 321 | + * @return Table subJoin 中的主表 | ||
| 322 | + */ | ||
| 323 | + private List<Table> processSubJoin(SubJoin subJoin) { | ||
| 324 | + List<Table> mainTables = new ArrayList<>(); | ||
| 325 | + if (subJoin.getJoinList() != null) { | ||
| 326 | + List<Table> list = processFromItem(subJoin.getLeft()); | ||
| 327 | + mainTables.addAll(list); | ||
| 328 | + mainTables = processJoins(mainTables, subJoin.getJoinList()); | ||
| 329 | + } | ||
| 330 | + return mainTables; | ||
| 331 | + } | ||
| 332 | + | ||
| 333 | + /** | ||
| 288 | * 处理 joins | 334 | * 处理 joins |
| 289 | * | 335 | * |
| 290 | - * @param joins join 集合 | 336 | + * @param mainTables 可以为 null |
| 337 | + * @param joins join 集合 | ||
| 338 | + * @return List<Table> 右连接查询的 Table 列表 | ||
| 291 | */ | 339 | */ |
| 292 | - private void processJoins(List<Join> joins) { | 340 | + private List<Table> processJoins(List<Table> mainTables, List<Join> joins) { |
| 341 | + // join 表达式中最终的主表 | ||
| 342 | + Table mainTable = null; | ||
| 343 | + // 当前 join 的左表 | ||
| 344 | + Table leftTable = null; | ||
| 345 | + | ||
| 346 | + if (mainTables == null) { | ||
| 347 | + mainTables = new ArrayList<>(); | ||
| 348 | + } else if (mainTables.size() == 1) { | ||
| 349 | + mainTable = mainTables.get(0); | ||
| 350 | + leftTable = mainTable; | ||
| 351 | + } | ||
| 352 | + | ||
| 293 | //对于 on 表达式写在最后的 join,需要记录下前面多个 on 的表名 | 353 | //对于 on 表达式写在最后的 join,需要记录下前面多个 on 的表名 |
| 294 | - Deque<Table> tables = new LinkedList<>(); | 354 | + Deque<List<Table>> onTableDeque = new LinkedList<>(); |
| 295 | for (Join join : joins) { | 355 | for (Join join : joins) { |
| 296 | // 处理 on 表达式 | 356 | // 处理 on 表达式 |
| 297 | - FromItem fromItem = join.getRightItem(); | ||
| 298 | - if (fromItem instanceof Table) { | ||
| 299 | - Table fromTable = (Table) fromItem; | 357 | + FromItem joinItem = join.getRightItem(); |
| 358 | + | ||
| 359 | + // 获取当前 join 的表,subJoint 可以看作是一张表 | ||
| 360 | + List<Table> joinTables = null; | ||
| 361 | + if (joinItem instanceof Table) { | ||
| 362 | + joinTables = new ArrayList<>(); | ||
| 363 | + joinTables.add((Table) joinItem); | ||
| 364 | + } else if (joinItem instanceof SubJoin) { | ||
| 365 | + joinTables = processSubJoin((SubJoin) joinItem); | ||
| 366 | + } | ||
| 367 | + | ||
| 368 | + if (joinTables != null) { | ||
| 369 | + | ||
| 370 | + // 如果是隐式内连接 | ||
| 371 | + if (join.isSimple()) { | ||
| 372 | + mainTables.addAll(joinTables); | ||
| 373 | + continue; | ||
| 374 | + } | ||
| 375 | + | ||
| 376 | + // 当前表是否忽略 | ||
| 377 | + Table joinTable = joinTables.get(0); | ||
| 378 | + | ||
| 379 | + List<Table> onTables = null; | ||
| 380 | + // 如果不要忽略,且是右连接,则记录下当前表 | ||
| 381 | + if (join.isRight()) { | ||
| 382 | + mainTable = joinTable; | ||
| 383 | + if (leftTable != null) { | ||
| 384 | + onTables = Collections.singletonList(leftTable); | ||
| 385 | + } | ||
| 386 | + } else if (join.isLeft()) { | ||
| 387 | + onTables = Collections.singletonList(joinTable); | ||
| 388 | + } else if (join.isInner()) { | ||
| 389 | + if (mainTable == null) { | ||
| 390 | + onTables = Collections.singletonList(joinTable); | ||
| 391 | + } else { | ||
| 392 | + onTables = Arrays.asList(mainTable, joinTable); | ||
| 393 | + } | ||
| 394 | + mainTable = null; | ||
| 395 | + } | ||
| 396 | + | ||
| 397 | + mainTables = new ArrayList<>(); | ||
| 398 | + if (mainTable != null) { | ||
| 399 | + mainTables.add(mainTable); | ||
| 400 | + } | ||
| 401 | + | ||
| 300 | // 获取 join 尾缀的 on 表达式列表 | 402 | // 获取 join 尾缀的 on 表达式列表 |
| 301 | Collection<Expression> originOnExpressions = join.getOnExpressions(); | 403 | Collection<Expression> originOnExpressions = join.getOnExpressions(); |
| 302 | // 正常 join on 表达式只有一个,立刻处理 | 404 | // 正常 join on 表达式只有一个,立刻处理 |
| 303 | - if (originOnExpressions.size() == 1) { | ||
| 304 | - processJoin(join); | 405 | + if (originOnExpressions.size() == 1 && onTables != null) { |
| 406 | + List<Expression> onExpressions = new LinkedList<>(); | ||
| 407 | + onExpressions.add(builderExpression(originOnExpressions.iterator().next(), onTables)); | ||
| 408 | + join.setOnExpressions(onExpressions); | ||
| 409 | + leftTable = joinTable; | ||
| 305 | continue; | 410 | continue; |
| 306 | } | 411 | } |
| 307 | - tables.push(fromTable); | 412 | + // 表名压栈,忽略的表压入 null,以便后续不处理 |
| 413 | + onTableDeque.push(onTables); | ||
| 308 | // 尾缀多个 on 表达式的时候统一处理 | 414 | // 尾缀多个 on 表达式的时候统一处理 |
| 309 | if (originOnExpressions.size() > 1) { | 415 | if (originOnExpressions.size() > 1) { |
| 310 | Collection<Expression> onExpressions = new LinkedList<>(); | 416 | Collection<Expression> onExpressions = new LinkedList<>(); |
| 311 | for (Expression originOnExpression : originOnExpressions) { | 417 | for (Expression originOnExpression : originOnExpressions) { |
| 312 | - Table currentTable = tables.poll(); | ||
| 313 | - onExpressions.add(builderExpression(originOnExpression, currentTable)); | 418 | + List<Table> currentTableList = onTableDeque.poll(); |
| 419 | + if (CollectionUtils.isEmpty(currentTableList)) { | ||
| 420 | + onExpressions.add(originOnExpression); | ||
| 421 | + } else { | ||
| 422 | + onExpressions.add(builderExpression(originOnExpression, currentTableList)); | ||
| 423 | + } | ||
| 314 | } | 424 | } |
| 315 | join.setOnExpressions(onExpressions); | 425 | join.setOnExpressions(onExpressions); |
| 316 | } | 426 | } |
| 427 | + leftTable = joinTable; | ||
| 317 | } else { | 428 | } else { |
| 318 | - // 处理右边连接的子表达式 | ||
| 319 | - processFromItem(fromItem); | 429 | + processOtherFromItem(joinItem); |
| 430 | + leftTable = null; | ||
| 320 | } | 431 | } |
| 321 | } | 432 | } |
| 433 | + | ||
| 434 | + return mainTables; | ||
| 322 | } | 435 | } |
| 323 | 436 | ||
| 437 | + // ========== 和 TenantLineInnerInterceptor 存在差异的逻辑:关键,实现权限条件的拼接 ========== | ||
| 438 | + | ||
| 324 | /** | 439 | /** |
| 325 | - * 处理联接语句 | 440 | + * 处理条件 |
| 441 | + * | ||
| 442 | + * @param currentExpression 当前 where 条件 | ||
| 443 | + * @param table 单个表 | ||
| 326 | */ | 444 | */ |
| 327 | - protected void processJoin(Join join) { | ||
| 328 | - if (join.getRightItem() instanceof Table) { | ||
| 329 | - Table fromTable = (Table) join.getRightItem(); | ||
| 330 | - Expression originOnExpression = CollUtil.getFirst(join.getOnExpressions()); | ||
| 331 | - originOnExpression = builderExpression(originOnExpression, fromTable); | ||
| 332 | - join.setOnExpressions(CollUtil.newArrayList(originOnExpression)); | ||
| 333 | - } | 445 | + protected Expression builderExpression(Expression currentExpression, Table table) { |
| 446 | + return this.builderExpression(currentExpression, Collections.singletonList(table)); | ||
| 334 | } | 447 | } |
| 335 | 448 | ||
| 336 | /** | 449 | /** |
| 337 | * 处理条件 | 450 | * 处理条件 |
| 451 | + * | ||
| 452 | + * @param currentExpression 当前 where 条件 | ||
| 453 | + * @param tables 多个表 | ||
| 338 | */ | 454 | */ |
| 339 | - protected Expression builderExpression(Expression currentExpression, Table table) { | ||
| 340 | - // 获得 Table 对应的数据权限条件 | ||
| 341 | - Expression equalsTo = buildDataPermissionExpression(table); | ||
| 342 | - if (equalsTo == null) { // 如果没条件,则返回 currentExpression 默认 | 455 | + protected Expression builderExpression(Expression currentExpression, List<Table> tables) { |
| 456 | + // 没有表需要处理直接返回 | ||
| 457 | + if (CollectionUtils.isEmpty(tables)) { | ||
| 343 | return currentExpression; | 458 | return currentExpression; |
| 344 | } | 459 | } |
| 345 | 460 | ||
| 346 | - // 表达式为空,则直接返回 equalsTo | 461 | + // 第一步,获得 Table 对应的数据权限条件 |
| 462 | + Expression dataPermissionExpression = null; | ||
| 463 | + for (Table table : tables) { | ||
| 464 | + // 构建每个表的权限 Expression 条件 | ||
| 465 | + Expression expression = buildDataPermissionExpression(table); | ||
| 466 | + if (expression == null) { | ||
| 467 | + continue; | ||
| 468 | + } | ||
| 469 | + // 合并到 dataPermissionExpression 中 | ||
| 470 | + dataPermissionExpression = dataPermissionExpression == null ? expression | ||
| 471 | + : new AndExpression(dataPermissionExpression, expression); | ||
| 472 | + } | ||
| 473 | + | ||
| 474 | + // 第二步,合并多个 Expression 条件 | ||
| 475 | + if (dataPermissionExpression == null) { | ||
| 476 | + return currentExpression; | ||
| 477 | + } | ||
| 347 | if (currentExpression == null) { | 478 | if (currentExpression == null) { |
| 348 | - return equalsTo; | 479 | + return dataPermissionExpression; |
| 349 | } | 480 | } |
| 350 | - // 如果表达式为 Or,则需要 (currentExpression) AND equalsTo | 481 | + // ① 如果表达式为 Or,则需要 (currentExpression) AND dataPermissionExpression |
| 351 | if (currentExpression instanceof OrExpression) { | 482 | if (currentExpression instanceof OrExpression) { |
| 352 | - return new AndExpression(new Parenthesis(currentExpression), equalsTo); | 483 | + return new AndExpression(new Parenthesis(currentExpression), dataPermissionExpression); |
| 353 | } | 484 | } |
| 354 | - // 如果表达式为 And,则直接返回 currentExpression AND equalsTo | ||
| 355 | - return new AndExpression(currentExpression, equalsTo); | 485 | + // ② 如果表达式为 And,则直接返回 where AND dataPermissionExpression |
| 486 | + return new AndExpression(currentExpression, dataPermissionExpression); | ||
| 356 | } | 487 | } |
| 357 | 488 | ||
| 358 | /** | 489 | /** |
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptorTest2.java
| @@ -46,7 +46,7 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | @@ -46,7 +46,7 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | ||
| 46 | 46 | ||
| 47 | @Override | 47 | @Override |
| 48 | public Set<String> getTableNames() { | 48 | public Set<String> getTableNames() { |
| 49 | - return asSet("entity", "entity1", "entity2", "t1", "t2", // 支持 MyBatis Plus 的单元测试 | 49 | + return asSet("entity", "entity1", "entity2", "entity3", "t1", "t2", "sys_dict_item", // 支持 MyBatis Plus 的单元测试 |
| 50 | "t_user", "t_role"); // 满足自己的单元测试 | 50 | "t_user", "t_role"); // 满足自己的单元测试 |
| 51 | } | 51 | } |
| 52 | 52 | ||
| @@ -84,30 +84,30 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | @@ -84,30 +84,30 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | ||
| 84 | @Test | 84 | @Test |
| 85 | void delete() { | 85 | void delete() { |
| 86 | assertSql("delete from entity where id = ?", | 86 | assertSql("delete from entity where id = ?", |
| 87 | - "DELETE FROM entity WHERE id = ? AND tenant_id = 1"); | 87 | + "DELETE FROM entity WHERE id = ? AND entity.tenant_id = 1"); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | @Test | 90 | @Test |
| 91 | void update() { | 91 | void update() { |
| 92 | assertSql("update entity set name = ? where id = ?", | 92 | assertSql("update entity set name = ? where id = ?", |
| 93 | - "UPDATE entity SET name = ? WHERE id = ? AND tenant_id = 1"); | 93 | + "UPDATE entity SET name = ? WHERE id = ? AND entity.tenant_id = 1"); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | @Test | 96 | @Test |
| 97 | void selectSingle() { | 97 | void selectSingle() { |
| 98 | // 单表 | 98 | // 单表 |
| 99 | assertSql("select * from entity where id = ?", | 99 | assertSql("select * from entity where id = ?", |
| 100 | - "SELECT * FROM entity WHERE id = ? AND tenant_id = 1"); | 100 | + "SELECT * FROM entity WHERE id = ? AND entity.tenant_id = 1"); |
| 101 | 101 | ||
| 102 | assertSql("select * from entity where id = ? or name = ?", | 102 | assertSql("select * from entity where id = ? or name = ?", |
| 103 | - "SELECT * FROM entity WHERE (id = ? OR name = ?) AND tenant_id = 1"); | 103 | + "SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1"); |
| 104 | 104 | ||
| 105 | assertSql("SELECT * FROM entity WHERE (id = ? OR name = ?)", | 105 | assertSql("SELECT * FROM entity WHERE (id = ? OR name = ?)", |
| 106 | - "SELECT * FROM entity WHERE (id = ? OR name = ?) AND tenant_id = 1"); | 106 | + "SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1"); |
| 107 | 107 | ||
| 108 | /* not */ | 108 | /* not */ |
| 109 | assertSql("SELECT * FROM entity WHERE not (id = ? OR name = ?)", | 109 | assertSql("SELECT * FROM entity WHERE not (id = ? OR name = ?)", |
| 110 | - "SELECT * FROM entity WHERE NOT (id = ? OR name = ?) AND tenant_id = 1"); | 110 | + "SELECT * FROM entity WHERE NOT (id = ? OR name = ?) AND entity.tenant_id = 1"); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | @Test | 113 | @Test |
| @@ -167,10 +167,12 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | @@ -167,10 +167,12 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | ||
| 167 | assertSql("SELECT * FROM entity e WHERE e.id >= (select e1.id from entity1 e1 where e1.id = ?)", | 167 | assertSql("SELECT * FROM entity e WHERE e.id >= (select e1.id from entity1 e1 where e1.id = ?)", |
| 168 | "SELECT * FROM entity e WHERE e.id >= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); | 168 | "SELECT * FROM entity e WHERE e.id >= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); |
| 169 | 169 | ||
| 170 | + | ||
| 170 | /* <= */ | 171 | /* <= */ |
| 171 | assertSql("SELECT * FROM entity e WHERE e.id <= (select e1.id from entity1 e1 where e1.id = ?)", | 172 | assertSql("SELECT * FROM entity e WHERE e.id <= (select e1.id from entity1 e1 where e1.id = ?)", |
| 172 | "SELECT * FROM entity e WHERE e.id <= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); | 173 | "SELECT * FROM entity e WHERE e.id <= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); |
| 173 | 174 | ||
| 175 | + | ||
| 174 | /* <> */ | 176 | /* <> */ |
| 175 | assertSql("SELECT * FROM entity e WHERE e.id <> (select e1.id from entity1 e1 where e1.id = ?)", | 177 | assertSql("SELECT * FROM entity e WHERE e.id <> (select e1.id from entity1 e1 where e1.id = ?)", |
| 176 | "SELECT * FROM entity e WHERE e.id <> (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); | 178 | "SELECT * FROM entity e WHERE e.id <> (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); |
| @@ -204,6 +206,14 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | @@ -204,6 +206,14 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | ||
| 204 | "SELECT * FROM entity e " + | 206 | "SELECT * FROM entity e " + |
| 205 | "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | 207 | "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + |
| 206 | "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1"); | 208 | "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1"); |
| 209 | + | ||
| 210 | + assertSql("SELECT * FROM entity e " + | ||
| 211 | + "left join entity1 e1 on e1.id = e.id " + | ||
| 212 | + "left join entity2 e2 on e1.id = e2.id", | ||
| 213 | + "SELECT * FROM entity e " + | ||
| 214 | + "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 215 | + "LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " + | ||
| 216 | + "WHERE e.tenant_id = 1"); | ||
| 207 | } | 217 | } |
| 208 | 218 | ||
| 209 | @Test | 219 | @Test |
| @@ -212,17 +222,125 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | @@ -212,17 +222,125 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | ||
| 212 | assertSql("SELECT * FROM entity e " + | 222 | assertSql("SELECT * FROM entity e " + |
| 213 | "right join entity1 e1 on e1.id = e.id", | 223 | "right join entity1 e1 on e1.id = e.id", |
| 214 | "SELECT * FROM entity e " + | 224 | "SELECT * FROM entity e " + |
| 215 | - "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 216 | - "WHERE e.tenant_id = 1"); | 225 | + "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " + |
| 226 | + "WHERE e1.tenant_id = 1"); | ||
| 227 | + | ||
| 228 | + assertSql("SELECT * FROM with_as_1 e " + | ||
| 229 | + "right join entity1 e1 on e1.id = e.id", | ||
| 230 | + "SELECT * FROM with_as_1 e " + | ||
| 231 | + "RIGHT JOIN entity1 e1 ON e1.id = e.id " + | ||
| 232 | + "WHERE e1.tenant_id = 1"); | ||
| 217 | 233 | ||
| 218 | assertSql("SELECT * FROM entity e " + | 234 | assertSql("SELECT * FROM entity e " + |
| 219 | "right join entity1 e1 on e1.id = e.id " + | 235 | "right join entity1 e1 on e1.id = e.id " + |
| 220 | "WHERE e.id = ? OR e.name = ?", | 236 | "WHERE e.id = ? OR e.name = ?", |
| 221 | "SELECT * FROM entity e " + | 237 | "SELECT * FROM entity e " + |
| 222 | - "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 223 | - "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1"); | 238 | + "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " + |
| 239 | + "WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1"); | ||
| 240 | + | ||
| 241 | + assertSql("SELECT * FROM entity e " + | ||
| 242 | + "right join entity1 e1 on e1.id = e.id " + | ||
| 243 | + "right join entity2 e2 on e1.id = e2.id ", | ||
| 244 | + "SELECT * FROM entity e " + | ||
| 245 | + "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " + | ||
| 246 | + "RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " + | ||
| 247 | + "WHERE e2.tenant_id = 1"); | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + @Test | ||
| 251 | + void selectMixJoin() { | ||
| 252 | + assertSql("SELECT * FROM entity e " + | ||
| 253 | + "right join entity1 e1 on e1.id = e.id " + | ||
| 254 | + "left join entity2 e2 on e1.id = e2.id", | ||
| 255 | + "SELECT * FROM entity e " + | ||
| 256 | + "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " + | ||
| 257 | + "LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " + | ||
| 258 | + "WHERE e1.tenant_id = 1"); | ||
| 259 | + | ||
| 260 | + assertSql("SELECT * FROM entity e " + | ||
| 261 | + "left join entity1 e1 on e1.id = e.id " + | ||
| 262 | + "right join entity2 e2 on e1.id = e2.id", | ||
| 263 | + "SELECT * FROM entity e " + | ||
| 264 | + "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 265 | + "RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " + | ||
| 266 | + "WHERE e2.tenant_id = 1"); | ||
| 267 | + | ||
| 268 | + assertSql("SELECT * FROM entity e " + | ||
| 269 | + "left join entity1 e1 on e1.id = e.id " + | ||
| 270 | + "inner join entity2 e2 on e1.id = e2.id", | ||
| 271 | + "SELECT * FROM entity e " + | ||
| 272 | + "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 273 | + "INNER JOIN entity2 e2 ON e1.id = e2.id AND e.tenant_id = 1 AND e2.tenant_id = 1"); | ||
| 224 | } | 274 | } |
| 225 | 275 | ||
| 276 | + | ||
| 277 | + @Test | ||
| 278 | + void selectJoinSubSelect() { | ||
| 279 | + assertSql("select * from (select * from entity) e1 " + | ||
| 280 | + "left join entity2 e2 on e1.id = e2.id", | ||
| 281 | + "SELECT * FROM (SELECT * FROM entity WHERE entity.tenant_id = 1) e1 " + | ||
| 282 | + "LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1"); | ||
| 283 | + | ||
| 284 | + assertSql("select * from entity1 e1 " + | ||
| 285 | + "left join (select * from entity2) e2 " + | ||
| 286 | + "on e1.id = e2.id", | ||
| 287 | + "SELECT * FROM entity1 e1 " + | ||
| 288 | + "LEFT JOIN (SELECT * FROM entity2 WHERE entity2.tenant_id = 1) e2 " + | ||
| 289 | + "ON e1.id = e2.id " + | ||
| 290 | + "WHERE e1.tenant_id = 1"); | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + @Test | ||
| 294 | + void selectSubJoin() { | ||
| 295 | + | ||
| 296 | + assertSql("select * FROM " + | ||
| 297 | + "(entity1 e1 right JOIN entity2 e2 ON e1.id = e2.id)", | ||
| 298 | + "SELECT * FROM " + | ||
| 299 | + "(entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " + | ||
| 300 | + "WHERE e2.tenant_id = 1"); | ||
| 301 | + | ||
| 302 | + assertSql("select * FROM " + | ||
| 303 | + "(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id)", | ||
| 304 | + "SELECT * FROM " + | ||
| 305 | + "(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " + | ||
| 306 | + "WHERE e1.tenant_id = 1"); | ||
| 307 | + | ||
| 308 | + | ||
| 309 | + assertSql("select * FROM " + | ||
| 310 | + "(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id) " + | ||
| 311 | + "right join entity3 e3 on e1.id = e3.id", | ||
| 312 | + "SELECT * FROM " + | ||
| 313 | + "(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " + | ||
| 314 | + "RIGHT JOIN entity3 e3 ON e1.id = e3.id AND e1.tenant_id = 1 " + | ||
| 315 | + "WHERE e3.tenant_id = 1"); | ||
| 316 | + | ||
| 317 | + | ||
| 318 | + assertSql("select * FROM entity e " + | ||
| 319 | + "LEFT JOIN (entity1 e1 right join entity2 e2 ON e1.id = e2.id) " + | ||
| 320 | + "on e.id = e2.id", | ||
| 321 | + "SELECT * FROM entity e " + | ||
| 322 | + "LEFT JOIN (entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " + | ||
| 323 | + "ON e.id = e2.id AND e2.tenant_id = 1 " + | ||
| 324 | + "WHERE e.tenant_id = 1"); | ||
| 325 | + | ||
| 326 | + assertSql("select * FROM entity e " + | ||
| 327 | + "LEFT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " + | ||
| 328 | + "on e.id = e2.id", | ||
| 329 | + "SELECT * FROM entity e " + | ||
| 330 | + "LEFT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " + | ||
| 331 | + "ON e.id = e2.id AND e1.tenant_id = 1 " + | ||
| 332 | + "WHERE e.tenant_id = 1"); | ||
| 333 | + | ||
| 334 | + assertSql("select * FROM entity e " + | ||
| 335 | + "RIGHT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " + | ||
| 336 | + "on e.id = e2.id", | ||
| 337 | + "SELECT * FROM entity e " + | ||
| 338 | + "RIGHT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " + | ||
| 339 | + "ON e.id = e2.id AND e.tenant_id = 1 " + | ||
| 340 | + "WHERE e1.tenant_id = 1"); | ||
| 341 | + } | ||
| 342 | + | ||
| 343 | + | ||
| 226 | @Test | 344 | @Test |
| 227 | void selectLeftJoinMultipleTrailingOn() { | 345 | void selectLeftJoinMultipleTrailingOn() { |
| 228 | // 多个 on 尾缀的 | 346 | // 多个 on 尾缀的 |
| @@ -256,51 +374,97 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | @@ -256,51 +374,97 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | ||
| 256 | "inner join entity1 e1 on e1.id = e.id " + | 374 | "inner join entity1 e1 on e1.id = e.id " + |
| 257 | "WHERE e.id = ? OR e.name = ?", | 375 | "WHERE e.id = ? OR e.name = ?", |
| 258 | "SELECT * FROM entity e " + | 376 | "SELECT * FROM entity e " + |
| 259 | - "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 260 | - "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1"); | 377 | + "INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " + |
| 378 | + "WHERE e.id = ? OR e.name = ?"); | ||
| 261 | 379 | ||
| 262 | assertSql("SELECT * FROM entity e " + | 380 | assertSql("SELECT * FROM entity e " + |
| 263 | "inner join entity1 e1 on e1.id = e.id " + | 381 | "inner join entity1 e1 on e1.id = e.id " + |
| 264 | "WHERE (e.id = ? OR e.name = ?)", | 382 | "WHERE (e.id = ? OR e.name = ?)", |
| 265 | "SELECT * FROM entity e " + | 383 | "SELECT * FROM entity e " + |
| 266 | - "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 267 | - "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1"); | 384 | + "INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " + |
| 385 | + "WHERE (e.id = ? OR e.name = ?)"); | ||
| 386 | + | ||
| 387 | + // 隐式内连接 | ||
| 388 | + assertSql("SELECT * FROM entity,entity1 " + | ||
| 389 | + "WHERE entity.id = entity1.id", | ||
| 390 | + "SELECT * FROM entity, entity1 " + | ||
| 391 | + "WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1"); | ||
| 392 | + | ||
| 393 | + // 隐式内连接 | ||
| 394 | + assertSql("SELECT * FROM entity a, with_as_entity1 b " + | ||
| 395 | + "WHERE a.id = b.id", | ||
| 396 | + "SELECT * FROM entity a, with_as_entity1 b " + | ||
| 397 | + "WHERE a.id = b.id AND a.tenant_id = 1"); | ||
| 398 | + | ||
| 399 | + assertSql("SELECT * FROM with_as_entity a, with_as_entity1 b " + | ||
| 400 | + "WHERE a.id = b.id", | ||
| 401 | + "SELECT * FROM with_as_entity a, with_as_entity1 b " + | ||
| 402 | + "WHERE a.id = b.id"); | ||
| 403 | + | ||
| 404 | + // SubJoin with 隐式内连接 | ||
| 405 | + assertSql("SELECT * FROM (entity,entity1) " + | ||
| 406 | + "WHERE entity.id = entity1.id", | ||
| 407 | + "SELECT * FROM (entity, entity1) " + | ||
| 408 | + "WHERE entity.id = entity1.id " + | ||
| 409 | + "AND entity.tenant_id = 1 AND entity1.tenant_id = 1"); | ||
| 410 | + | ||
| 411 | + assertSql("SELECT * FROM ((entity,entity1),entity2) " + | ||
| 412 | + "WHERE entity.id = entity1.id and entity.id = entity2.id", | ||
| 413 | + "SELECT * FROM ((entity, entity1), entity2) " + | ||
| 414 | + "WHERE entity.id = entity1.id AND entity.id = entity2.id " + | ||
| 415 | + "AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1"); | ||
| 416 | + | ||
| 417 | + assertSql("SELECT * FROM (entity,(entity1,entity2)) " + | ||
| 418 | + "WHERE entity.id = entity1.id and entity.id = entity2.id", | ||
| 419 | + "SELECT * FROM (entity, (entity1, entity2)) " + | ||
| 420 | + "WHERE entity.id = entity1.id AND entity.id = entity2.id " + | ||
| 421 | + "AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1"); | ||
| 422 | + | ||
| 423 | + // 沙雕的括号写法 | ||
| 424 | + assertSql("SELECT * FROM (((entity,entity1))) " + | ||
| 425 | + "WHERE entity.id = entity1.id", | ||
| 426 | + "SELECT * FROM (((entity, entity1))) " + | ||
| 427 | + "WHERE entity.id = entity1.id " + | ||
| 428 | + "AND entity.tenant_id = 1 AND entity1.tenant_id = 1"); | ||
| 268 | 429 | ||
| 269 | - // 垃圾 inner join todo | ||
| 270 | -// assertSql("SELECT * FROM entity,entity1 " + | ||
| 271 | -// "WHERE entity.id = entity1.id", | ||
| 272 | -// "SELECT * FROM entity e " + | ||
| 273 | -// "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 274 | -// "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1"); | ||
| 275 | } | 430 | } |
| 276 | 431 | ||
| 432 | + | ||
| 277 | @Test | 433 | @Test |
| 278 | void selectWithAs() { | 434 | void selectWithAs() { |
| 279 | assertSql("with with_as_A as (select * from entity) select * from with_as_A", | 435 | assertSql("with with_as_A as (select * from entity) select * from with_as_A", |
| 280 | - "WITH with_as_A AS (SELECT * FROM entity WHERE tenant_id = 1) SELECT * FROM with_as_A"); | 436 | + "WITH with_as_A AS (SELECT * FROM entity WHERE entity.tenant_id = 1) SELECT * FROM with_as_A"); |
| 437 | + } | ||
| 438 | + | ||
| 439 | + | ||
| 440 | + @Test | ||
| 441 | + void selectIgnoreTable() { | ||
| 442 | + assertSql(" SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)", | ||
| 443 | + "SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id AND item.tenant_id = 1 WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)"); | ||
| 281 | } | 444 | } |
| 282 | 445 | ||
| 283 | private void assertSql(String sql, String targetSql) { | 446 | private void assertSql(String sql, String targetSql) { |
| 284 | assertEquals(targetSql, interceptor.parserSingle(sql, null)); | 447 | assertEquals(targetSql, interceptor.parserSingle(sql, null)); |
| 285 | } | 448 | } |
| 286 | 449 | ||
| 450 | + | ||
| 287 | // ========== 额外的测试 ========== | 451 | // ========== 额外的测试 ========== |
| 288 | 452 | ||
| 289 | @Test | 453 | @Test |
| 290 | public void testSelectSingle() { | 454 | public void testSelectSingle() { |
| 291 | // 单表 | 455 | // 单表 |
| 292 | assertSql("select * from t_user where id = ?", | 456 | assertSql("select * from t_user where id = ?", |
| 293 | - "SELECT * FROM t_user WHERE id = ? AND tenant_id = 1 AND dept_id IN (10, 20)"); | 457 | + "SELECT * FROM t_user WHERE id = ? AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)"); |
| 294 | 458 | ||
| 295 | assertSql("select * from t_user where id = ? or name = ?", | 459 | assertSql("select * from t_user where id = ? or name = ?", |
| 296 | - "SELECT * FROM t_user WHERE (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)"); | 460 | + "SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)"); |
| 297 | 461 | ||
| 298 | assertSql("SELECT * FROM t_user WHERE (id = ? OR name = ?)", | 462 | assertSql("SELECT * FROM t_user WHERE (id = ? OR name = ?)", |
| 299 | - "SELECT * FROM t_user WHERE (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)"); | 463 | + "SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)"); |
| 300 | 464 | ||
| 301 | /* not */ | 465 | /* not */ |
| 302 | assertSql("SELECT * FROM t_user WHERE not (id = ? OR name = ?)", | 466 | assertSql("SELECT * FROM t_user WHERE not (id = ? OR name = ?)", |
| 303 | - "SELECT * FROM t_user WHERE NOT (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)"); | 467 | + "SELECT * FROM t_user WHERE NOT (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)"); |
| 304 | } | 468 | } |
| 305 | 469 | ||
| 306 | @Test | 470 | @Test |
| @@ -329,16 +493,16 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | @@ -329,16 +493,16 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | ||
| 329 | "right join t_role e1 on e1.id = e.id " + | 493 | "right join t_role e1 on e1.id = e.id " + |
| 330 | "WHERE e.id = ? OR e.name = ?", | 494 | "WHERE e.id = ? OR e.name = ?", |
| 331 | "SELECT * FROM t_user e " + | 495 | "SELECT * FROM t_user e " + |
| 332 | - "RIGHT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 333 | - "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)"); | 496 | + "RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " + |
| 497 | + "WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1"); | ||
| 334 | 498 | ||
| 335 | // 条件 e.id = ? OR e.name = ? 带括号 | 499 | // 条件 e.id = ? OR e.name = ? 带括号 |
| 336 | assertSql("SELECT * FROM t_user e " + | 500 | assertSql("SELECT * FROM t_user e " + |
| 337 | "right join t_role e1 on e1.id = e.id " + | 501 | "right join t_role e1 on e1.id = e.id " + |
| 338 | "WHERE (e.id = ? OR e.name = ?)", | 502 | "WHERE (e.id = ? OR e.name = ?)", |
| 339 | "SELECT * FROM t_user e " + | 503 | "SELECT * FROM t_user e " + |
| 340 | - "RIGHT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 341 | - "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)"); | 504 | + "RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " + |
| 505 | + "WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1"); | ||
| 342 | } | 506 | } |
| 343 | 507 | ||
| 344 | @Test | 508 | @Test |
| @@ -348,23 +512,22 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | @@ -348,23 +512,22 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest | ||
| 348 | "inner join entity1 e1 on e1.id = e.id " + | 512 | "inner join entity1 e1 on e1.id = e.id " + |
| 349 | "WHERE e.id = ? OR e.name = ?", | 513 | "WHERE e.id = ? OR e.name = ?", |
| 350 | "SELECT * FROM t_user e " + | 514 | "SELECT * FROM t_user e " + |
| 351 | - "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 352 | - "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)"); | 515 | + "INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " + |
| 516 | + "WHERE e.id = ? OR e.name = ?"); | ||
| 353 | 517 | ||
| 354 | // 条件 e.id = ? OR e.name = ? 带括号 | 518 | // 条件 e.id = ? OR e.name = ? 带括号 |
| 355 | assertSql("SELECT * FROM t_user e " + | 519 | assertSql("SELECT * FROM t_user e " + |
| 356 | - "inner join t_role e1 on e1.id = e.id " + | 520 | + "inner join entity1 e1 on e1.id = e.id " + |
| 357 | "WHERE (e.id = ? OR e.name = ?)", | 521 | "WHERE (e.id = ? OR e.name = ?)", |
| 358 | "SELECT * FROM t_user e " + | 522 | "SELECT * FROM t_user e " + |
| 359 | - "INNER JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 360 | - "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)"); | ||
| 361 | - | ||
| 362 | - // 垃圾 inner join todo | ||
| 363 | -// assertSql("SELECT * FROM entity,entity1 " + | ||
| 364 | -// "WHERE entity.id = entity1.id", | ||
| 365 | -// "SELECT * FROM entity e " + | ||
| 366 | -// "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + | ||
| 367 | -// "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1"); | 523 | + "INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " + |
| 524 | + "WHERE (e.id = ? OR e.name = ?)"); | ||
| 525 | + | ||
| 526 | + // 没有 On 的 inner join | ||
| 527 | + assertSql("SELECT * FROM entity,entity1 " + | ||
| 528 | + "WHERE entity.id = entity1.id", | ||
| 529 | + "SELECT * FROM entity, entity1 " + | ||
| 530 | + "WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1"); | ||
| 368 | } | 531 | } |
| 369 | 532 | ||
| 370 | } | 533 | } |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
| @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil; | @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.SortingField; | 5 | import cn.iocoder.yudao.framework.common.pojo.SortingField; |
| 6 | import com.baomidou.mybatisplus.core.metadata.OrderItem; | 6 | import com.baomidou.mybatisplus.core.metadata.OrderItem; |
| 7 | +import com.baomidou.mybatisplus.core.toolkit.StringPool; | ||
| 7 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; | 8 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| 8 | import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; | 9 | import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; |
| 9 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | 10 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| @@ -78,7 +79,10 @@ public class MyBatisUtils { | @@ -78,7 +79,10 @@ public class MyBatisUtils { | ||
| 78 | * @return Column 对象 | 79 | * @return Column 对象 |
| 79 | */ | 80 | */ |
| 80 | public static Column buildColumn(String tableName, Alias tableAlias, String column) { | 81 | public static Column buildColumn(String tableName, Alias tableAlias, String column) { |
| 81 | - return new Column(tableAlias != null ? tableAlias.getName() + "." + column : column); | 82 | + if (tableAlias != null) { |
| 83 | + tableName = tableAlias.getName(); | ||
| 84 | + } | ||
| 85 | + return new Column(tableName + StringPool.DOT + column); | ||
| 82 | } | 86 | } |
| 83 | 87 | ||
| 84 | } | 88 | } |