2011-04-27 17 views
4

我有一些sql查询通过python mysqldb工作到我的mysql数据库,但是我想让它们少一些sql注入漏洞,所以小的bobby表不会尝试添加数据。 。在python中传递元组到MySQLdb的问题

例如:

ORIGINAL:
(这工作,所以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,)) 

WORKS:10元组试图

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

我不知道为什么第2次尝试不作为一个元组工作,但接受它作为一个参数,但无论哪种另一个说法的方式,我需要传递多个参数,所以这不会为工作:

ORIGINAL:

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) 

甚至只是

​​

我最近得到这个错误在我的网络服务器日志上,但请注意,这可能是一个重新尝试,因为我一直在尝试的许多不同的东西,因为它以前没有错误:(错误指的是传递“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文档是..

+0

如果您在前几种情况下提供了比“不起作用”更多的信息,并且显示了您在执行记录的错误时正在执行的操作,将会有很大的帮助。请注意,您可以也应该在Python交互式提示符('>>>')和/或可以在shell命令行运行的非常简单的脚本中尝试解决您的问题 - 避免像web服务器那样的不相关的问题调试简单问题更困难。显示您的数据'print repr(ListID)'。 – 2011-04-27 01:50:21

+0

这一切都在上面的代码正常工作,我不明白为什么这是一个问题,将它从字符串替换到元组参数化,当文档说它只接受元组。我会认为这是一个容易发生的错误,以便发现任何不是我的人。它是读取JSON结构并将其返回给Android手机的CGI脚本的一部分,因此安装本地Apache Web服务器并调整输入以调试可能非常明显的事情可能会适得其反,特别是在实际脚本完成后。此外,当第一批不起作用时,不会出现错误。 – alsandair 2011-04-27 01:55:23

+0

正如我所说,所有的CGI/JSON/Android/apache的东西都与你指称的MySQLdb问题毫无关系。我当然不是在煽动你安装本地apache web服务器,而是像@jsw所做的那样做一些与你的问题有关的实验。 “”“第一批不工作时,没有错误”“”那么“不工作”是什么意思?如果你不能以类似于@jsw的方式重现你的问题,你需要记录(1)你的sql语句(2)参数元组(3)fetchall()结果(在每种情况下使用' repr()'以避免含糊不清)并向我们展示结果。 – 2011-04-27 02:26:49

回答

0

我无法复制这与MySQLdb。我正在使用1.2.2 final。 也许尝试一个简单的调试,以确保问题出在哪里,你都表示:

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

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

更新1:所以我抓住并安装1.2.3决赛,这是我的成绩单:

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是你ARGS转换/逃脱,然后插入到查询字符串。 因此,也许你可以做这样的事情:

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

怎么看参数是由驱动程序转换,与您的查询字符串合并之前。

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

您好,感谢试图与复制一个类似的版本!不幸的是同样的结果,只是失败了,没有蟒蛇错误,没有结果 – alsandair 2011-04-27 02:26:01

+0

的输出中(我也把东西例外输出:除了MySQLdb.Error,E:dumpout.write(“\ n” + e.args [0 ] +“”+ e.args [1]),但这并不是输出。)尽管我的web服务器刚刚重新登录:与上面相同的“TypeError:没有足够的格式字符串参数”代码你提供 – alsandair 2011-04-27 02:31:55

+0

@ user530501:请出示过程的记录... – 2011-04-27 02:33:20

2

您的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

+0

可能是,它是连接这就是从我所知道的错误中引发的错误。 – alsandair 2011-04-28 19:15:52

+0

@user:naw,你的源代码是1.2。3,并且您可以在原始问题发布中看到引发异常的那一行。我认为这种差异是来自更新的来源。你的查询%connection.literal(args)' – jsw 2011-04-28 22:42:06

+0

它在文字行失败,但在字符串替换成功,但我选择了1.2.3 mysqldb,因为它表示它与oyhtin 2.3.6兼容。你是说代码看起来不是从1.2.3开始的? – alsandair 2011-04-29 02:14:00

1

在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()函数中调用)引用结果字符串,将它从一个数字列表转换为一个字符串,然后变成一个单一值, “T匹配任何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')" 
>>> 

我还没有看,看看这是固定在以后的版本中的错误,当前的问题,是我不好,或者他们并不知晓的一个问题。

+0

Hrm。我似乎已经阅读*我*的问题,因为你的问题是一样的。你只是想传递一个或两个简单的变量。对不起,我不能用MySQLdb 1.2.3重现你的问题,正是你正在使用的。 – 2015-12-21 19:21:50

0

工作与非工作示例:

import MySQLdb as mysql 
from MySQLdb.constants import FIELD_TYPE 
In [9]: conn = mysql.connect(host=hostname, user=user_name, passwd=password, port=port_number, db=schema_name) 
In [10]: cursor = conn.cursor() 
In [11]: cursor.execute('select %s + %s', (1, 3)) 
Out[11]: 1L 

In [16]: conn = mysql.connect(host=hostname, user=user_name, passwd=password, port=port_number, db=schema_name, conv={FIELD_TYPE.LONG: long}) 
In [17]: cursor = conn.cursor() 
In [18]: cursor.execute('select %s + %s', (1, 3))--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-18-08423fe5373f> in <module>() 
----> 1 cursor.execute('select %s + %s', (1, 3)) 
/usr/lib64/python2.6/site-packages/MySQLdb/cursors.pyc in execute(self, query, args) 
    156    query = query.encode(charset) 
    157   if args is not None: 
--> 158    query = query % db.literal(args) 
    159   try: 
    160    r = self._query(query) 
TypeError: not enough arguments for format string 

conv参数mysql.connect是我的问题。没有它,我的查询参数按预期解释。有了它,我就把头发撕掉了。