mybatis-plus icon indicating copy to clipboard operation
mybatis-plus copied to clipboard

别名带有SQL转义字符 ` 导致分页优化了LEFT JOIN

Open code-brandon opened this issue 1 year ago • 6 comments

当前使用版本(必填,否则不予处理)

mybatis-plus-extension-3.5.3.1.jar

该问题是如何引起的?(确定最新版也有问题再提!!!)

在自定义插件拦截器 拼写SQL时,交给分页插件时分页插件优化了LEFT(根据优化条件:条件中包含了 LEFT JOIN 表 的别名 不进行移除,而我的SQL条件中是存在的)

SELECT
	su.`user_id`,
	su.`dept_id`,
	su.`username`,
	su.`nick_name`,
	su.`user_type`,
	su.`email`,
	su.`phonenumber`,
	su.`sex`,
	su.`avatar`,
	su.`status`,
	su.`del_flag`,
	su.`login_ip`,
	su.`login_date`,
	su.`create_by`,
	su.`create_time`,
	su.`update_by`,
	su.`update_time`,
	su.`remark`,
	sd.dept_name 
FROM
	sys_user su
	LEFT JOIN sys_dept sd ON su.dept_id = sd.dept_id 
WHERE
	su.del_flag = '0' 
	AND (
		`sd`.dept_id = 105 
		OR `su`.dept_id IN (
		SELECT
			dept_id 
		FROM
			`sys_role_dept` 
		WHERE
		FIND_IN_SET( role_id, '2,100' ))) 
ORDER BY
	su.`create_time`

优化后:

SELECT
	COUNT(*) AS total 
FROM
	sys_user su 
WHERE
	su.del_flag = '0' 
	AND (
		`sd`.dept_id = 105 
		OR `su`.dept_id IN (
		SELECT
			dept_id 
		FROM
			`sys_role_dept` 
	WHERE
	FIND_IN_SET( role_id, '2,100' )))

DEUBG后发现此段代码:

if (rightItem instanceof Table) {
    Table table = (Table) rightItem;
    str = Optional.ofNullable(table.getAlias()).map(Alias::getName).orElse(table.getName()) + StringPool.DOT;
} else if (rightItem instanceof SubSelect) {
    SubSelect subSelect = (SubSelect) rightItem;
    /* 如果 left join 是子查询,并且子查询里包含 ?(代表有入参) 或者 where 条件里包含使用 join 的表的字段作条件,就不移除 join */
    if (subSelect.toString().contains(StringPool.QUESTION_MARK)) {
        canRemoveJoin = false;
        break;
    }
    str = subSelect.getAlias().getName() + StringPool.DOT;
}
// 不区分大小写
str = str.toLowerCase();

if (whereS.contains(str)) {
    /* 如果 where 条件里包含使用 join 的表的字段作条件,就不移除 join */
    canRemoveJoin = false;
    break;
}

str = subSelect.getAlias().getName() + StringPool.DOT; 只是alias + . 而少了 MYSQL 转义字符 `

重现步骤(如果有就写完整)

报错信息

code-brandon avatar Feb 27 '23 06:02 code-brandon

去掉转义字符

miemieYaho avatar Feb 27 '23 07:02 miemieYaho

是否具有转义字符的两个sql是等价的,mp应该对这两种情况都做好兼容和支持。个人觉得,不应该强制用户不加转义字符

timnick-snow avatar Feb 27 '23 08:02 timnick-snow

为了你目前这种极端情况添加判断也没必要

miemieYaho avatar Feb 27 '23 09:02 miemieYaho

是否具有转义字符的两个sql是等价的,mp应该对这两种情况都做好兼容和支持。个人觉得,不应该强制用户不加转义字符

我觉得也是,我是用转义字符 是为了避免别名与关键字冲突,也是为了兼容一下框架的CRUD,框架的CRUD似乎没有加入别名,出于此考虑才选择拼接SQL时使用转义字符包裹

code-brandon avatar Feb 27 '23 10:02 code-brandon

干脆自己重新写一个. 或者fork自己改改.

是否具有转义字符的两个sql是等价的,mp应该对这两种情况都做好兼容和支持。个人觉得,不应该强制用户不加转义字符

javaofferss avatar Mar 02 '23 01:03 javaofferss

为了你目前这种极端情况添加判断也没必要

这边也遇到了这段代码引发的问题,走的是第一个if分支。

select * from a left join `b` on a.x = b.x where b.y = xxx
if (rightItem instanceof Table) {
    Table table = (Table) rightItem;
    str = Optional.ofNullable(table.getAlias()).map(Alias::getName).orElse(table.getName()) + StringPool.DOT;
} 

虽然修改sql就能规避这个问题,但是给框架使用带来了极大的影响,不清楚的人都需要跟着debug一遍源码才知道问题所在

建议在判断条件是否覆盖left join右侧的表时,把可能的`字符去除掉

missfine avatar Sep 01 '23 07:09 missfine