29

由于某些原因,我想对字符串值进行显式引用(成为构造 SQL 查询的一部分),而不是等待cursor.execute方法对其第二个参数的内容执行隐式引用。

“隐式引用”是指:

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

我更喜欢这样的东西:

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

Python DB API 规范是否期望如此低的级别(我在PEP 249文档READY_TO_USE_QUOTING_FUNCTION中找不到这样的功能)。如果没有,也许 Psycopg2 提供了这样的功能?如果没有,也许 Django 提供了这样的功能?我不想自己写这样的函数......

4

10 回答 10

33

好的,所以我很好奇,去看了psycopg2的来源。原来我不必比示例文件夹走得更远:)

是的,这是特定于 psycopg2 的。基本上,如果你只想引用一个字符串,你可以这样做:

from psycopg2.extensions import adapt

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

但是您可能想要做的是编写和注册自己的适配器;

在 psycopg2 的示例文件夹中,您可以找到文件“myfirstrecipe.py”,其中有一个如何以特殊方式转换和引用特定类型的示例。

如果你有你想做的事情的对象,你可以只创建一个符合“IPsycopgSQLQuote”协议的适配器(请参阅 pydocs 以获取 myfirstrecipe.py-example ......实际上这是我能找到的唯一参考该名称) 引用您的对象,然后像这样注册它:

from psycopg2.extensions import register_adapter

register_adapter(mytype, myadapter)

此外,其他示例也很有趣。尤其是 'dialtone.py''simple.py'

于 2008-11-23T11:47:54.167 回答
17

我猜你正在寻找mogrify功能。

例子:

>>> cur.mogrify("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
"INSERT INTO test (num, data) VALUES (42, E'bar')"
于 2014-07-05T20:46:46.157 回答
2

你应该尽量避免自己引用。正如人们指出的那样,它不仅是特定于数据库的,而且引用中的缺陷是 SQL 注入错误的根源。

如果您不想单独传递查询和值,请传递参数列表:

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

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

(我可能有 cursor.execute 的语法错误)这里的重点是,仅仅因为 cursor.execute 接受了许多参数,这并不意味着你必须单独处理它们。您可以将它们作为一个列表来处理。

于 2008-11-22T00:01:40.737 回答
1

这将取决于数据库(iirc,mysql 允许\作为转义字符,而像 oracle 之类的东西希望引号加倍:) 'my '' quoted string'

如果我错了,有人纠正我,但双引号方法是标准方法。

可能值得看看其他数据库抽象库做了什么(sqlalchemy、cx_Oracle、sqlite 等)。

我不得不问 - 你为什么要内联值而不是绑定它们?

于 2008-11-21T20:25:48.990 回答
0

这将取决于数据库。例如,在 MySQLdb 的情况下,connection该类有一个literal方法可以将值转换为正确的转义表示以传递给 MySQL(这就是cursor.execute使用的方法)。

我想 Postgres 有类似的东西,但我认为作为 DB API 2.0 规范的一部分,我不认为有一个函数可以转义值。

于 2008-11-21T20:07:31.693 回答
0

我认为您没有给出任何充分的理由来避免这样做是正确的方式。请按照设计使用 APi,不要太努力地使您的代码对下一个人来说可读性降低,并且变得更脆弱。

于 2008-11-23T15:17:20.810 回答
0

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

getquoted函数value以带引号和转义字符串的形式返回 ,因此您也可以使用:"SELECT * FROM some_table WHERE some_char_field = " + adapt(value).getquoted()

于 2012-12-12T21:09:27.313 回答
0

PyPika是构建 SQL 语句的另一个不错的选择。使用示例(基于项目主页上的示例):

>>> 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
于 2019-01-29T18:41:58.037 回答
-1

如果您使用 django,您可能希望使用自动适应当前配置的 DBMS 的引用功能:

from django.db import backend
my_quoted_variable = backend.DatabaseOperations().quote_name(myvar)
于 2008-11-23T14:39:48.220 回答
-2
import re

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

可以完成至少适用于 MySQL 的简单引用工作。我们真正需要的是 cursor.format() 函数,它可以像 cursor.execute() 一样工作,除了它会返回结果查询而不是执行它。有时您不希望查询完全执行 - 例如,您可能希望先记录它,或者在继续之前将其打印出来进行调试。

于 2013-02-07T23:32:41.990 回答