当前使用版本(必填,否则不予处理)
v3.5.4.1
该问题是如何引起的?(确定最新版也有问题再提!!!)
BaseMultiTableInnerInterceptor 在执行 processPlainSelect(final PlainSelect plainSelect, final String whereSegment) 方法时逻辑有漏洞
重现步骤(如果有就写完整)
看官方用例MultiDataPermissionInterceptorTest#test6
sqlSegmentMap.put(TEST_6, "sys_user", "u.state=1 and u.amount > 1000");
sqlSegmentMap.put(TEST_6, "sys_user_role", "r.role_id=3 AND r.role_id IN (7,9,11)");
@Test
void test6() {
// 显式指定 JOIN 类型时 JOIN 右侧表才能进行拼接条件
assertSql(TEST_6, "select u.username from sys_user u LEFT join sys_user_role r on u.id=r.user_id",
"SELECT u.username FROM sys_user u LEFT JOIN sys_user_role r ON u.id = r.user_id AND r.role_id = 3 AND r.role_id IN (7, 9, 11) WHERE u.state = 1 AND u.amount > 1000");
}
因为left join 只拼接到了on条件下 会导致 主表还是有数据 只是 left join 不到数据 正确sql应该是
SELECT u.username FROM sys_user u LEFT JOIN sys_user_role r ON u.id = r.user_id AND r.role_id = 3 AND r.role_id IN (7, 9, 11) WHERE u.state = 1 AND u.amount > 1000 and r.role_id=3 AND r.role_id IN (7,9,11)
比如说
SELECT * FROM entity e
left join entity1 e1 on e1.id = e.id
WHERE e.id = ?
变成
SELECT * FROM entity e
LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1
WHERE (e.id = ?) AND e1.tenant_id = 1
目前是变成
SELECT * FROM entity e
LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1
WHERE (e.id = ?)
原因是BaseMultiTableInnerInterceptor这段代码
// 处理 join
List<Join> joins = plainSelect.getJoins();
if (CollectionUtils.isNotEmpty(joins)) {
mainTables = processJoins(mainTables, joins, whereSegment);
}
// 当有 mainTable 时,进行 where 条件追加
if (CollectionUtils.isNotEmpty(mainTables)) {
plainSelect.setWhere(builderExpression(where, mainTables, whereSegment));
}
改成
// 处理 join
List<Join> joins = plainSelect.getJoins();
if (CollectionUtils.isNotEmpty(joins)) {
mainTables = processJoins(mainTables, joins, whereSegment);
for (Join join : joins) {
FromItem rightItem = join.getRightItem();
if(rightItem instanceof Table){
mainTables.add((Table) rightItem);
}
}
}
// 当有 mainTable 时,进行 where 条件追加
if (CollectionUtils.isNotEmpty(mainTables)) {
plainSelect.setWhere(builderExpression(where, mainTables, whereSegment));
}
就可以避免
Comment From: dandelion2
这个后期会修改吗?LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 这种写法在某些数据库大数据量的表下,如pg,性能影响还是有的。放到where里统一过滤条件反而更好