Как использовать блок параметров транзакции с API Firebird 3 OO

Я экспериментировал с новым интерфейсом Firebird.pas, входящим в состав Firebird 3. У меня возникла проблема, когда я пытаюсь использовать пользовательский блок параметров транзакции. Кажется, я всегда получаю сообщение об ошибке «недопустимый формат блока параметров транзакции», если добавляю какие-либо теги в блок. Единственный пример того, как это сделать, я видел, это документ «Using_OO_API.html», включенный в Firebird 3. Вот код для воспроизведения ошибки. Любые предложения приветствуются!

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;

person MarkF    schedule 12.05.2016    source источник
comment
Я предлагаю вам задать вопрос в списке рассылки Firebird-devel, так как я подозреваю, что за пределами основных разработчиков Firebird этот API еще не нашел широкого применения; Подозреваю, что шанс на ответ здесь не очень высок.   -  person Mark Rotteveel    schedule 12.05.2016
comment
Спасибо, Марк. Я тоже попробую.   -  person MarkF    schedule 12.05.2016


Ответы (1)


Похоже, возникла проблема с 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]);
person MarkF    schedule 15.05.2016
comment
Молодец, что опубликовал собственное решение, +1. Я бы хотел, чтобы больше людей делали это, а не просто отказывались от своего вопроса. - person MartynA; 15.05.2016