sql >> Base de Datos >  >> RDS >> Mysql

¿Por qué Rails agrega `OR 1=0` a las consultas que utilizan la sintaxis hash de la cláusula where con un rango?

Sobre la base del hecho, que ha descubierto, que [1..5] no es la forma correcta de especificar el rango... He descubierto por qué [1..5] se comporta como lo hace. Para llegar allí, primero descubrí que una matriz vacía en una condición hash produce el 1=0 Condición SQL:

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

Y, si marca ActiveRecord::PredicateBuilder::ArrayHandler código , verá que los valores de matriz siempre se dividen en rangos y otros valores.

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

Esto explica por qué no ves el 1=0 cuando se utilizan valores que no son de rango. Es decir, la única forma de obtener 1=0 de una matriz sin incluir un rango es proporcionar una matriz vacía, lo que produce el 1=0 condición, como se muestra arriba. Y cuando todo lo que contiene la matriz es un rango, obtendrá las condiciones del rango (ranges ) y, por separado, una condición de matriz vacía (values ) ejecutado. Supongo que no hay una buena razón para esto... simplemente es más fácil dejarlo así que evitarlo (ya que el conjunto de resultados es equivalente de cualquier manera). Si el código de partición fuera un poco más inteligente, entonces no tendría que agregar los values vacíos adicionales. matriz y podría omitir el 1=0 condición.

En cuanto a dónde está el 1=0 proviene en primer lugar... Creo que proviene del adaptador de la base de datos, pero no pude encontrar exactamente dónde. Sin embargo, yo lo llamaría un intento de no encontrar un registro. En otras palabras, WHERE 1=0 nunca devolverá ningún usuario, lo que tiene sentido sobre SQL alternativo como WHERE id=null que encontrará cualquier usuario cuya identificación sea nula (dándose cuenta de que esta no es realmente la sintaxis SQL correcta). Y esto es lo que esperaría al intentar encontrar a todos los usuarios cuya identificación está en el conjunto vacío (es decir, no estamos solicitando identificaciones nulas o identificaciones nulas o lo que sea). Entonces, en mi mente, dejar el bit exactamente donde 1=0 viene como una caja negra está bien. ¡Al menos ahora podemos razonar acerca de por qué el rango dentro de la matriz hace que aparezca!

ACTUALIZAR

También descubrí que, incluso cuando usa ARel directamente, todavía puede obtener 1=0 :

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