Page 1 of 1

check On-Disk-Structure (Version) of fdb-file

Posted: 16.01.2024, 09:12
by sglodek
Hello,

I am testing migration from FB 2.5 to FB 4 with the embedded Version of Firebird. In embedded Version of firebird 4 it is possible, to open a Database-File that has Version 2.5. My Delphi-application does not recognize that there is an old ODS-version. I don't want this kind of mismatching usage so I am looking for a way, to check after opening a Database-file, which Firebird-Version is used to create this fdb-file (which ODS version is present).
I can't find any "get"-function in ZConnection to read the ODS-version from the used DB-file. Is there such a function that I can't find?

I know that it is possible to get the version with gstat-tool from firebird as "ODS version" in the result-page. But I would like to avoid running gstat via windows-call and then searching the result for the ODS version. So I hope there is any function in ZeosLib to get the file-version :-)

best regards
Siegbert

Re: check On-Disk-Structure (Version) of fdb-file

Posted: 16.01.2024, 15:51
by marsupilami
Hello Siegbert,
sglodek wrote: 16.01.2024, 09:12 In embedded Version of firebird 4 it is possible, to open a Database-File that has Version 2.5.
No - this is not possible at all. Are you sure, your program is loading the correct fbclient.dll?

I use the following code to determine the ODS version, where the ODS version gets saved into the FODSVersion member of TFBDatabaseInfo:

Code: Select all

procedure TFBDatabaseInfo.RetrieveOdsVersion;
var
  Count: Integer;
begin
  Query.Close;
  Query.SQL.Text := 'select count(*) as X from RDB$RELATIONS where RDB$SYSTEM_FLAG = 1';
  Query.Open;
  try
    Count := Query.FieldByName('X').AsInteger;
  finally
    Query.Close;
  end;

  if Count >= 40 then begin
    Query.SQL.Text := 'select ((MON$ODS_MAJOR * 10) + MON$ODS_MINOR) as ODSVERSION, MON$PAGE_SIZE from MON$DATABASE';
    Query.Open;
    try
      FODSVersion := Query.FieldByName('ODSVERSION').AsInteger;
      FPageSize := Query.FieldByName('MON$PAGE_SIZE').AsInteger;
    finally
      Query.Close;
    end;
  end else begin
    FPageSize := -1;
    case Count of
      32: FODSVersion := 101;
      33: FODSVersion := 110;
      else FODSVersion := 0;
    end;
  end;
end;
The following code correctly identifies the ODS major version for me:

Code: Select all

type
//struct pag
//{
//    SCHAR pag_type;
//    UCHAR pag_flags;
//    USHORT pag_checksum;
//    ULONG pag_generation;
//    ULONG pag_scn;
//    ULONG reserved;
//};

  TPag = packed record
    pag_type: shortint;
    pag_flages: byte;
    pag_checksum: word;
    pag_generation: cardinal;
    pag_scn: cardinal;
    reserved: cardinal;
  end;

//struct header_page
//{
//    pag hdr_header;
//    USHORT hdr_page_size;
//    USHORT hdr_ods_version;
//    SLONG hdr_PAGES;
//    ULONG hdr_next_page;
//    SLONG hdr_oldest_transaction;
//    SLONG hdr_oldest_active;
//    SLONG hdr_next_transaction;
//    USHORT hdr_sequence;
//    USHORT hdr_flags;
//    SLONG hdr_creation_date[2];
//    SLONG hdr_attachment_id;
//    SLONG hdr_shadow_count;
//    SSHORT hdr_implementation;
//    USHORT hdr_ods_minor;
//    USHORT hdr_ods_minor_original;
//    USHORT hdr_end;
//    ULONG hdr_page_buffers;
//    SLONG hdr_bumped_transaction;
//    SLONG hdr_oldest_snapshot;
//    SLONG hdr_backup_pages;
//    SLONG hdr_misc[3];
//    UCHAR hdr_data[1];
//};

   THeader_page = packed record
     hdr_header: TPag;
     hdr_page_size: Word;
     hdr_ods_version: Word;
     // everything else is left out
   end;

function GetOdsVersion(Database: String): Integer;
var
  Stream: TFileStream;
  Hdr: THeader_page;
begin
  Stream := TFileStream.Create(Database, fmOpenRead or fmShareDenyNone);
  try
    Stream.Read(Hdr, SizeOf(Hdr));
  finally
    FreeAndNil(Stream);
  end;

  Result := (Hdr.hdr_ods_version xor $8000);
  Result := Result * 10;
end;
This can be used to determine the ODS version before fbclient.dll gets loaded.

Best regards,

Jan