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

时间:2017-12-17 00:37:08

标签: python firebird pyodbc

我有一个使用pyodbc连接数据库的应用程序。它可以通过不同的数据库引擎运行。现在我尝试将它改编为Firebird。

对于某些数据库引擎(使用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]validation error for column FILE_TYPE_ID, value "*** 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]Dynamic SQL Error\nSQL error code = -104\nToken unknown - line 1, column 5\nterm (-104) (SQLExecDirectW)')

我正在寻找任何溶剂,所以我将能够以这两种方式运行它。性能方面也非常重要 - 应用程序不经常运行,但每次代码部分对files表进行大约50k的插入时。

1 个答案:

答案 0 :(得分:2)

第一个错误是由于您将null值插入名为not null的{​​{1}}列,换句话说您的变量FILE_TYPE_ID为空,并且列上的约束不允许这样做,或者其他东西出错。

我用Python或其DB-API做了一段时间,但据我记忆,你执行的方式是错误的:

file_type_id

应该(注意使用元组)

cur.execute("insert into files (file_type_id, path, md5) values (?, ?, ?)", file_type_id, path, md5)

第二个错误是由cur.execute("insert into files (file_type_id, path, md5) values (?, ?, ?)", (file_type_id, path, md5)) 不是有效的Firebird SQL语句引起的,它是特定于客户端工具切换语句终止符的语句,另请参阅firebird procedural query throwing "token unknown" error at "SET TERM #;"

执行块是一个匿名的“存储”过程,通常不用于以这种方式执行预准备语句。由于使用了字符串格式,因此使用执行块特别不安全,因为你使用了字符串格式,而且由于执行块这个形式比执行'normal'语句更危险。

Python有几个Firebird数据库驱动程序,FDBpyfirebirdsql,这样您就不需要使用ODBC。