在Delphi IBX异常处理中,Firebird 3.x错误“试图执行未准备好的动态SQL语句”?

时间:2018-10-07 15:48:40

标签: delphi firebird delphi-2009 firebird-3.0

我正在使用带有IBX组件的Delphi 2009 Unicode和Firebird 3.x UTF8 / dialect 3数据库。现在,我看到IBX将Firebird SQL过程和触发器代码引发的所有异常(例如,使用exception my_exception;语句)作为特殊的Firebird异常处理:

Attempt to execute an unprepared dynamic SQL statement
Error Code: 335544711 SQL Code: -901

IBX不报告原始Firebird异常的名称/代码/内容。这很奇怪,因为Delphi 2009 IBX可以毫无问题地处理Firebird 2.1 UTF8 / Unicode异常。在我看来,IBX试图做一些不允许的额外步骤。

当然,我知道从IBX转移到其他框架的所有建议,但我们并不生活在理想的世界中,所以问题就在这里。

问题扩展: 在项目文件中的初始化代码之后(这是IB例程http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/IB_SetIBDataBaseErrorMessages.html):

SetIBDataBaseErrorMessages([ShowSQLCode,ShowIBMessage,ShowSQLMessage]);

我从触发器引发的异常中获取正常的错误消息,但是在从SQL过程中引发异常的情况下,我仍然得到通用的“尝试执行...”错误消息。

问题已更新: 从IBX TIBStoredProc调用该过程时,会出现有关尝试的一般异常,但是如果从TIBDataSet调用存储过程(通过select ...),则会出现正确的错误消息。因此-TIBStoredProc如何处理错误消息应该存在问题。

1 个答案:

答案 0 :(得分:0)

调试显示,Delphi IBX代码IBSQL.pas包含代码:

SQLExecProcedure:
    begin
      fetch_res := Call(FGDSLibrary.isc_dsql_execute2(StatusVector, TRHandle,
                            @FHandle, Database.SQLDialect, FSQLParams.AsXSQLDA,
                            FSQLRecord.AsXSQLDA), False);
      if (fetch_res <> 0) then
      begin
        if (fetch_res <> isc_lock_conflict) then
        begin
           { Sometimes a prepared stored procedure appears to get
             off sync on the server ....This code is meant to try
             to work around the problem simply by "retrying". This
             need to be reproduced and fixed.
           }
          FGDSLibrary.isc_dsql_prepare(StatusVector, TRHandle, @FHandle, 0,
                          PByte(FProcessedSQL.Text), Database.SQLDialect, nil);
          Call(FGDSLibrary.isc_dsql_execute2(StatusVector, TRHandle,
                             @FHandle, Database.SQLDialect, FSQLParams.AsXSQLDA,
                             FSQLRecord.AsXSQLDA), True);
        end
        else
          IBDataBaseError;  // go ahead and raise the lock conflict
      end;
    end

,并且在第二次执行isc_dsql_execute2(...)时,就会引发关于未准备好的语句的错误消息,因此-也许不需要第二次尝试,并且只要fetch_res不为0,我们就可以引发Exception IBDataBaseError?也许有人知道为什么杰夫(Jeff)引入了这种第二通电话,以及该第二通电话试图解决哪些错误?

看来,Delphi XE 10.2代码仅在特定情况下才进行第二次调用:

if (fetch_res = isc_bad_stmt_handle) then

这使得错误的第二次呼叫不足以解决我的问题。因此,解决方案是将初始一般条件(fetch_res <> isc_lock_conflict)替换为更具体的条件(fetch_res = isc_bad_stmt_handle)