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

Perché Rails sta aggiungendo `OR 1=0` alle query utilizzando la sintassi hash della clausola where con un intervallo?

Basandosi sul fatto, che hai scoperto, che [1..5] non è il modo corretto per specificare l'intervallo... ho scoperto perché [1..5] si comporta come fa. Per arrivarci, per prima cosa ho scoperto che un array vuoto in una condizione hash produce il 1=0 Condizione SQL:

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

E, se controlli ActiveRecord::PredicateBuilder::Codice ArrayHandler , vedrai che i valori dell'array sono sempre partizionati in intervalli e altri valori.

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

Questo spiega perché non vedi 1=0 quando si utilizzano valori non compresi nell'intervallo. Cioè, l'unico modo per ottenere 1=0 da un array senza includere un intervallo è fornire un array vuoto, che restituisce il 1=0 condizione, come mostrato sopra. E quando tutto ciò che l'array contiene è un intervallo, otterrai le condizioni dell'intervallo (ranges ) e, separatamente, una condizione di matrice vuota (values ) eseguito. La mia ipotesi è che non ci sia una buona ragione per questo ... semplicemente è più facile lasciare che sia così che evitarlo (poiché il set di risultati è equivalente in entrambi i casi). Se il codice della partizione fosse un po' più intelligente, non dovrebbe aggiungere i values vuoti aggiuntivi array e potrebbe saltare il 1=0 condizione.

Per quanto riguarda dove il 1=0 viene da in primo luogo ... Penso che provenga dall'adattatore del database, ma non sono riuscito a trovare esattamente dove. Tuttavia, lo definirei un tentativo di non riuscire a trovare un record. In altre parole, WHERE 1=0 non restituirà mai alcun utente, il che ha senso su SQL alternativo come WHERE id=null che troverà tutti gli utenti il ​​cui ID è nullo (rendendosi conto che questa non è la sintassi SQL realmente corretta). E questo è quello che mi aspetterei quando tento di trovare tutti gli utenti il ​​cui ID è nel set vuoto (cioè non stiamo chiedendo ID nulli o ID nulli o altro). Quindi, nella mia mente, lasciando il bit su dove esattamente 1=0 viene da come una scatola nera è OK. Almeno ora possiamo ragionare sul motivo per cui l'intervallo all'interno dell'array lo sta causando!

AGGIORNAMENTO

Ho anche scoperto che, anche utilizzando ARel direttamente, puoi comunque ottenere 1=0 :

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