Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Por que o Rails está adicionando `OR 1=0` às consultas usando a sintaxe de hash da cláusula where com um intervalo?


Com base no fato, que você descobriu, que [1..5] não é a maneira correta de especificar o intervalo... Descobri por que [1..5] se comporta como o faz. Para chegar lá, descobri primeiro que uma matriz vazia em uma condição de hash produz o 1=0 Condição SQL:
User.where(id: []).to_sql
# => "SELECT \"users\".* FROM \"users\"  WHERE 1=0"

E, se você verificar o Código ActiveRecord::PredicateBuilder::ArrayHandler , você verá que os valores de matriz são sempre particionados em intervalos e outros valores.
ranges, values = values.partition { |v| v.is_a?(Range) }

Isso explica por que você não vê o 1=0 ao usar valores fora do intervalo. Ou seja, a única maneira de obter 1=0 de um array sem incluir um intervalo é fornecer um array vazio, que produz o 1=0 condição, como mostrado acima. E quando todo o array tiver um intervalo, você obterá as condições do intervalo (ranges ) e, separadamente, uma condição de array vazia (values ) executado. Meu palpite é que não há uma boa razão para isso ... simplesmente é mais fácil deixar isso acontecer do que evitá-lo (já que o conjunto de resultados é equivalente de qualquer maneira). Se o código da partição fosse um pouco mais inteligente, ele não teria que adicionar os values vazios adicionais array e poderia pular o 1=0 doença.

Quanto a onde o 1=0 vem em primeiro lugar... Acho que vem do adaptador de banco de dados, mas não consegui encontrar exatamente onde. No entanto, eu chamaria isso de uma tentativa de não encontrar um registro. Em outras palavras, WHERE 1=0 nunca retornará nenhum usuário, o que faz sentido em SQL alternativo como WHERE id=null que encontrará qualquer usuário cujo id seja nulo (percebendo que essa não é realmente a sintaxe SQL correta). E isso é o que eu esperaria ao tentar encontrar todos os usuários cujo id está no conjunto vazio (ou seja, não estamos pedindo nil ids ou null ids ou qualquer outra coisa). Então, em minha mente, deixando a parte sobre exatamente onde 1=0 vem como uma caixa preta está OK. Pelo menos agora podemos raciocinar sobre por que o intervalo dentro do array está fazendo com que ele apareça!

ATUALIZAÇÃO


Também descobri que, mesmo usando o ARel diretamente, você ainda pode obter 1=0 :
User.arel_table[:id].in([]).to_sql
# => "1=0"