Devart ODAC driver

Devart ODAC driver

This unit, directly inspired by Aurelius.Drivers.UniDac.pas seems to work:



unit Aurelius.Drivers.Odac;

{$I Aurelius.inc}

interface

uses
  Classes, DB, Variants, Generics.Collections,
  DBAccess,
  Aurelius.Drivers.Base,
  Aurelius.Drivers.Interfaces;

type
  TOdacResultSetAdapter = class(TDriverResultSetAdapter<TCustomDADataset>)
  end;

  TOdacStatementAdapter = class(TInterfacedObject, IDBStatement)
  private
    FQuery: TCustomDADataset;
  public
    constructor Create(AQuery: TCustomDADataset);
    destructor Destroy; override;
    procedure SetSQLCommand(SQLCommand: string);
    procedure SetParams(Params: TEnumerable<TDBParam>);
    procedure Execute;
    function ExecuteQuery: IDBResultSet;
  end;

  TOdacConnectionAdapter = class(TDriverConnectionAdapter<TCustomDAConnection>, IDBConnection)
  public
    procedure Connect;
    procedure Disconnect;
    function IsConnected: Boolean;
    function CreateStatement: IDBStatement;
    function BeginTransaction: IDBTransaction;
    function RetrieveSqlDialect: string; override;
  end;

  TOdacTransactionAdapter = class(TInterfacedObject, IDBTransaction)
  private
    FConnection: TCustomDAConnection;
  public
    constructor Create(AConnection: TCustomDAConnection);
    procedure Commit;
    procedure Rollback;
  end;

implementation

{ TOdacStatementAdapter }

uses
  SysUtils,
  Ora,
  Aurelius.Drivers.Exceptions,
  Aurelius.Global.Utils;

constructor TOdacStatementAdapter.Create(AQuery: TCustomDADataset);
begin
  FQuery := AQuery;
end;

destructor TOdacStatementAdapter.Destroy;
begin
  FQuery.Free;
  inherited;
end;

procedure TOdacStatementAdapter.Execute;
begin
  FQuery.ExecSQL;
end;

function TOdacStatementAdapter.ExecuteQuery: IDBResultSet;
var
  ResultSet: TCustomDADataset;
  I: Integer;
begin
  ResultSet := FQuery.Connection.CreateDataSet;
  try
    ResultSet.Connection := FQuery.Connection;
    ResultSet.SQL := FQuery.SQL;
    for I := 0 to FQuery.Params.Count - 1 do
      ResultSet.Params.Assign(FQuery.Params);

    ResultSet.Open;
  except
    ResultSet.Free;
    raise;
  end;
  Result := TOdacResultSetAdapter.Create(ResultSet);
end;

procedure TOdacStatementAdapter.SetParams(Params: TEnumerable<TDBParam>);
var
  P: TDBParam;
  Parameter: TDAParam;
  Bytes: TBytes;
begin
  for P in Params do
  begin
    Parameter := FQuery.ParamByName(P.ParamName);
    Parameter.DataType := P.ParamType;
    Parameter.ParamType := ptInput;

    if P.ParamType in [ftOraBlob, ftOraClob, ftBlob] then
    begin
      Bytes := TUtils.VariantToBytes(P.ParamValue);
      if VarIsNull(P.ParamValue) or (Length(Bytes) = 0) then
        Parameter.Clear
      else
      begin
        Parameter.DataType := P.ParamType;
        Parameter.AsBlob := Bytes;
      end;
    end
    else
    if P.ParamType in [ftMemo, ftWideMemo] then
    begin
      if VarIsNull(P.ParamValue) or (Length(VarToStr(P.ParamValue)) = 0) then
        Parameter.AsMemo := ''
      else
      begin
        Parameter.AsMemo := P.ParamValue;
      end;
    end
    else
      Parameter.Value := P.ParamValue;
  end;
end;

procedure TOdacStatementAdapter.SetSQLCommand(SQLCommand: string);
begin
  FQuery.SQL.Text := SQLCommand;
end;

{ TOdacConnectionAdapter }

procedure TOdacConnectionAdapter.Disconnect;
begin
  if Connection <> nil then
    Connection.Connected := False;
end;

function TOdacConnectionAdapter.RetrieveSqlDialect: string;
begin
  if Connection = nil then
    Exit('');
  Result := 'Oracle';
end;

function TOdacConnectionAdapter.IsConnected: Boolean;
begin
  if Connection <> nil then
    Result := Connection.Connected
  else
    Result := false;
end;

function TOdacConnectionAdapter.CreateStatement: IDBStatement;
var
  Statement: TCustomDADataset;
begin
  if Connection = nil then
    Exit(nil);

  Statement := Connection.CreateDataSet;
  try
    Statement.Connection := Connection;
  except
    Statement.Free;
    raise;
  end;
  Result := TOdacStatementAdapter.Create(Statement);
end;

procedure TOdacConnectionAdapter.Connect;
begin
  if Connection <> nil then
    Connection.Connected := True;
end;

function TOdacConnectionAdapter.BeginTransaction: IDBTransaction;
begin
  if Connection = nil then
    Exit(nil);

  Connection.Connected := true;

  if not Connection.InTransaction then
  begin
    Connection.StartTransaction;
    Result := TOdacTransactionAdapter.Create(Connection);
  end else
    Result := TOdacTransactionAdapter.Create(nil);
end;

{ TOdacTransactionAdapter }

procedure TOdacTransactionAdapter.Commit;
begin
  if (FConnection = nil) then
    Exit;

  FConnection.Commit;
end;

constructor TOdacTransactionAdapter.Create(AConnection: TCustomDAConnection);
begin
  FConnection := AConnection;
end;

procedure TOdacTransactionAdapter.Rollback;
begin
  if (FConnection = nil) then
    Exit;

  FConnection.Rollback;
end;

end.


Hi Etienne,

 
thank you very much for sharing. Unfortunately we can't include this in official distribution because we don't have a license for ODAC and can't run the tests on it so we can't be sure it works in all scenarios. Unfortunately Devart didn't reply our requests for a license (just Unidac was provided).
But we will keep this as a reference for other users asking for it. It might be useful for others. Thanks again.