I've been playing with the new Firebird.pas interface included with Firebird 3. I'm having an issue when I try to use a custom transaction parameter block. I seem to always get the error "invalid format for transaction parameter block" if I add any tags to the block. The only example I've seen of how to do this is the "Using_OO_API.html" document included with Firebird 3. Here's the code to reproduce the error. Any suggestions appreciated!
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;
There appears to be a problem with the IXpbBuilder (perhaps specific to TPB or to InsertTag) such that it creates an invalid transaction parameter buffer. This can be worked around by creating the buffer by hand as in the following code:
// 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]);