Python 使用pyodbc绑定参数并连接到Firebird
我有一个应用程序,它使用pyodbc连接到数据库。它可以与不同的db引擎一起运行。现在我试着让它适应火鸟 对于某些db引擎(使用sqlite、Sybase测试),我可以使用本机pyodbc方式处理绑定参数:Python 使用pyodbc绑定参数并连接到Firebird,python,firebird,pyodbc,Python,Firebird,Pyodbc,我有一个应用程序,它使用pyodbc连接到数据库。它可以与不同的db引擎一起运行。现在我试着让它适应火鸟 对于某些db引擎(使用sqlite、Sybase测试),我可以使用本机pyodbc方式处理绑定参数: cnxn = pyodbc.connect(connect_string, autocommit=True) cur = cnxn.cursor() cur.execute("insert into files (file_type_id, path, md5) values (?, ?,
cnxn = pyodbc.connect(connect_string, autocommit=True)
cur = cnxn.cursor()
cur.execute("insert into files (file_type_id, path, md5) values (?, ?, ?)", file_type_id, path, md5)
对于Oracle,我必须准备一些要运行的特殊SQL:
cnxn = pyodbc.connect(connect_string, autocommit=True)
cur = cnxn.cursor()
sql = """DECLARE v_file_type_id INT; v_path varchar2(1024); v_md5 varchar2(32);
BEGIN
v_file_type_id := %d;
v_path := '%s';
v_md5 := '%s';
insert into files (file_type_id, path, md5) values (v_file_type_id, v_path, v_md5);
END;""" % (file_type_id, path, md5)
cur.execute(sql)
第一种方法不适用于Firebird。我收到错误:pyodbc.IntegrityError:('23000','[23000][ODBC Firebird Driver][Firebird]列文件类型ID的验证错误,值“***null***”(.625)(SQLExecDirectW)
我试着准备专门的SQL,就像Oracle一样,但我遇到了一些问题
cnxn = pyodbc.connect(connect_string, autocommit=True)
cur = cnxn.cursor()
sql = """set term ^ ;
execute block
as
declare v_file_type_id int = %d;
declare v_path varchar(1024) = '%s';
declare v_md5 varchar(32) = '%s';
begin
insert into files (file_type_id, path, md5) values (:v_file_type_id, :v_path, :v_md5);
end
^
set term ; ^""" % (file_type_id, path, md5)
cur.execute(sql)
它不起作用。这次的错误是:pyodbc.Error:('HY000','[HY000][ODBC Firebird Driver][Firebird]动态SQL错误\nSQL错误代码=-104\n未知-第1行第5列\nterm(-104)(SQLExecDirectW)
我正在寻找任何解决方案,所以我可以用这两种方法中的任何一种来运行它。性能方面也是非常重要的—应用程序并不经常运行,但每次该部分代码向
文件
表中插入大约50k次 第一个错误是由于将null
值插入名为FILE\u-TYPE\u-ID
的not-null
列中,换句话说,变量FILE\u-TYPE\u-ID
为null,并且该列上的约束不允许这样做,或者出现了其他问题
我已经有一段时间没有用Python或其DB-API做任何事情了,但据我回忆,您的执行方式是错误的:
cur.execute("insert into files (file_type_id, path, md5) values (?, ?, ?)", file_type_id, path, md5)
应该是(注意元组的使用)
第二个错误是由以下事实引起的:set term
不是有效的Firebird SQL语句,它是特定于切换语句终止符的客户端工具的语句,另请参见
Execute块是一个匿名“存储”过程,通常不用于以这种方式执行准备好的语句。使用execute block是特别不安全的,因为您使用的是字符串格式,并且因为execute block,所以在打开SQL注入时,这种形式比执行“normal”语句更危险
Python有几个Firebird数据库驱动程序,这样您就不需要使用ODBC。查看Firebird试图执行的实际SQL将在这里有所帮助。在传递SQL和参数时,无法看到从
pyodbc
执行的实际SQL(也不应该)。能否在Firebird中打开查询日志记录并包含导致错误的SQL?实际上,pyodbc不要求将参数值作为元组(ref:)传递。是的,第一个错误是关于尝试将null
值放入不允许的列中。但是请相信我,文件类型\u id
不是null
,我可以在cur.execute(…)
之前打印它的值。另外,当我将connect\u string
更改为sqlite或Sybase数据库时,同样的代码也可以工作。我尝试了两种传递参数的方法——直接传递(如我上面所写的)和tumple传递。在那种情况下,两者都不起作用。我从开头和结尾都删除了set term
部分,现在它可以工作了。我了解潜在的危险。谢谢您的帮助。@Yama-Hmm,这表明ODBC驱动程序中存在错误,您使用的是Firebird ODBC驱动程序2.0.5吗?
cur.execute("insert into files (file_type_id, path, md5) values (?, ?, ?)", (file_type_id, path, md5))