mysql - 为什么 Rails 使用带范围的 where 子句哈希语法将 `OR 1=0` 添加到查询中?

标签 mysql ruby-on-rails between

我正在从事的项目是在 RDS 上使用 MySQL(特别是 mysql2 gem)。

当我在 where 语句中使用包含范围的条件散列时,我的查询中添加了一些奇怪的内容。

User.where(id: [1..5])

User.where(id: [1...5])

分别产生如下查询:

SELECT `users`.* FROM `users` WHERE ((`users`.`id` BETWEEN 1 AND 5 OR 1=0))
SELECT `users`.* FROM `users` WHERE ((`users`.`id` >= 1 AND `users`.`id` < 5 OR 1=0))

查询工作得很好,因为 OR FALSE 实际上是一个空操作。我只是想知道为什么 Rails 或 ARel 将这段代码添加到查询中。

编辑

看起来可以解释这是line 26 in ActiveRecord::PredicateBuilder .仍然不知道散列怎么可能是 empty? ,但也许其他人知道。

编辑 2

这很有趣。我正在研究 Filip 的评论,看看他为什么要发表评论,因为它看起来只是一种澄清,但他是正确的 1..5 != [1..5]。前者是从 1 到 5 的包含范围,而后者是一个数组,其第一个元素前者。我尝试将它们放入 ARel where 调用中以查看生成的 SQL,但 OR 1=0 不存在!

User.where(id: 1..5) #=> SELECT "users".* FROM "users"  WHERE ("users"."id" BETWEEN 1 AND 5)
User.where(id: 1...5) #=> SELECT "users".* FROM "users"  WHERE ("users"."id" >= 1 AND "users"."id" < 5)

虽然我仍然不知道为什么 ARel 添加了OR 1=0,但它始终是错误的并且看似不必要。这可能是由于 ArrayRange 的处理方式不同。

最佳答案

基于您发现的事实,[1..5] 不是指定范围的正确方法...我发现了为什么 [1. .5] 的行为与它一样。为了到达那里,我首先发现散列条件中的空数组会产生 1=0 SQL 条件:

User.where(id: []).to_sql
# => "SELECT \"users\".* FROM \"users\"  WHERE 1=0"

而且,如果您查看 ActiveRecord::PredicateBuilder::ArrayHandler code ,您会看到数组值总是被划分为范围和其他值。

ranges, values = values.partition { |v| v.is_a?(Range) }

这解释了为什么您在使用非范围值时看不到 1=0。也就是说,从数组中获取 1=0 而不包含范围的唯一方法是提供一个空数组,这会产生 1=0 条件,如上所示.当数组中的所有数组都是一个范围时,您将获得范围条件(ranges),并分别执行一个空数组条件(values)。我的猜测是,这没有充分的理由......只是让它变得比避免它更容易(因为结果集是等效的)。如果分区代码更聪明一点,那么它就不必添加额外的空 values 数组,并且可以跳过 1=0 条件。

至于 1=0 首先来自哪里......我认为来自数据库适配器,但我找不到确切的位置。但是,我将其称为未能找到记录的尝试。换句话说,WHERE 1=0 永远不会返回任何用户,这比 WHERE id=null 之类的替代 SQL 更有意义,后者会找到任何 id 的用户为空(意识到这不是真正正确的 SQL 语法)。这就是我在尝试查找 id 在空集中的所有用户时所期望的(即,我们不要求 nil id 或 null id 或其他任何东西)。因此,在我看来,将关于 1=0 的确切来源的部分保留为黑匣子是可以的。至少我们现在可以推断为什么数组内部的范围会导致它出现!

更新

我还发现,即使直接使用ARel,还是可以得到1=0:

User.arel_table[:id].in([]).to_sql
# => "1=0"

关于mysql - 为什么 Rails 使用带范围的 where 子句哈希语法将 `OR 1=0` 添加到查询中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21886242/

相关文章:

python - 计算列表中其他元素之间特定元素的数量

php - 如果页面刷新如何取消保存

php - 使用 PHPMyAdmin 并创建一个包含多个条目的列?

ruby-on-rails - 在 rails3 的连接查询中获取不同的记录

ruby-on-rails - Capistrano 3. shared_pa​​th 变量中的错误路径

sql - t-sql : Flipping a BETWEEN operator depending on row value

Mysql 与 Between\in 范围条件

mysql - 如何使用代理设置在 Windows 7 上安装 RMysql

php - MySQL服务器不见了

ruby-on-rails - Rails 如何查询关联定义