0

这里有张桌子

mysql> select * from people;
ID 性别 姓名
1 남자 김준영</td>
2 남자 박민수</td>
3 여자 김영지
4 남자 준수</td>
5 남자 구준표</td>
6 여자 윤지
7 여자 이혜리</td>
8 여자 권아영</td>
9 여자 김예지
10 남자 준필</td>

10 行一组(0.00 秒)

mysql> select * from people where 0 and (select 1 union select 2);
Empty set (0.00 sec)

mysql> select * from people where id=50 and (select 1 union select 2);
ERROR 1242 (21000): Subquery returns more than 1 row

我正在解决 SQL 注入问题。在第一种情况下,(select~) 命令没有执行,因为 '0 并且' 已经是假的。

我知道“逻辑运算符短路”

没有id=50的列,为什么会出现下面这种情况的错误?

4

2 回答 2

3

与有多少编程语言工作相反,SQL 引擎可以自由选择运算符的操作数的AND评估顺序。这个决定是引擎为查询设计的执行计划的一部分。

在第一种情况下,查询返回而不评估子查询是有道理的,因为 0 是常量,并且引擎不需要访问数据就知道不会有结果。

然而,在第二种情况下,引擎确实需要查询表中的第一个条件,因为它事先并不知道没有id值为 50。而且由于它必须真正为此进行查询,因此它也需要考虑到子查询。由于该子查询不访问任何表,因此首先评估它是一个很好的候选者。这就是引擎发现它返回 2 条记录的时候,这在该上下文中是无效的。

至于你的评论:

我正在解决 SQL 注入问题。

像这样解决 SQL 注入是非常糟糕的做法。您应该编译您的 SQL 语句,并将变量绑定到该编译语句。这就是以可靠的方式防止 SQL 注入的方法。

于 2020-12-30T10:23:53.783 回答
0

另一个答案具有误导性,因为您所看到的与 order of evaluation无关。它与查询的整体处理有关。

SQL 查询在不同的步骤中处理。第一步是编译查询。二是优化执行计划,三是执行查询。

在优化阶段,MySQL 检查where子句中的常量条件。这称为常量条件删除,并且有据可查

在第一个查询中发生的情况是 MySQL 看到0条件中的常量,将其识别为 false,并且(因为所有其他条件都被and编入它)将where子句替换为where 0. 第二个或附加条件不相关,因此将其删除。答案在编译过程中是已知的。

在第二种情况下,MySQL 必须实际查看数据。没有机会进行这种优化。

确实,执行阶段表达式的求值顺序也由优化器决定。但是,这与您在此处提出的问题无关。

我非常同意这样的评论和观点,即这不是解决任何类型的 SQL 注入问题的正确方法。事实上,我什至看不出它有什么帮助。使用参数。

于 2020-12-30T13:41:00.273 回答