2011-03-10 17 views
29

Utilizo el siguiente código en Python (con pyodbc para una base de MS-Access).Cómo ver la consulta SQL real en Python cursor.execute

cursor.execute("select a from tbl where b=? and c=?", (x, y)) 

Está bien pero, para fines de mantenimiento, necesito saber el envío completo y exacto de cadenas SQL a la base de datos.
¿Es posible y cómo?

Respuesta

4

La respuesta es: NO. he puesto mi pregunta sobre el proyecto principal de Google Code (y en el grupo de Google) es la respuesta es:

comentario # 1 en el tema 163 por l ... @ deller.id.au: cursor. mogrify volver cadena de consulta http://code.google.com/p/pyodbc/issues/detail?id=163

Como referencia aquí hay un enlace a la documentación pyscopg de su "mogrify" método de cursor que el reportero se refiere a: http://initd.org/psycopg/docs/cursor.html#cursor.mogrify

pyodbc no realiza una n tales traducciones del SQL: pasa SQL parametrizado directamente a el controlador ODBC al pie de la letra. El único proceso involucrado es la traducción de los parámetros de los objetos Python a los tipos C compatibles con la API ODBC.

alguna transformación en el SQL puede ser realizado en el controlador ODBC antes de que se envía al servidor (por ejemplo, Microsoft SQL Native Client hace esto) pero estas transformaciones se oculta a pyodbc.

En consecuencia, creo que no es factible proporcionar una función de mogrify en pyodbc.

+1

Es ciertamente posible. Simplemente significa volver a implementar las transformaciones realizadas por el controlador ODBC. Normalmente esto solo será un escape. –

-1

escribir la cadena SQL y luego ejecutarlo:

sql='''select a 
     from tbl 
     where b=? 
     and c=? ''' 

cursor.execute(sql, x, y) 
print 'just executed:',(sql, x,y) 

Ahora usted puede hacer lo que quiera con la instrucción SQL.

+4

No es tan bueno para evitar la inyección SQL ... – FerranB

+0

No es bueno también para mí: paso las variables en 'ejecutar' por diferentes motivos, inyección de SQL pero también porque la función 'ejecutar' modifica la consulta SQL según la Base de Datos escriba y escriba las columnas. Ejemplo: puedo pasar un campo de cadena o número entero o fecha sin preocuparme de citarlos en la consulta. – philnext

2

Dependiendo del controlador que utilice, esto puede o no ser posible. En algunas bases de datos, los parámetros (? s) simplemente se reemplazan, como sugiere la respuesta del usuario 589983 (aunque el controlador tendrá que hacer cosas como cotizar cadenas y escapes de cotizaciones dentro de esas cadenas, para dar como resultado una declaración que sea ejecutable).

Otros controladores solicitarán a la base de datos que compile ("prepare") la declaración y luego le pidan que ejecute la instrucción preparada utilizando los valores dados. De esta forma, el uso de sentencias preparadas o parametrizadas ayuda a evitar las inyecciones de SQL: en el momento en que se ejecuta la declaración, la base de datos "sabe" qué parte del SQL desea ejecutar y qué parte de un valor se usa dentro de esa declaración.

A juzgar por un desnatado rápido del PyODBC documentation, no parece que sea posible obtener el SQL real, pero puedo estar equivocado.

+0

Sí, hoy no puedo ver la información en el documento. – philnext

33

Se diferencia por el controlador. Aquí hay dos ejemplos:

import MySQLdb 
mc = MySQLdb.connect() 
r = mc.cursor() 
r.execute('select %s, %s', ("foo", 2)) 
r._executed 
"select 'foo', 2" 

import psycopg2 
pc = psycopg2.connect() 
r = pc.cursor() 
r.execute('select %s, %s', ('foo', 2)) 
r.query 
"select E'foo', 2" 
+6

en psycopg2 también está el método 'mogrify()' del cursor, que le permite ver exactamente qué comando sería ejecutado por una consulta dada sin (o antes) ejecutarlo. – kindall

+5

En MySQLdb ** '_ last_executed' ** contiene la última cadena de consulta para ejecutar incluso cuando se produce una excepción. La propiedad ** _ ejecutada ** es Ninguna si es un error. [http://stackoverflow.com/a/7190914/653372] – nergeia

+0

La op específicamente dice pyodbc para MS Access. No MySQL o Postgres – ThatAintWorking

2

Para depurar el purpuse Creé una función de verificación que simplemente reemplaza? con los valores de consulta ... no es de alta tecnología :) ¡pero funciona! : D

def check_sql_string(sql, values): 
    unique = "%PARAMETER%" 
    sql = sql.replace("?", unique) 
    for v in values: sql = sql.replace(unique, repr(v), 1) 
    return sql 

query="""SELECT * FROM dbo.MA_ItemsMonthlyBalances 
        WHERE Item = ? AND Storage = ? AND FiscalYear = ? AND BalanceYear = ? AND Balance = ? AND BalanceMonth = ?""" 
values = (1,2,"asdasd",12331, "aas)",1) 

print(check_sql_string(query,values)) 

El resultado:

SELECT * FROM dbo.MA_ItemsMonthlyBalances cuando el punto = 1 y almacenamiento = 2 Y FiscalYear = 'asdasd' Y BalanceYear = 12331 y el equilibrio = 'aas') y BalanceMonth = 1

con esto se puede registrar o hacer lo que quiera:

rowcount = self.cur.execute(query,values).rowcount 
logger.info(check_sql_string(query,values)) 

Si necesita sólo tiene que añadir alguna excepción de captura a la función.

1

Me echa cursor._last_executed después, pero si usted quiere que imprimen en tiempo real sin tener que cambiar cada ejecuto probar este parche mono:

def log_queries(cur): 
    def _query(q): 
     print q # could also use logging 
     return cur._do_query(q) 
    cur._query = _query 

conn = MySQLdb.connect(read_default_file='~/.my.cnf') 
cur = conn.cursor() 
log_queries(cur) 
cur.execute('SELECT %s, %s, %s', ('hello','there','world')) 

Es muy dependiente MySQLdb (y se puede romper más tarde versiones). Funciona porque cur._query actualmente simplemente llama a calls._do_query y devuelve su resultado.

3

Puede usar print cursor._last_executed para obtener la última consulta ejecutada.

Lea en this responda que también puede usar print cursor.mogrify(query,list) para ver la consulta completa antes o después de la ejecución.

Cuestiones relacionadas