在python中将Tuple传递给MySQLdb的问题

2024-09-22 18:19:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一些sql查询可以通过python mysqldb运行到mysql数据库中,但是我想让它们少一点sql注入漏洞,这样小bobby表就不会试图添加数据。。

例如:

原件:
(这有效,因此ListID等绝对有效)

sql="SELECT NAME FROM ListsTable WHERE ID=%s"%(ListID)  
c.execute(sql)  

尝试使用元组:

sql="SELECT NAME FROM ListsTable WHERE ID=%s"  
c.execute(sql,(ListID,))  

有效:

sql="SELECT NAME FROM ListsTable WHERE ID=%s"  
c.execute(sql, ListID)  

我不知道为什么第二次尝试不作为元组工作,而是作为一个参数接受它,但是无论是哪种方式,对于另一个语句,我都需要传递多个参数,这样就不起作用:

原件:

sql="SELECT * FROM ListsTable ORDER BY ID DESC LIMIT %s,%s"%(Page, (Page*20)+20)  
c.execute(sql)

如果我尝试以元组的形式发送参数,那么这个方法仍然有效:

sql="SELECT * FROM ListsTable ORDER BY ID DESC LIMIT %s,%s"  
var1=Page  
var2=(Page*20)+20  
params=(var1,var2)              
c.execute(sql,params)  

甚至只是

sql="SELECT * FROM ListsTable ORDER BY ID DESC LIMIT %s,%s"  
c.execute(sql,(Page,(Page*20)+20))  

我最近在我的webserver日志中发现了这个错误,不过请注意,这可能是一个redhering,因为我尝试了很多不同的东西,因为它以前没有出现过错误:(这个错误是指上面传递“params”变量的尝试)

File "process.py", line 98, in main  
c.execute(sql,params)  
File "/var/www/cgi-bin/MySQLdb/cursors.py", line 159, in execute  
query = query % db.literal(args)  
TypeError: not enough arguments for format string  

编辑:如果有帮助的话,我正在使用mysqldb版本1.2.3,以防它不接受该版本的元组,但不要让我开始了解mysqldb文档是多么垃圾。。


Tags: namefromidexecutesql参数pageorder
3条回答

你的mysqldb版本一定是问题所在。

http://mysql-python.hg.sourceforge.net/hgweb/mysql-python/MySQLdb-2.0/file/5a7c30cd9de2/MySQLdb/cursors.py#l180

已更改为:

1.51 -        if args is not None:
1.52 -            query = query % self.connection.literal(args)
1.53          try:
1.54 +            if args is not None:
1.55 +                query = query % tuple(map(self.connection.literal, args))

http://mysql-python.hg.sourceforge.net/hgweb/mysql-python/MySQLdb-2.0/diff/98d968f5af11/MySQLdb/cursors.py

后来改为:

1.144 -                query = query % tuple(map(self.connection.literal, args))
1.145 +                query = query % tuple(( get_codec(a, self.encoders)(db, a) for a in args ))

http://mysql-python.hg.sourceforge.net/hgweb/mysql-python/MySQLdb-2.0/diff/d9bb912776a5/MySQLdb/cursors.py#l1.144

我不能用MySQLdb复制这个。我用的是1.2.2期末考试。 也许可以尝试一个简单的调试,以确保问题出在您已经指出的地方:

In [13]: cur.execute('select %s + %s', (1,2))
Out[13]: 1L

In [14]: cur.fetchall()
Out[14]: ((3L,),)

更新1:所以我抓取并安装了1.2.3 final,这是我的成绩单:

In [1]: import MySQLdb
In [2]: MySQLdb.version_info
Out[2]: (1, 2, 3, 'final', 0)
In [3]: con = MySQLdb.connect(user='root', db='inventory')
In [4]: cur = con.cursor()
In [5]: cur.execute('select %s + %s', (1,2))
Out[5]: 1L
In [6]: cur.fetchall()
Out[6]: ((3L,),)

如果我能复制你的问题,也许我能提供一个解决方案!? 那么我们两个环境还有什么不同呢?

$ mysql --version
mysql  Ver 14.14 Distrib 5.1.41, for debian-linux-gnu (x86_64) using readline 6.1

更新2: 你也许可以把事情分解得比上面稍微多一些。请注意MySQLdb-1.2.3的源代码中的以下代码片段:

139     def execute(self, query, args=None):
...
158         if args is not None:
159             query = query % db.literal(args)
160         try:
161             r = self._query(query)
162         except TypeError, m:
163             if m.args[0] in ("not enough arguments for format string",
164                              "not all arguments converted"):
165                 self.messages.append((ProgrammingError, m.args[0]))

第159行是转换/转义参数,然后插入查询字符串的位置。 所以也许你可以这样做:

In [24]: con.literal((1,2,))
Out[24]: ('1', '2')

在与查询字符串合并之前,查看驱动程序如何转换参数。

In [26]: "select %s + %s" % con.literal((1,2,))
Out[26]: 'select 1 + 2'

在MySQLdb 1.2.3中,查询来自字符串替换,第一个参数用作模型字符串,第二个参数用作参数列表或单个参数,通过con.literal传递。con.literal接受您提供的内容,并尝试将其转换为一个字符串,由MySQL正确解析。它在字符串中添加撇号。它输出不带引号的数字。或者,如果给它一个带撇号的字符串,它会引用撇号。

在您的特定情况下,MySQLdb似乎总是会做错误的事情,当您将一个只有一个项的元组交给它时(con是任何打开的连接):

>>> con.literal((10,))
('10',)
>>>

这正是Python希望能够创建一个包含单个项的元组的原因,但这会导致MySQL出现barf(向右滚动可以看到barfness):

mysql> select distinct sites.SiteCode, sites.SiteName, Latitude, Longitude, County, SourceID from sites, seriescatalog where sites.SiteID = seriescatalog.SiteID and sites.SiteID in (82,);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1
mysql> 

这是我的工作,以防止博比小报:

siteinfoquery = """select distinct sites.SiteCode, sites.SiteName, Latitude, Longitude, County, SourceID from sites, seriescatalog where sites.SiteID = seriescatalog.SiteID and sites.SiteID in (%s);"""

cur.execute(siteinfoquery % ",".join([str(int(i)) for i in SiteID]))

顺便说一句,下面的代码不起作用,因为con.literal(在MySQLdb的execute()函数中调用)引用了结果字符串,将其从一个数字列表转换为一个字符串,然后变成一个与任何SiteID都不匹配的值:

cur.execute(siteinfoquery , ",".join([str(int(i)) for i in SiteID]))

>>> "(%s)" % con.literal(",".join([str(float(i)) for i in SiteID]))
"('10.0,20.0')"
>>> 

我还没有看到这是不是一个在更高版本中修复的错误,当前的问题,我的错误,还是一个他们不知道的问题。

相关问题 更多 >