Question

Pour certaines raisons, je voudrais faire une citation explicite d'une valeur de chaîne (faisant désormais partie d'une requête SQL construite) au lieu d'attendre une citation implicite effectuée par la méthode cursor.execute sur le contenu de son deuxième paramètre.

Par "citation implicite" Je veux dire:

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

Je préférerais quelque chose comme ça:

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

Ce READY_TO_USE_QUOTING_FUNCTION de bas niveau est-il attendu par la spécification d'API de base de données Python (je ne pouvais pas trouver cette fonctionnalité dans PEP 249 ). Si non, peut-être que Psycopg2 fournit une telle fonction? Si non, peut-être que Django fournit une telle fonction? Je préférerais ne pas écrire cette fonction moi-même ...

Était-ce utile?

La solution

Ok, alors j'étais curieux et je suis allé regarder la source de psycopg2. Il s'avère que je n'ai pas eu à aller plus loin que le dossier des exemples:)

Et oui, ceci est spécifique à psycopg2. En gros, si vous voulez juste citer une chaîne, vous ferez ceci:

from psycopg2.extensions import adapt

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

Mais vous voudrez probablement écrire et enregistrer votre propre adaptateur;

Dans le dossier des exemples de psycopg2, vous trouverez le fichier 'myfirstrecipe.py' il existe un exemple montrant comment convertir et citer un type spécifique de manière spéciale.

Si vous avez des objets pour ce que vous voulez faire, vous pouvez simplement créer un adaptateur conforme au protocole 'IPsycopgSQLQuote' (voir pydocs pour myfirstrecipe.py-example ... en fait, c'est la seule référence que je puisse trouver. à ce nom) qui cite votre objet puis l’enregistre comme suit:

from psycopg2.extensions import register_adapter

register_adapter(mytype, myadapter)

De plus, les autres exemples sont intéressants. esp. 'dialtone.py' et 'simple.py' .

Autres conseils

Je suppose que vous recherchez la fonction mogrify .

Exemple:

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

Vous devriez essayer d’éviter de faire vos propres citations. Comme il a déjà été souligné, cette fonction dépend non seulement de la base de données, mais elle est également source de bogues d’injection SQL.

Si vous ne souhaitez pas transmettre les requêtes et les valeurs séparément, transmettez une liste des paramètres:

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

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

(j'ai probablement la syntaxe suivante: curseur.execute faux) Le fait est que ce n'est pas parce que cursor.execute prend un certain nombre d'arguments que cela ne signifie pas que vous devez tous les gérer séparément. Vous pouvez les traiter comme une seule liste.

Je ne pense pas que vous donniez un raisonnement suffisant derrière votre évitement pour faire cela dans le bon sens. S'il vous plaît, utilisez l'API comme il est conçu et n'essayez pas si fort de rendre votre code moins lisible par le prochain utilisateur et plus fragile.

Cela dépendra de la base de données. Dans le cas de MySQLdb, par exemple, la classe connection a une méthode literal qui convertit la valeur en représentation échappée correcte pour la passer à MySQL (c'est ce que curseur.exécute utilise).

J'imagine que Postgres a quelque chose de similaire, mais je ne pense pas qu'il existe une fonction permettant d'échapper des valeurs dans le cadre de la spécification DB API 2.0.

Cela dépendra de la base de données (iirc, mysql autorise \ en tant que caractère d'échappement, tandis que quelque chose comme oracle s'attend à ce que les guillemets soient doublés: 'ma' 'chaîne' entre guillemets ').

Quelqu'un me corrige si je me trompe, mais la méthode des guillemets doubles est la méthode standard.

Il peut être utile de regarder ce que font les autres bibliothèques d'abstraction de base de données (sqlalchemy, cx_Oracle, sqlite, etc.).

Je dois demander: pourquoi voulez-vous intégrer les valeurs au lieu de les lier?

Votre extrait de code deviendrait exactement comme ceci, selon les documents d'extension 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 fonction getquoted renvoie la valeur en tant que chaîne entre guillemets et caractères d'échappement. Vous pouvez donc également utiliser: "SELECT * FROM une_table WHERE une_char_field = " + adapt (valeur) .getquoted () .

PyPika constitue une autre bonne solution pour créer des instructions SQL. Exemple d'utilisation (basé sur un exemple de la page d'accueil du projet):

>>> 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

Si vous utilisez django, vous voudrez peut-être utiliser la fonction de citation qui est automatiquement adaptée au SGBD actuellement configuré:

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

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

peut faire le travail de citations simples qui fonctionnent au moins avec MySQL. Ce dont nous avons vraiment besoin, c’est bien la fonction cursor.format () qui fonctionnerait comme cursor.execute (), sauf qu’elle renverrait la requête résultante au lieu de l’exécuter. Il arrive parfois que vous ne vouliez pas que la requête soit encore exécutée, par exemple, vous voudrez peut-être la consigner d'abord ou l'imprimer pour le débogage avant de poursuivre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top