Componentes.Terceros.RemObj.../official/5.0.35.741/Data Abstract for Delphi/Source/uDAHETDriver.pas
2009-02-27 15:16:56 +00:00

233 lines
6.2 KiB
ObjectPascal

unit uDAHETDriver;
{----------------------------------------------------------------------------}
{ Data Abstract Library - 'Rosetta' Library - HIGHLY CONFIDENTIAL
{
{ compiler: Delphi 6 and up
{ platform: Win32
{
{ (c)opyright RemObjects Software. all rights reserved.
{
{ Using this code requires a valid license of the Data Abstract
{ which can be obtained at http://www.remobjects.com.
{----------------------------------------------------------------------------}
{$I DataAbstract.inc}
interface
// {$R DataAbstract_Rosetta_Glyphs.res}
uses
Classes, SysUtils,
uDAInterfaces, uDAClasses, uDAEngine, uDARes, uDADriverManager,
uDAHETConnections, DB;
type
TDAHETDriver = class(TDADriverReference)
end;
TDAEHETDriver = class(TDAEDriver)
protected
function GetConnectionClass: TDAEConnectionClass; override;
function GetDriverID: string; override;
function GetDescription: string; override;
public
end;
TDAEHETConnection = class(TDAEConnection, IDAHETConnection)
private
fInTransaction: boolean;
fActiveConnections: TStringList;
function GetConnectionByName(const aConnectionName: string; aOpenConnection: boolean = false): IDAConnection;
protected
function DoBeginTransaction: Integer; override;
procedure DoCommitTransaction; override;
procedure DoRollbackTransaction; override;
function DoGetInTransaction: Boolean; override;
function CreateCustomConnection: TCustomConnection; override;
function GetConnected: Boolean; override; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF}
public
constructor Create(aDriver: TDAEDriver; aName: string = ''); override;
destructor Destroy; override;
{ IDAHETConnection }
function GetConnectionForObject(const aObjectName: string; aOpenConnection: boolean = false): IDAConnection;
end;
TDAHETConnectionContainer = class
private
fConnection: IDAConnection;
constructor Create(aConnection: IDAConnection);
end;
procedure Register;
function GetDriverObject: IDADriver; stdcall;
implementation
{ TDAEHETDriver }
function TDAEHETDriver.GetConnectionClass: TDAEConnectionClass;
begin
result := TDAEHETConnection;
end;
function TDAEHETDriver.GetDescription: string;
begin
result := 'Connection for Heterogenous Queries across multiple databases';
end;
function TDAEHETDriver.GetDriverID: string;
begin
result := 'HET';
end;
{ TDAEHETConnection }
constructor TDAEHETConnection.Create(aDriver: TDAEDriver; aName: string = '');
begin
inherited;
fActiveConnections := TStringList.Create();
fActiveConnections.Sorted := true;
fActiveConnections.Duplicates := dupError;
end;
function TDAEHETConnection.CreateCustomConnection: TCustomConnection;
begin
result := nil;
end;
destructor TDAEHETConnection.Destroy;
var
i: Integer;
begin
for i := 0 to fActiveConnections.Count-1 do
fActiveConnections.Objects[i].Free();
FreeAndNil(fActiveConnections);
//ToDo: auto-transacton handling?
inherited;
end;
function TDAEHETConnection.DoBeginTransaction: Integer;
var
i: Integer;
begin
if fInTransaction then
raise Exception.Create('Already in a transaction');
for i := 0 to fActiveConnections.Count-1 do
(fActiveConnections.Objects[i] as TDAHETConnectionContainer).fConnection.BeginTransaction();
fInTransaction := true;
result := 0;
end;
procedure TDAEHETConnection.DoCommitTransaction;
var
i: Integer;
begin
inherited;
try
for i := 0 to fActiveConnections.Count-1 do
(fActiveConnections.Objects[i] as TDAHETConnectionContainer).fConnection.CommitTransaction();
except
// ToDo: we need to use a two-phase commit here, to properly handle any single commit failing
// to roll back ALL transactons (inclusing those already (tentatively) comitted.
DoRollbackTransaction();
raise;
end;
fInTransaction := false;
end;
procedure TDAEHETConnection.DoRollbackTransaction;
var
i: Integer;
begin
inherited;
for i := 0 to fActiveConnections.Count-1 do
(fActiveConnections.Objects[i] as TDAHETConnectionContainer).fConnection.RollbackTransaction();
fInTransaction := false;
end;
function TDAEHETConnection.DoGetInTransaction: Boolean;
begin
result := fInTransaction;
end;
function TDAEHETConnection.GetConnected: Boolean;
begin
result := true;
end;
function TDAEHETConnection.GetConnectionForObject(const aObjectName: string; aOpenConnection: boolean = false): IDAConnection;
var
lConnectionName: string;
begin
lConnectionName := (ConnectionDefinition as TDAHETConnection).ObjectMappings.Values[aObjectName];
if lConnectionName = '' then
raise Exception.CreateFmt('HET Connection "%s" does not contain an object mapping for "%s".', [ConnectionName, aObjectName]);
result := GetConnectionByName(lConnectionName);
end;
function TDAEHETConnection.GetConnectionByName(const aConnectionName: string; aOpenConnection: boolean = false): IDAConnection;
var
i: Integer;
begin
if aConnectionName = self.ConnectionName then
raise Exception.CreateFmt('Cannot use HET Connection "%s" nested within itself.', [ConnectionName]);
i := fActiveConnections.IndexOf(aConnectionName);
if i >= 0 then begin
result := (fActiveConnections.Objects[i] as TDAHETConnectionContainer).fConnection
end
else begin
result := ConnectionManager.NewConnection(aConnectionName, true); //todo: aOpenConnection
if fInTransaction then result.BeginTransaction;
fActiveConnections.AddObject(aConnectionName, TDAHETConnectionContainer.Create(result));
end;
end;
{ TDAHETConnectionContainer }
constructor TDAHETConnectionContainer.Create(aConnection: IDAConnection);
begin
fConnection := aConnection;
end;
{ global driver registration }
var
_driver: TDAEDriver = nil;
procedure Register;
begin
RegisterComponents(DAPalettePageName, [TDAHETDriver]);
end;
function GetDriverObject: IDADriver;
begin
if (_driver = nil) then _driver := TDAEHETDriver.Create(nil);
result := _driver;
end;
exports
GetDriverObject name func_GetDriverObject;
initialization
_driver := nil;
RegisterDriverProc(GetDriverObject);
finalization
UnregisterDriverProc(GetDriverObject);
FreeAndNIL(_driver);
end.