Delphi Clinic | C++Builder Gate | Training & Consultancy | Delphi Notes Weblog | Dr.Bob's Webshop |
|
BDE Alias Analyser
But first of all, let's consider my BDE Alias analyser.
The purpose of this little tool (which can be seen in Listing 1), is to walk through all tables in a given alias, and produce some detailed information for each of these tables.
The helpful method that gives us all tablenames for a given alias can be obtained by calling the GetTableNames method from an active Session component (very BDE specific, indeed), as follows:
Once we have a list of TableNames, we need to use those to open specific TTable components (using both the given AliasName and TableName) and list relevant information for fields, such as Name, Type and whether or not a value is required.
We can also use the IndexDefs to list the known indices (like the primary index).
program analias;
{$APPTYPE CONSOLE}
uses
Classes, DB, DBTables;
var
i,j: Integer;
TableNames: TStringList;
begin
TableNames := TStringList.Create;
with TSession.Create(nil) do
try
AutoSessionName := True;
GetTableNames(ParamStr(1), '', True, False, TableNames);
finally
Free
end;
with TTable.Create(nil) do
try
DatabaseName := ParamStr(1);
for j:=0 to Pred(TableNames.Count) do
begin
writeln;
TableName := TableNames[j];
Open;
writeln(TableNames[j],' ',RecordCount:4);
writeln('<TABLE BORDER=1>');
writeln('<TR><TD BGCOLOR=FFFFFF>Field</TD>'+
'<TD BGCOLOR=FFFFFF>Name</TD>'+
'<TD BGCOLOR=FFFFFF>Type</TD>'+
'<TD BGCOLOR=FFFFFF>Req</TD></TR>');
for i:=0 to Pred(FieldCount) do
begin
write('<TR><TD>',i,'</TD><TD>');
write(Fields[i].DisplayName,'</TD><TD>');
write(FieldDefs[i].FieldClass.ClassName);
if FieldDefs[i].DataType = ftString then
write('[',FieldDefs[i].Size,']');
write('</TD><TD>');
if FieldDefs[i].Required then write('Yes');
writeln('</TD></TR>');
end;
writeln('</TABLE>');
writeln('<BR>');
IndexDefs.Update;
if IndexDefs.Count > 0 then
begin
writeln('<TABLE BORDER=1>');
writeln('<TR><TD BGCOLOR=FFFFFF>Index</TD>'+
'<TD BGCOLOR=FFFFFF>Name</TD>'+
'<TD BGCOLOR=FFFFFF>Fields</TD></TR>')
end;
for i:=0 to Pred(IndexDefs.Count) do
begin
write('<TR><TD>',i,'</TD><TD>');
write(IndexDefs[i].DisplayName,'</TD><TD>');
write(IndexDefs[i].Fields);
writeln('</TD></TR>')
end;
writeln('</TABLE>');
writeln('<P>');
Close
end
finally
Free
end
end.
Listing 1. BDE Alias Analyser (producing HTML)
Note that the code from Listing 1. uses HTML tags as delimiter between the different values (or columns). This is done so I can import the resulting file inside Windows, and convert the text to a Winword table, which results in a nice and readable report (but I could have used tabs as well). As an example, the table BIOLIFE.DB from Alias DBDEMOS is analysed and reported as follows:
biolife.db 28
Field | Name | Type | Req |
0 | Species No | TFloatField | |
1 | Category | TStringField[15] | |
2 | Common_Name | TStringField[30] | |
3 | Species Name | TStringField[40] | |
4 | Length (cm) | TFloatField | |
5 | Length_In | TFloatField | |
6 | Notes | TMemoField | |
7 | Graphic | TGraphicField |
Index | Name | Fields |
0 | | Species No |
By the way, you can extend the code from listing 1. with additional features that can report even more information, like range (min value, max value), etc. but the information printed above is usually enough for my first analysis anyway.
dbExpress Analyser
As you probably know: Kylix is shipping (I recently received my copy of Kylix Server Developer edition), and - what you may or may not know - Kylix is not using the BDE, but rather uses something called dbExpress for data access.
And Delphi 6 will be using BDE as well as dbExpress, so most of what I'm saying in the remainder of this article will probably also work with the forthcoming Delphi 6 (at least, that's what I've been told).
Anyway, to move the code in listing 1 from Windows (Delphi) to Linux (Kylix), I usually FTP it to my Linux machine, and then open the project in Kylix.
I won't bother you here with details regarding .res, .opt, .cfg and .dfm files, we only have to worry about a single analias.dpr file here, which can be moved over and loaded in Kylix without too much trouble.
Of course, loading in Kylix and recompiling with Kylix are two different matters.
And since the original application is very BDE specific (TSession and TTable), we need to look at dbExpress alternatives instead (like SQLConnection and SQLTable).
But first, we need to replace the DBTables unit with SqlExpr.
Now, we can replace the TSession with TSQLConnection.
The AutoSessionName property makes no sense her, but we can set the ConnectionName to initialise the TSQLConnection component (and can make it active by setting Connected to true).
Once we have a list of TableNames, we can again loop through it, and create TSQLTable components.
The only difference with a BDE TTable is that we no longer need to mention a DatabaseName, but an SQLConnection instead (which must point to an existing SQLConnection instance, just like we should have used a TDatabase component in the BDE example, which should have been much better).
program analias; {$APPTYPE CONSOLE} uses Classes, DB, SqlExpr; var i,j: Integer; TableNames: TStringList; SQLConnection1: TSQLConnection; begin TableNames := TStringList.Create; SQLConnection1 := TSQLConnection.Create(nil); with SQLConnection1 do begin LoadParamsOnConnect := True; ConnectionName := ParamStr(1); Connected := True; GetTableNames(TableNames); end; with TSQLTable.Create(nil) do try SQLConnection := SQLConnection1; for j:=0 to Pred(TableNames.Count) do begin writeln; TableName := TableNames[j]; Open; writeln(TableNames[j],' ',RecordCount:4); for i:=1 to Length(TableNames[j])+5 do write('='); writeln; writeln('Field'#9'Name'#9'Type'#9'Req'); for i:=0 to Pred(FieldCount) do begin write(i,#9); write(Fields[i].DisplayName,#9); write(FieldDefs[i].FieldClass.ClassName); if FieldDefs[i].DataType = ftString then write('[',FieldDefs[i].Size,']'); if FieldDefs[i].Required then write(#9'Yes'); writeln end; IndexDefs.Update; if IndexDefs.Count > 0 then begin writeln; writeln('Index'#9'Name'#9'Fields') end; for i:=0 to Pred(IndexDefs.Count) do begin write(i,#9); write(IndexDefs[i].DisplayName,#9); write(IndexDefs[i].Fields); writeln end; writeln; Close end finally Free; SQLConnection1.Free end end.Listing 2. dbExpress Connection Analyser (producing ASCII)
Note that LoadParamsOnConnect which we must set to True and is needed to make sure that the SQLConnection component will load the DriverName and Params automatically when you set (or change) the value of ConnectionName. In this particular case, ConnectionName should be defined in your file "dbxdrivers" (as described in the Kylix Developer's Guide page 19-2). As you can see, it took just over 10 lines of code to change, one unit, two components and a few properties, and now this applications compiles with Kylix. And will also work with Delphi 6, of course.