diff --git a/runtime/nongui/IBDatabase.pas b/runtime/nongui/IBDatabase.pas index ab3ec71b..d1ca5c8d 100644 --- a/runtime/nongui/IBDatabase.pas +++ b/runtime/nongui/IBDatabase.pas @@ -1599,7 +1599,13 @@ constructor TIBTransaction.Create(AOwner: TComponent); FTimer.Interval := 0; FTimer.OnTimer := TimeoutTransaction; FDefaultAction := taCommit; - FTransactionList.Add(self); + { Guarded the way Destroy's Remove already is. A transaction can be + constructed after this unit has finalized - the LCL frees documents from + Application's async queue during Application.Destroy, and tearing a + data-aware control down there reaches IBX again - and the list is gone by + then. Unguarded, that is an access violation on the way out. } + if Assigned(FTransactionList) then + FTransactionList.Add(self); if (FTransactionName = '') and (CreateGUID(uuid) = 0) then FTransactionName := GUIDToString(uuid); end; @@ -2407,10 +2413,18 @@ function TIBDataBase.GenerateDPB(FirebirdAPI: IFirebirdAPI; sl: TStrings): IDPB; case DPBItem.getParamType of isc_dpb_user_name, isc_dpb_password, isc_dpb_password_enc, isc_dpb_sys_user_name, isc_dpb_license, isc_dpb_encrypt_key, - isc_dpb_lc_messages, isc_dpb_lc_ctype, isc_dpb_page_size, + isc_dpb_lc_messages, isc_dpb_lc_ctype, isc_dpb_sql_role_name: DPBItem.SetAsString(ParamValue); + {isc_dpb_page_size is an integer parameter, not a string one. Writing it + with SetAsString stores the digits as text, which the clumplet writer + rejects outright once there are more than four of them - so + Params.Values['page_size'] := '16384' failed with "length of integer + exceeds 4 bytes (5)", and only the four-digit sizes appeared to work.} + isc_dpb_page_size: + DPBItem.SetAsInteger(StrToUInt(ParamValue)); + isc_dpb_sql_dialect: begin if (ParamValue = '') or (ParamValue[1] = '3') then @@ -2492,8 +2506,13 @@ function TIBTransaction.GenerateTPB(FirebirdAPI: IFirebirdAPI; sl: TStrings): IT TIBTransaction.FTransactionList := TList.Create; Finalization - if assigned(TIBTransaction.FCriticalSection) then TIBTransaction.FCriticalSection.Free; - if assigned(TIBTransaction.FTransactionList) then TIBTransaction.FTransactionList.Free; + { FreeAndNil rather than Free: these are class vars that outlive the unit's + finalization in the sense that something can still reach them afterwards, + and Free leaves the reference dangling - so the Assigned tests guarding + them stayed true and went on reading released memory. Nil is what makes + those guards mean anything. } + if assigned(TIBTransaction.FCriticalSection) then FreeAndNil(TIBTransaction.FCriticalSection); + if assigned(TIBTransaction.FTransactionList) then FreeAndNil(TIBTransaction.FTransactionList); end. diff --git a/runtime/nongui/IBXServices.pas b/runtime/nongui/IBXServices.pas index 4f9b8c40..c9f7cf9e 100644 --- a/runtime/nongui/IBXServices.pas +++ b/runtime/nongui/IBXServices.pas @@ -341,11 +341,17 @@ TIBXBackupRestoreService = class(TIBXControlAndQueryService) private FStatisticsRequested: TBackupStatsOptions; FVerbose: Boolean; + FParallelWorkers: Integer; protected procedure SetServiceStartOptions; override; property Verbose : Boolean read FVerbose write FVerbose default False; property StatisticsRequested: TBackupStatsOptions read FStatisticsRequested write FStatisticsRequested; published + {Number of workers the server should use for the backup or restore, as + gbak -par does. Firebird 5 and later; an older server rejects the + parameter, so it is only sent when the server can take it. Zero or one + means the default, single-threaded behaviour.} + property ParallelWorkers: Integer read FParallelWorkers write FParallelWorkers default 0; end; TBackupOption = (IgnoreChecksums, IgnoreLimbo, MetadataOnly, NoGarbageCollection, @@ -479,8 +485,10 @@ TIBXOnlineValidationService = class(TIBXControlAndQueryService) property DatabaseName; end; + {UpgradeODS is appended rather than inserted so that the existing values keep + their ordinals for anything already compiled against this unit.} TValidateOption = (CheckDB, IgnoreChecksum, KillShadows, MendDB, - SweepDB, ValidateDB, ValidateFull); + SweepDB, ValidateDB, ValidateFull, UpgradeODS); TValidateOptions = set of TValidateOption; { TIBXValidationService } @@ -1694,6 +1702,13 @@ procedure TIBXValidationService.SetServiceStartOptions; if not (MendDB in Options) then param := param or isc_spb_rpr_validate_db; end; + {Firebird 5 and later: upgrade the on-disk structure in place, as + gfix -upgrade does, rather than by backup and restore. Only sent to a + server that knows the option, since an older one rejects it.} + if (UpgradeODS in Options) then + with ServicesConnection do + if ServerVersionNo[1] >= 5 then + param := param or isc_spb_rpr_upgrade_db; if param > 0 then SRB.Add(isc_spb_options).AsInteger := param; end; @@ -1928,6 +1943,14 @@ procedure TIBXBackupRestoreService.SetServiceStartOptions; if Verbose then SRB.Add(isc_spb_verbose); + {Firebird 5 and later. isc_spb_bkp_parallel_workers and + isc_spb_res_parallel_workers are the same parameter code, so one property + serves both directions.} + if FParallelWorkers > 1 then + with ServicesConnection do + if ServerVersionNo[1] >= 5 then + SRB.Add(isc_spb_bkp_parallel_workers).AsInteger := FParallelWorkers; + with ServicesConnection do {Firebird 2.5.5 and later} if (ServerVersionNo[1] < 2) or