sql >> Database teknologi >  >> RDS >> Mysql

Hvorfor tilføjer Rails `OR 1=0` til forespørgsler ved hjælp af where-sætningens hash-syntaks med et interval?

Bygger på det faktum, som du har opdaget, at [1..5] er ikke den korrekte måde at angive området på... Jeg har opdaget hvorfor [1..5] opfører sig som den gør. For at komme dertil fandt jeg først ud af, at et tomt array i en hash-tilstand producerer 1=0 SQL-betingelse:

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

Og hvis du tjekker ActiveRecord::PredicateBuilder::ArrayHandler-kode , vil du se, at matrixværdier altid er opdelt i områder og andre værdier.

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

Dette forklarer, hvorfor du ikke kan se 1=0 ved brug af ikke-områdeværdier. Det vil sige den eneste måde at få 1=0 fra et array uden at inkludere et interval er at levere et tomt array, som giver 1=0 tilstand, som vist ovenfor. Og når alt arrayet har i det er et område, vil du få rækkeviddebetingelserne (ranges ) og separat en tom matrix-betingelse (values ) udført. Mit gæt er, at der ikke er en god grund til dette... det er simpelthen nemmere at lade dette være end at undgå det (da resultatsættet er ækvivalent på begge måder). Hvis partitionskoden var en smule smartere, ville den ikke behøve at slå på de yderligere tomme values array og kunne springe 1=0 over tilstand.

Med hensyn til hvor 1=0 kommer fra i første omgang... Jeg tror det kommer fra databaseadapteren, men jeg kunne ikke finde præcis hvor. Jeg vil dog kalde det et forsøg på at undlade at finde en rekord. Med andre ord, WHERE 1=0 kommer aldrig til at returnere nogen brugere, hvilket giver mening i forhold til alternativ SQL som WHERE id=null som vil finde alle brugere, hvis id er null (ved at indse, at dette ikke er den rigtige SQL-syntaks). Og det er, hvad jeg ville forvente, når jeg forsøger at finde alle brugere, hvis id er i det tomme sæt (dvs. vi beder ikke om nul-id'er eller null-id'er eller hvad som helst). Så, i mit sind, forlader jeg lidt om præcis hvor 1=0 kommer fra, da en sort boks er OK. Nu kan vi i det mindste ræsonnere om, hvorfor rækkevidden inde i arrayet får det til at dukke op!

OPDATERING

Jeg har også fundet ud af, at selv når du bruger ARel direkte, kan du stadig få 1=0 :

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


  1. Indsættelse af flere rækker i en tabel ved hjælp af PHP

  2. Vælg mySQL kun baseret på måned og år

  3. Hvordan afslutter jeg et script i SQLPlus, når der opstår en fejl, og vender tilbage til SQLPlus-prompten uden at afbryde eller afslutte SQLPlus?

  4. PostgreSQL CSV import fra kommandolinjen