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

25
demandé sur Dariusz Walczak 2008-11-21 22:47:11

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

28
répondu Henrik Gustafsson 2012-07-13 20:00:05

je suppose que vous cherchez 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')"
14
répondu Beli 2014-07-05 20:46:46

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

2
répondu Ned Batchelder 2008-11-22 00:01:40

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.

1
répondu ironfroggy 2008-11-23 15:17:20

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.

0
répondu davidavr 2008-11-21 20:07:31

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?

0
répondu Richard Levasseur 2008-11-21 20:25:48

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() .

0
répondu Roberto 2012-12-12 21:09:27

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)
-1
répondu vincent 2008-11-23 14:55:11
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.

-1
répondu Sasha Pachev 2013-02-07 23:32:41