繁体   English   中英

如何在Delphi XE5中使用Firedac FDConnection组件调用具有空返回的函数?

[英]How to call a function with void return using Firedac FDConnection Component in Delphi XE5?

我最近开始在Delphi XE5中使用FDConnection组件的[ExecSQLScalar] 1[ExecSQL] 2方法。 无需仅为简单查询或执行而构建FDQuery之类的Dataset对象,就非常方便。 但是,在执行带有void返回的函数时,我有一个奇怪的问题,该函数具有内部验证,可以在其中生成异常。 我正在使用Postgres数据库。

CREATE FUNCTION can_be_exception()
  RETURNS void AS
$$
BEGIN
    RAISE EXCEPTION E'fail';
END;
$$
  LANGUAGE plpgsql STABLE;

在delphi中,我调用ExecSQLScalar函数...

FDConnection1.ExecSQLScalar('select 1');
FDConnection1.ExecSQLScalar('select can_be_exception()');

第一次运行时,出现以下错误:

项目TFDConnectionDEMO.exe引发了异常类EPgNativeException,消息为“ [FireDAC] [Phys] [PG] [libpq]错误:失败”。

在第二次运行中,我收到违规访问错误:

项目TFDConnectionDEMO.exe引发了异常类$ C0000005,消息为“访问冲突在0x00000000:读取地址0x00000000”。

显然,该错误在单元FireDAC.Comp.Client中的以下行中发生

function TFDCustomConnection.ExecSQLScalar(const ASQL: String;
  const AParams: array of Variant; const ATypes: array of TFieldType): Variant;
var
  oCmd: IFDPhysCommand;
begin
  oCmd := BaseCreateSQL;
  try
    if BasePrepareSQL(oCmd, ASQL, AParams, ATypes) or (FExecSQLTab = nil) then begin
      FDFree(FExecSQLTab);

...

忽略先前的错误并重试,则显示另一个错误...

项目TZConnectionDEMO.exe引发了异常类EFDException,消息为“ [FireDAC] [DatS] -24”。 行未嵌套”。

搜索时,我没有找到对此错误的响应。 我发现我的错误是使用FDConnection组件的ExecSQLScalar函数调用bank raise_exception函数。 因此,我尝试使用FDConnection.ExecSQL并且正如我想象的那样,如果参数中有SELECT子句,则无法使用它。

是否有更好的方法使用FDConnection.ExecSQL以void返回值调用函数? BUG会出现在组件中吗? 还是打这样的电话不正确吗?

在这种情况下,使用ExecSQLScalar很好。 这肯定是一个错误(至少在Delphi 10.2.3中已得到修复)。 正如您已经正确指出的那样,问题在于使用FDFree过程释放了FExecSQLTab字段持有的表存储对象实例。

我没有Delphi XE5源代码,但也许您可以在里面看到类似的内容(关于发生的事情的评论由我添加):

if BasePrepareSQL(oCmd, ASQL, AParams, ATypes) or (FExecSQLTab = nil) then
begin
  FDFree(FExecSQLTab); { ← directly calls destructor if object is not nil }
  FExecSQLTab := oCmd.Define; { ← no assignment if command execution raises exception }
end;

问题是,当SQL命令执行在存储表定义阶段( oCmd.Define )引发异常时,对先前销毁的存储表对象实例的引用(通过FDFree )仍然存储在FExecSQLTab字段中(作为悬空指针)。

然后,当以这种方式执行其他命令时,仅针对该悬空指针调用FDFree过程。 因此,访问冲突。

解决此问题的方法是替换行,例如:

FDFree(FExecSQLTab);

通过:

FDFreeAndNil(FExecSQLTab);

这是在后来的Delphi版本中完成的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM