Mysql
 sql >> Base de données >  >> RDS >> Mysql

Pourquoi Rails ajoute-t-il `OR 1=0` aux requêtes utilisant la syntaxe de hachage de la clause where avec une plage ?

S'appuyant sur le fait, que vous avez découvert, que [1..5] n'est pas la bonne façon de spécifier la plage... J'ai découvert pourquoi [1..5] se comporte comme il le fait. Pour y arriver, j'ai d'abord trouvé qu'un tableau vide dans une condition de hachage produit le 1=0 Condition SQL :

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

Et, si vous cochez la case ActiveRecord::PredicateBuilder::ArrayHandler code , vous verrez que les valeurs de tableau sont toujours partitionnées en plages et autres valeurs.

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

Cela explique pourquoi vous ne voyez pas le 1=0 lors de l'utilisation de valeurs hors plage. Autrement dit, la seule façon d'obtenir 1=0 à partir d'un tableau sans inclure une plage est de fournir un tableau vide, ce qui donne le 1=0 état, comme indiqué ci-dessus. Et lorsque tout le tableau contient une plage, vous obtenez les conditions de plage (ranges ) et, séparément, une condition de tableau vide (values ) réalisé. Je suppose qu'il n'y a pas de bonne raison à cela ... il est tout simplement plus facile de laisser cela être que de l'éviter (puisque le jeu de résultats est équivalent dans les deux sens). Si le code de partition était un peu plus intelligent, il n'aurait pas à ajouter les values vides supplémentaires tableau et pourrait ignorer le 1=0 état.

Quant à savoir où le 1=0 vient en premier lieu ... Je pense que cela vient de l'adaptateur de base de données, mais je n'ai pas trouvé exactement où. Cependant, j'appellerais cela une tentative de ne pas trouver un enregistrement. En d'autres termes, WHERE 1=0 ne renverra jamais d'utilisateurs, ce qui est logique par rapport à SQL alternatif comme WHERE id=null qui trouvera tous les utilisateurs dont l'identifiant est nul (en réalisant que ce n'est pas vraiment la syntaxe SQL correcte). Et c'est ce à quoi je m'attendrais en essayant de trouver tous les utilisateurs dont l'identifiant est dans l'ensemble vide (c'est-à-dire que nous ne demandons pas d'identifiants nuls ou d'identifiants nuls ou autre). Donc, dans mon esprit, laisser le bit exactement où 1=0 vient comme une boîte noire est OK. Au moins, nous pouvons maintenant comprendre pourquoi la plage à l'intérieur du tableau le fait apparaître !

MISE À JOUR

J'ai également constaté que, même en utilisant ARel directement, vous pouvez toujours obtenir 1=0 :

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