sql >> Database >  >> RDS >> Mysql

Waarom voegt Rails `OR 1=0` toe aan query's met behulp van de hash-syntaxis van de where-clausule met een bereik?

Voortbouwend op het feit, dat je hebt ontdekt, dat [1..5] is niet de juiste manier om het bereik te specificeren... Ik heb ontdekt waarom [1..5] gedraagt ​​zich zoals het doet. Om daar te komen, ontdekte ik eerst dat een lege array in een hash-voorwaarde de 1=0 . produceert SQL-voorwaarde:

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

En als je de ActiveRecord::PredicateBuilder::ArrayHandler-code , zult u zien dat matrixwaarden altijd worden opgedeeld in bereiken en andere waarden.

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

Dit verklaart waarom je de 1=0 . niet ziet bij gebruik van niet-bereikwaarden. Dat wil zeggen, de enige manier om 1=0 . te krijgen van een array zonder een bereik op te nemen, is het leveren van een lege array, wat de 1=0 . oplevert staat, zoals hierboven weergegeven. En als de hele array een bereik heeft, krijg je de bereikvoorwaarden (ranges ) en, afzonderlijk, een lege matrixvoorwaarde (values ) uitgevoerd. Mijn gok is dat hier geen goede reden voor is ... het is gewoon gemakkelijker om dit te laten zijn dan om het te vermijden (aangezien de resultatenset hoe dan ook gelijk is). Als de partitiecode wat slimmer zou zijn, dan zou hij niet de extra, lege values moeten gebruiken array en kan de 1=0 . overslaan staat.

Wat betreft waar de 1=0 komt in de eerste plaats... Ik denk dat dat van de database-adapter komt, maar ik kon niet precies vinden waar. Ik zou het echter een poging willen noemen om geen record te vinden. Met andere woorden, WHERE 1=0 zal nooit gebruikers retourneren, wat logisch is boven alternatieve SQL zoals WHERE id=null die alle gebruikers zal vinden wiens id null is (beseffend dat dit niet echt de juiste SQL-syntaxis is). En dit is wat ik zou verwachten als ik probeer alle gebruikers te vinden wiens ID in de lege set staat (d.w.z. we vragen niet om nul-ID's of nul-ID's of wat dan ook). Dus, in mijn gedachten, laat ik het stukje over precies waar 1=0 komt uit als een zwarte doos is OK. We kunnen nu tenminste redeneren waarom het bereik binnen de array ervoor zorgt dat het wordt weergegeven!

UPDATE

Ik heb ook ontdekt dat, zelfs als je ARel rechtstreeks gebruikt, je nog steeds 1=0 . kunt krijgen :

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


  1. PostgreSQL:serieel versus identiteit

  2. Logboekregistratie inschakelen voor SQL-instructies bij gebruik van JDBC

  3. Dynamisch PHP-object maken op basis van string

  4. PostgreSQL-waarde uit vorige rij gebruiken als deze ontbreekt