如何在 Firebird 3 OO 中使用事务参数块 Api

How to use a transaction parameter block with the Firebird 3 OO Api

我一直在玩 Firebird 3 中包含的新 Firebird.pas 界面。我在尝试使用自定义事务参数块时遇到问题。如果我向块添加任何标签,我似乎总是会收到错误 "invalid format for transaction parameter block"。我见过的关于如何执行此操作的唯一示例是 Firebird 3 附带的 "Using_OO_API.html" 文档。这是重现错误的代码。任何建议表示赞赏!

procedure TForm1.Connect2ButtonClick(Sender: TObject);
var
  Master: IMaster;
  Status: IStatus;
  Dispatcher: IProvider;
  Util: IUtil;
  dpb: IXpbBuilder;
  tpb: IXpbBuilder;
  Attachment: IAttachment;
  Transaction: ITransaction;
  Statement: IStatement;
  ErrorString: AnsiString;
  StatusVector: NativeIntPtr;
  UseCustomTransaction: Boolean;
begin
  // Connect to Firebird 3 and use a custom transaction object.
  try
    Master := fb_get_master_interface();
    Status := Master.getStatus();

    Dispatcher := master.getDispatcher();
    Util := Master.getUtilInterface();
    dpb := Util.getXpbBuilder(status, IXpbBuilder.DPB, nil, 0);
    dpb.insertString(status, isc_dpb_user_name, 'SYSDBA');
    dpb.insertString(status, isc_dpb_password, 'sillypw');
    Attachment := Dispatcher.attachDatabase(status, PAnsiChar('myserver:testdb'), dpb.getBufferLength(status), dpb.getBuffer(status));

    UseCustomTransaction := True;
    if UseCustomTransaction then
    begin
      // Transaction := attachment.startTransaction(status, 0, nil);
      tpb := Util.getXpbBuilder(status, IXpbBuilder.TPB, nil, 0);
      tpb.insertTag(status, isc_tpb_version3);
      tpb.insertTag(status, isc_tpb_write);
      tpb.insertTag(status, isc_tpb_read_committed);
      tpb.insertTag(status, isc_tpb_nowait);
      tpb.insertTag(status, isc_tpb_rec_version);

      // This always seems to error with "invalid format for transaction parameter block"
      Transaction := attachment.startTransaction(status, tpb.getBufferLength(status), tpb.getBuffer(status));
    end
    else
    begin
      // Creating default transaction works fine. As an aside, what are the default transaction properties?
      Transaction := attachment.startTransaction(status, 0, nil);
    end;

    Statement := attachment.prepare(status, transaction, 0,
          'select rdb$relation_id relid, rdb$relation_name csname ' +
          '  from rdb$relations ' +
          '  where rdb$relation_id < ?',
             3, 0);

    Memo1.Lines.Add('Simple Plan: ' + Statement.getPlan(status, false));
    Memo1.Lines.Add('Detailed Plan: ' + Statement.getPlan(status, true));
    Memo1.Lines.Add('');

        transaction.rollback(status);

        Statement.free(status);
        attachment.detach(status);

    dpb.dispose;
    if UseCustomTransaction then
      tpb.dispose;

  except
    on E: FbException do
    begin
      SetLength(ErrorString, 2000);
      StatusVector := E.getStatus().getErrors();
      // Note that fb_interpret does not seem to appear in firebird.pas so we added it by hand.
      //   function fb_interpret(s: PAnsiChar; n: Cardinal; var statusVector: NativeIntPtr): Integer; cdecl;    external 'fbclient';
      SetLength(ErrorString, fb_interpret(PAnsiChar(ErrorString), 2000, StatusVector));
      ShowMessage(String(ErrorString));
    end
  end;

end;

IXpbBuilder(可能特定于 TPB 或 InsertTag)似乎存在问题,因此它创建了无效的事务参数缓冲区。这可以通过手动创建缓冲区来解决,如下面的代码所示:

//  var TransParamBuffer: TBytes
SetLength(TransParamBuffer, 5);
TransParamBuffer[0] := isc_tpb_version3;
TransParamBuffer[1] := isc_tpb_write;
TransParamBuffer[2] := isc_tpb_read_committed;
TransParamBuffer[3] := isc_tpb_nowait;
TransParamBuffer[4] := isc_tpb_rec_version;
Transaction := attachment.startTransaction(status, Length(TransParamBuffer), @TransParamBuffer[0]);