在Magento集成中查询的PDO Firebird准备中出现异常



我正在进行一个项目,该项目通过php firebird pdo扩展直接与客户的ERP*集成,以获取品牌、类别、产品、产品价格等信息。

数据库不在运行脚本的服务器上。如果这很重要的话,通过VPN连接可以连接到数据库。

首先,脚本要求Firebird在一个名为SYS$ACTION_DS的系统表中进行一些查询,Firebird返回以下查询:

execute block (
MARK_AS_PROCESSED DM_BOOL = :MARK_AS_PROCESSED,
EXTENAL_SYSTEM_ID DM_123 = :EXTENAL_SYSTEM_ID)
returns (
ID bigint,
BRAND_NAME$1 DM_STR30,
BRAND_NAME$2 DM_STR30,
BRAND_PARENT_REF bigint,
OP varchar(1))
as
DECLARE VARIABLE SL_ID BIGINT;
begin
FOR SELECT SL.ID, SL.OPERATION, SL.TABLE_ID_REF, N.BRAND_NAME$1, N.BRAND_NAME$2, N.BRAND_PARENT_REF
FROM  SYS$EXT_LOG SL
LEFT JOIN NOM$BRANDS N ON (SL.TABLE_ID_REF = N.ID)
WHERE (SL.PROCESSED = 0) AND (SL.EXTERNAL_SYSTEM_ID = :EXTENAL_SYSTEM_ID) AND (SL.TABLE_NAME = 'NOM$BRANDS')
ORDER BY SL.ID
INTO :SL_ID, :OP, :ID, :BRAND_NAME$1, :BRAND_NAME$2, :BRAND_PARENT_REF
do begin
suspend;
if (MARK_AS_PROCESSED = 1) then
update SYS$EXT_LOG SL set SL.PROCESSED = 1, SL.PROCESSED_ON = current_timestamp where SL.ID = :SL_ID;
end
end

之后,脚本尝试准备PDO语句,但prepare抛出异常:Dynamic SQL Error SQL error code = -104 Token unknown - line 18, column 12 ?

我不知道为什么会出现这个错误,但在实时服务器上一切都很好,但在我的机器上却不行。我在我的机器上尝试了几个php版本(5.6、7.0、7.1),但都不起作用,在实时服务器上,php版本是5.5,但我找不到与PDO或Firebird PDO相关的5.5和5.6之间的任何变化。

其他信息:火鸟服务器版本:2.5.5.26

当前PDO Firebird驱动程序对命名参数进行简单的基元替换,将:param替换为?,因为FB不支持命名参数。PDO FB驱动程序源中的更多信息

不幸的是,这不适用于"执行块"语句。我希望,并在未来做出一些努力来解决这个问题。这在FB论坛中进行了讨论,添加了对命名参数的支持,也在PHP开发论坛和跟踪器中进行了改进,以改进驱动程序。

目前,作为一种变通方法,您可以使用存储过程。

问题是Firebird在PSQL块之外没有命名参数,而PDO Firebird似乎提供了一个翻译来模拟对此的支持。

例如,的原始执行

execute block (
MARK_AS_PROCESSED DM_BOOL = :MARK_AS_PROCESSED,
EXTENAL_SYSTEM_ID DM_123 = :EXTENAL_SYSTEM_ID)
.. etc..

将提高

SQL Message : -104
Invalid token
Engine Code    : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -104
Token unknown - line 2, column 33
:

PDO Firebird库将用?替换参数名称,并且给定错误和命名的参数替换,执行的内容如下:

execute block (
MARK_AS_PROCESSED DM_BOOL = ?,
EXTENAL_SYSTEM_ID DM_123 = ?)
returns (
ID bigint,
BRAND_NAME$1 DM_STR30,
BRAND_NAME$2 DM_STR30,
BRAND_PARENT_REF bigint,
OP varchar(1))
as
DECLARE VARIABLE SL_ID BIGINT;
begin
FOR SELECT SL.ID, SL.OPERATION, SL.TABLE_ID_REF, N.BRAND_NAME$1, N.BRAND_NAME$2, N.BRAND_PARENT_REF
FROM  SYS$EXT_LOG SL
LEFT JOIN NOM$BRANDS N ON (SL.TABLE_ID_REF = N.ID)
WHERE (SL.PROCESSED = 0) AND (SL.EXTERNAL_SYSTEM_ID = ?) AND (SL.TABLE_NAME = 'NOM$BRANDS')
ORDER BY SL.ID
INTO ?, ?, ?, ?, ?, ?
do begin
suspend;
if (MARK_AS_PROCESSED = 1) then
update SYS$EXT_LOG SL set SL.PROCESSED = 1, SL.PROCESSED_ON = current_timestamp where SL.ID = ?;
end
end

注意into-子句中的?。这就是触发异常的原因,因为?在这里无效。

我实际上不知道PDO Firebird,但它看起来会用?替换所有出现的:<variablename>。由于PDO Firebird似乎会大规模替换所有看起来像:<variable>的东西,那么你可以尝试使用位置参数(希望它不会用?替换每个:<variable>),

execute block (
MARK_AS_PROCESSED DM_BOOL = ?,
EXTENAL_SYSTEM_ID DM_123 = ?)
.. etc..

或者您将需要创建一个实际的存储过程(而不是使用PDO Firebird来创建它),并从PDO Firebird执行它。

如果这在PHP的早期版本中有效,那么您似乎遇到了回归,我建议您报告PDO项目的回归错误。

最新更新