Subject | run a stored procedure in a separate thread using IBO |
---|---|
Author | |
Post date | 2014-06-14T08:35:28Z |
In an IBO and FB program I want to run a stored procedure when the first user logs into the DB each day. It could be the procedure takes a while. I wanted to do this without delaying the users start-up time. More generally I have other programs where it would be nice to run a stored procedure and not wait for its return before allowing the user to do other things. Rob martin suggested I run the SP in a separate thread and gave some indicative code. The code by Delphi is in class TThread.
The OTL manual discusses its use for DBs. This library looks nice.
Omni Thread Library is here: http://www.omnithreadlibrary.com/
Its use with databass is discussed here: book:howto:databases [OmniThreadLibrary book]
The code here is in a datamodule with no components. It should be self explaining. I have tested it by running it 101 times in a loop with no errors. However I do not understand well the architecture of Windows Threading so am not sure how to make a stress test for this code.
unit dmExtThreadpas;
interface
uses
forms,
SysUtils, Classes, IB_Components, IB_Session, dialogs,
utils01, {for sayDiagnosticsLog} globals {for gbcdConnectionDetails};
type Tbcd2ndThread = class(TThread)
public
procToRun: string;
constructor create(aProcToRun: string; aConnectionDetails: TbcdConnectionDetails);
// the TbcdConnectionDetails is a record with four fields, see below
protected
connectionDetails : TbcdConnectionDetails;
Procedure Execute; override;
end; // bcd2ndThread
type
TdmExtThread = class(TDataModule)
procedure DataModuleCreate(sender:tobject);
private
{ Private declarations }
my2ndThread : Tbcd2ndThread;
public
{ Public declarations }
function runProcedure(aProcedure : String):Boolean;
end; // TdmExtThread
var
dmExtThread: TdmExtThread;
my2ndThread : Tbcd2ndThread;
implementation
{$R *.dfm}
procedure TdmExtThread.dataModulecreate(sender:Tobject);
begin
;
end; // dataModuleCreate
function TdmExtThread.runProcedure(aProcedure : String):Boolean;
begin
SayDiagnosticsLog('runProcedure('+aProcedure+') called'); // in utils01
// gbcdConnectionDetails is in globals
my2ndThread := Tbcd2ndThread.create(aProcedure, gbcdConnectionDetails); // ctor
with my2ndThread.connectionDetails do
begin
protocol := gbcdConnectionDetails.protocol; // TIB_PROTOCOL
password := gbcdConnectionDetails.password; // string
username := gbcdConnectionDetails.username; // string
databaseName := gbcdConnectionDetails.databasename; // string
end; // with
my2ndThread.FreeOnTerminate := true;
my2ndThread.start; // start the TThread
end; // runProcedure
constructor Tbcd2ndThread.create(aProcToRun:String; aConnectionDetails: TbcdConnectionDetails);
begin
inherited create(true); // "true" to start the TThread suspended
procToRun := aProcToRun;
connectionDetails := aConnectionDetails;
end;
procedure Tbcd2ndThread.execute;
var
ssnExtThread: TIB_Session;
cnExtThread: TIB_Connection;
trExtThread: TIB_Transaction;
dsqlExtThread: TIB_DSQL;
// local scope so destroyed when Execute goes out of scope
begin
// the TIB_Session for this thread
ssnExtThread := TIB_Session.create(nil);
ssnExtThread.UseCursor := false;
ssnExtThread.DefaultConnection := cnExtThread;
// the TIB_Connection for this thread
cnExtThread := TIB_Connection.CreateForSession(nil,ssnExtThread);
cnExtThread.DefaultTransaction := trExtThread;
cnExtThread.IB_Session := ssnExtThread;
// The TIB_Transaction for this thread
trExtThread := TIB_Transaction.CreateForSession(nil,ssnExtThread);
trExtThread.IB_Session := ssnExtThread;
trExtThread.IB_Connection := cnExtThread;
trExtThread.Isolation := tiCommitted;
// the TIB_DSQL used in this thread
dsqlExtThread := TIB_DSQL.CreateForSession(nil,ssnExtThread);
dsqlExtThread.IB_Connection := cnExtThread;
dsqlExtThread.IB_Transaction := trExtThread;
cnExtThread.database := connectionDetails.databaseName;
cnExtThread.Username := connectionDetails.Username;
cnExtThread.password := connectionDetails.password;
cnExtThread.protocol := connectionDetails.protocol;
cnExtThread.connect;
if cnExtThread.Connected then
with dsqlExtThread do
begin
sql.text := 'execute Procedure '+procToRun;
prepare;
Execute;
end; // if connected
Terminate; // this thread has done its work
end; // Execute
end.