Python 使用pyodbc绑定参数并连接到Firebird

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 (?, ?,

我有一个应用程序,它使用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 (?, ?, ?)", 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))