为什么Rails使用带有范围的where子句哈希语法向查询添加"OR 1 = 0"?

Aar*_*ron 18 mysql ruby-on-rails between

我正在研究的项目是在RDS上使用MySQL(特别是mysql2 gem).

当我在where语句中使用包含范围的条件的哈希时,我的查询有点奇怪.

User.where(id: [1..5])
Run Code Online (Sandbox Code Playgroud)

User.where(id: [1...5])
Run Code Online (Sandbox Code Playgroud)

分别导致以下查询:

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))
Run Code Online (Sandbox Code Playgroud)

查询工作完全正常,因为OR FALSE实际上是无操作.我只是想知道为什么Rails或ARel将这个片段添加到查询中.

编辑

看起来可以解释这一点的线ActiveRecord::PredicateBuilder26号线.仍然不知道哈希是如何empty?在那一点,但也许其他人做.

编辑2

这是有趣的.我正在调查菲利普的评论,看看为什么他这样做,因为它似乎只是一个澄清,但他是正确的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)
Run Code Online (Sandbox Code Playgroud)

虽然我仍然不知道为什么 ARel正在添加OR 1=0哪些将永远是假的,看似没必要.这可能是由于Arrays和Ranges的处理方式不同.

pdo*_*obb 11

基于你发现的事实,这[1..5]不是指定范围的正确方法......我已经发现了为什么[1..5]会这样做.为此,我首先发现散列条件中的空数组产生1=0SQL条件:

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

并且,如果检查ActiveRecord :: PredicateBuilder :: ArrayHandler代码,您将看到数组值始终被分区为范围和其他值.

ranges, values = values.partition { |v| v.is_a?(Range) }
Run Code Online (Sandbox Code Playgroud)

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

至于从哪里来的1=0......我认为它来自数据库适配器,但我找不到确切的位置.但是,我会称之为尝试找不到记录.换句话说,WHERE 1=0永远不会返回任何用户,这对于替代SQL是有意义的,因为WHERE id=null它会找到id为null的任何用户(意识到这不是真正正确的SQL语法).这是我在尝试查找id为空集的所有用户时所期望的(即我们不要求nil id或null id或其他).所以,在我的脑海里,把关于确切位置的信息1=0留作黑盒子就可以了.至少我们现在可以推断为什么数组内部的范围导致它出现!

UPDATE

我也发现,即使直接使用ARel,你仍然可以得到1=0:

User.arel_table[:id].in([]).to_sql
# => "1=0"
Run Code Online (Sandbox Code Playgroud)