David T
David T

Reputation: 13

Delphi XE7 BDE Alias - setting it at run time?

I use Delphi XE7, and one of our large legacy applications still uses the BDE extensively with Paradox tables. I know the BDE is deprecated, but we have no choice with this app.

This app currently sets up the BDE aliases at run time, at startup. It uses the standard default Session provided by the BDE, and it uses "TSession.AddStandardAlias" to add an alias, and refers to many tables defined in data modules.

I now have the need to be able to change the folder path an alias refers to later in the running of the app, but have found problems with it. Basically, it seems to work, but after the alias is changed it somehow still refers to the previous path. Even "TSession.GetAliasParams" reports the new path, but then an error occurs in Bde.DBTables because it's trying to access the previous path, which no longer exists.

Given the app is large, I've reproduced a similar problem in the following sample project. If someone is willing to try this, it's a very simple app with just the main form. You need to setup two folders, and drop any Paradox table into one folder, when then specify that path to that folder in the Edit box and then press the "Set Alias Path" button, that will set the alias, and then it writes to a label below the button that tells you the path the alias refers to. Then the "Find table" button and edit box looks for the existence of a table using "TSession.GetTableNames".

The simplest way to do it is to setup two folders "C:\TEMP\testBDE\path1" and "C:\TEMP\testBDE\path2", and drop any Paradox table into path1, when you run the app press the "Set Alias Path" button, and then press the "Find table" button and it will report the table exists.

Main form of sample app

Then change the alias to refer to path2, which is empty, and it reports it pointing path2, but also reports the table exists. It's easy then to move the table from path1 to path2, and it will then report the table does not exist.

Any advice would be greatly appreciated.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Button2: TButton;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Bde.DBTables;

const
  myAlias = 'ALIAS1';

function getPathFromAlias(tempAlais : String ): String;
var
  MyStringList : TStringList;
  i, k: integer;
  tempStr, newDirectory: String;
begin
  newDirectory:='';
  MyStringList := TStringList.Create;
  try
    Session.GetAliasParams(tempAlais,MyStringList);
    { fill stringlist with driver names }
    for i := 0 to MyStringList.count-1 do
    begin
      tempStr:= uppercase(trim(MyStringList.Strings[i]));
      k := pos('PATH=', tempStr);
      if k > 0 then
      begin
        delete(tempStr,1, k+4);
        newDirectory:=tempStr;
      end;
    end;
  finally
    MyStringList.Free;
  end;
  result:=newDirectory;
end;

procedure setAliases( apath : String);
var
  MyStringList : TStringList;
begin
(*
  MyStringList := TStringList.Create;
  try
    MyStringList.Add( 'PATH='+apath);
    MyStringList.Add( 'ENABLE BCD=FALSE');
    MyStringList.Add( 'DEFAULT DRIVER=PARADOX');
    Session.ConfigMode := cmSession;
    if Session.IsAlias( myAlias) then
      Session.ModifyAlias( myAlias, MyStringList)
    else
      Session.AddStandardAlias( myAlias, apath, 'PARADOX');
    Session.ConfigMode := cmSession;
  finally
    MyStringList.Free;
  end;
*)
  Session.ConfigMode := cmSession;
  if Session.IsAlias( myAlias) then
    Session.DeleteAlias( myAlias);
  Session.AddStandardAlias( myAlias, apath, 'PARADOX');
  Session.ConfigMode := cmSession;

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  setAliases( Edit1.Text);
  Label1.Caption := getPathFromAlias( myAlias);
end;

function TableExists(const aDataBaseName, aTableName:string): Boolean;
var
  TableNames: TStringList;
begin

  TableNames:=TStringList.Create;
  try
    Session.GetTableNames(aDatabaseName,'',True,False,TableNames);
    Result:=(TableNames.IndexOf(aTableName)<>-1);
  finally
    TableNames.Free;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  temps : String;
  myTable : TTable;
begin

  if TableExists( myAlias, Edit2.Text) then
    Label2.Caption := 'Exists'
  else
    Label2.Caption := 'Not found'
end;

end.

Upvotes: 1

Views: 1609

Answers (1)

Deltics
Deltics

Reputation: 23046

You need to Close the session before changing the alias properties and then Open it again afterward:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Session.Close;

  setAliases( Edit1.Text);
  Label1.Caption := getPathFromAlias( myAlias);

  Session.Open;
end;

The problem is not that path changes are not recognised but that such changes are not recognised if they are made to aliases that are in use as this scenario in your test program illustrates:

  1. Button 1 clicked: path is changed
  2. Button 2 clicked: Table is not found
  3. Change path in Edit 1 to refer back to original alias path
  4. Use Button 1 to reset path
  5. Button 2 clicked: Table is still not found

i.e. if the first thing you do is change the path, then the alias does indeed reflect that changed path. The issue is that once you have used an alias, changes to the path are not subsequently reflected.

By closing the session and re-opening it, you ensure that the alias is properly "reset".

In your actual application this may cause knock-on effects with database connections needing to be re-opened after closing and re-opening the session, although this is speculation on my part.

Alternative Approach

As an alternative to closing the session in order to modify an alias at runtime, another approach might be to add a new alias with the required properties and redirect the database connections to that alternate alias.

This also will obviously entail disconnecting and reconnecting all databases and queries that are redirected to this alternate alias.

Upvotes: 1

Related Questions