Domanda

Per alcuni motivi, vorrei fare un preventivo esplicito di un valore di stringa (diventando parte della query SQL costruita) invece di attendere la citazione implicita eseguita dal metodo cursor.execute sul contenuto di il suo secondo parametro.

Per "quotazione implicita" Voglio dire:

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;"
cursor.execute( query, (value,) ) # value will be correctly quoted

Preferirei qualcosa del genere:

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;" % \
    READY_TO_USE_QUOTING_FUNCTION(value)
cursor.execute( query ) # value will be correctly quoted, too

Questo livello READY_TO_USE_QUOTING_FUNCTION è così basso previsto dalla specifica dell'API di Python DB (non sono riuscito a trovare tale funzionalità in documento PEP 249 ). In caso contrario, forse Psycopg2 fornisce tale funzione? In caso contrario, forse Django offre tale funzione? Preferirei non scrivere questa funzione da solo ...

È stato utile?

Soluzione

Ok, quindi ero curioso e sono andato a vedere la fonte di psycopg2. Si scopre che non ho dovuto andare oltre la cartella degli esempi :)

E sì, questo è specifico per psycopg2. Fondamentalmente, se vuoi solo citare una stringa, dovresti farlo:

from psycopg2.extensions import adapt

print adapt("Hello World'; DROP DATABASE World;")

Ma quello che probabilmente vuoi fare è scrivere e registrare il tuo adattatore;

Nella cartella degli esempi di psycopg2 trovi il file 'myfirstrecipe.py' c'è un esempio di come lanciare e citare un tipo specifico in modo speciale.

Se hai oggetti per le cose che vuoi fare, puoi semplicemente creare un adattatore conforme al protocollo 'IPsycopgSQLQuote' (vedi pydocs per l'esempio myfirstrecipe.py ... in realtà è l'unico riferimento che riesco a trovare a quel nome) che cita il tuo oggetto e poi lo registra in questo modo:

from psycopg2.extensions import register_adapter

register_adapter(mytype, myadapter)

Inoltre, gli altri esempi sono interessanti; esp. 'dialtone.py' e 'simple.py' .

Altri suggerimenti

Suppongo che tu stia cercando la funzione mogrify .

Esempio:

>>> cur.mogrify("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
"INSERT INTO test (num, data) VALUES (42, E'bar')"

Dovresti cercare di evitare di fare le tue citazioni. Non solo sarà specifico del DB come hanno sottolineato le persone, ma i difetti di quotazione sono la fonte dei bug di iniezione SQL.

Se non si desidera passare query e valori separatamente, passare un elenco di parametri:

def make_my_query():
    # ...
    return sql, (value1, value2)

def do_it():
    query = make_my_query()
    cursor.execute(*query)

(Probabilmente ho la sintassi di cursor.execute errata) Il punto qui è che solo perché cursor.execute accetta un numero di argomenti, ciò non significa che devi gestirli tutti separatamente. Puoi gestirli come un unico elenco.

Non credo che tu abbia fornito un ragionamento sufficiente dietro il tuo eludere per fare questo nel modo giusto. Per favore, usa l'API così com'è progettato e non sforzarti così tanto da rendere il tuo codice meno leggibile per il prossimo ragazzo e più fragile.

Questo dipenderà dal DB. Nel caso di MySQLdb, ad esempio, la classe connection ha un metodo letterale che convertirà il valore nella rappresentazione con escape corretta per passare a MySQL (ecco cosa cursore.execute utilizza).

Immagino che Postgres abbia qualcosa di simile, ma non credo che ci sia una funzione per sfuggire ai valori come parte della specifica DB API 2.0.

Questo dipenderà dal database (iirc, mysql consente \ come carattere di escape, mentre qualcosa come l'oracolo prevede che le virgolette vengano raddoppiate: 'my' 'quoted string' ).

Qualcuno mi corregga se sbaglio, ma il metodo a virgolette doppie è il metodo standard.

Potrebbe valere la pena di vedere cosa fanno le altre librerie di astrazioni db (sqlalchemy, cx_Oracle, sqlite, ecc.)

Devo chiedere: perché vuoi incorporare i valori invece di vincolarli?

Il tuo frammento di codice verrebbe visualizzato in questo modo, secondo documenti di estensione psycopg

from psycopg2.extensions import adapt

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;" % \
    adapt(value).getquoted()
cursor.execute( query ) # value will be correctly quoted, too

La funzione getquoted restituisce il valore come stringa quotata e con escape, quindi puoi anche andare: " SELECT * FROM some_table DOVE some_char_field = " + adapt (value) .getquoted () .

PyPika in un'altra buona opzione per la creazione di istruzioni SQL. Esempio di utilizzo (basato su un esempio nella homepage del progetto):

>>> from pypika import Order, Query
>>> Query.from_('customers').select('id', 'fname', 'lname', 'phone').orderby('id', order=Order.desc)
SELECT "id","fname","lname","phone" FROM "customers" ORDER BY "id" DESC

Se usi django potresti voler usare la funzione di quotazione che viene automaticamente adattata al DBMS attualmente configurato:

from django.db import backend
my_quoted_variable = backend.DatabaseOperations().quote_name(myvar)
import re

def db_quote(s):
  return "\"" + re.escape(s) + "\""

può fare il lavoro di semplice quotazione che funziona almeno con MySQL. Ciò di cui abbiamo davvero bisogno, tuttavia, è la funzione cursor.format () che funzionerebbe come cursore.execute () tranne che restituirebbe la query risultante invece di eseguirla. Ci sono momenti in cui non vuoi ancora che la query venga eseguita abbastanza - ad esempio potresti voler prima registrarla o stamparla per il debug prima di procedere con essa.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top