Comment citer explicitement une valeur de chaîne de caractères (API Python DB / Psycopg2)
pour certaines raisons, je voudrais faire une citation explicite d'une valeur de chaîne (devenant une partie de requête SQL construite) au lieu d'attendre la 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
Est de bas niveau READY_TO_USE_QUOTING_FUNCTION
prévu par Python DB spécification de l'API (Je n'ai pas pu trouver cette fonctionnalité dans le document PEP 249 ). Si non, peut-être Psycopg2 fournit une telle fonction? Si ce n'est pas le cas, peut-être que Django fournit une telle fonction? Je préférerais ne pas écrire une telle fonction moi-même...
9 réponses
Ok, donc j'étais curieux et je suis allé voir la source de psycopg2. S'avère que je n'ai pas eu à aller plus loin que le dossier exemples :)
et oui, c'est spécifique à psycopg2. En gros, si vous voulez juste citer une chaîne de caractères, vous feriez ceci:
from psycopg2.extensions import adapt
print adapt("Hello World'; DROP DATABASE World;")
mais ce que vous voulez probablement faire, c'est écrire et enregistrer votre propre adaptateur;""
Dans le dossier exemples de psycopg2 vous trouvez le fichier "myfirstrecipe.py " il y a un exemple de la façon de mouler et de citer un type spécifique d'une manière spéciale.
si vous avez des objets pour les choses que vous voulez faire, vous pouvez simplement créer un adaptateur qui est conforme au protocole 'IPsycopgSQLQuote' (voir pydocs pour myfirstrecipe.PY-exemple ... en fait, c'est la seule référence que je peux trouver à ce nom) qui cite votre objet et l'enregistrer comme suit:
from psycopg2.extensions import register_adapter
register_adapter(mytype, myadapter)
également, l'autre des exemples sont intéressants; esp. "dialtone.py" et "simple.py " .
, Vous devriez essayer d'éviter de faire votre propre citant. Non seulement il sera spécifique à la base de données comme les gens l'ont fait remarquer, mais les erreurs dans les citations sont la source des bogues D'injection SQL.
si vous ne voulez pas faire circuler les requêtes et les valeurs séparément, faites circuler 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 de curseur.exécuter mal) Le point ici est que juste parce que le curseur.exécuter prend un certain nombre d'arguments, que ne signifie pas que vous devez les traiter séparément. Vous pouvez les traiter comme une seule liste.
Je ne pense pas que vous donnez un raisonnement suffisant derrière votre évitement pour faire cela de la bonne façon. S'il vous plaît, utilisez L'APi telle qu'elle est conçue et n'essayez pas de rendre votre code moins lisible pour le prochain type et plus fragile.
cela va dépendre des PD. Dans le cas de MySQLdb, par exemple, la classe connection
a une méthode literal
qui convertit la valeur à la bonne représentation échappée pour passer à MySQL (c'est ce que cursor.execute
utilise).
J'imagine que Postgres a quelque chose de similaire, mais je ne pense pas qu'il y ait une fonction pour échapper aux valeurs dans le cadre de la spécification de L'API 2.0 de la DB.
ce sera dépendant de la base de données (IIRC, mysql permet \
comme un caractère d'évasion, tandis que quelque chose comme oracle s'attend à ce que les citations soient doublées: 'my '' quoted string'
).
que Quelqu'un me corrige si je me trompe, mais la méthode de double citation est la méthode standard.
il peut être intéressant de regarder ce que font les autres bibliothèques d'abstraction db (sqlalchemy, cx_Oracle, sqlite, etc.).
je dois demander-pourquoi voulez-vous les valeurs au lieu de les lier?
votre code snippet obtiendrait exactement comme ceci, selon psycopg extension docs
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 value
comme chaîne de caractères Citée et échappée, donc vous pouvez aussi aller: "SELECT * FROM some_table WHERE some_char_field = " + adapt(value).getquoted()
.
si vous utilisez django, vous pouvez utiliser la fonction de citation qui est automatiquement adaptée aux SGBD actuellement configurés:
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 simple citation qui fonctionne au moins avec MySQL. Ce dont nous avons vraiment besoin est de curseur.format () fonction qui fonctionnerait comme curseur.execute (), sauf qu'elle serait de retour de la requête au lieu de l'exécuter. Il ya des moments où vous ne voulez pas que la requête à exécuter tout à fait encore - e.g vous pouvez connecter d'abord, ou l'imprimer pour le débogage avant d'aller de l'avant avec elle.