Articles   Members Online: 3
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
How to pack a Paradox or dBase table programmatically Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
Pack a Paradox or dBase table programatically 28-Aug-02
Category
DB-General
Language
Delphi 4.x
Views
112
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Jonas Bilinkevicius 

How to pack a Paradox or dBase table programmatically

Answer:

Solve 1:
1   
2   function dgPackParadoxTable(Tbl: TTable; Db: TDatabase): DBIResult;
3   {Packs a Paradox table by calling the BDE DbiDoRestructure function. The TTable 
4   passed as the first parameter must be closed. The TDatabase passed as the second 
5   parameter must be connected.}
6   var
7     TblDesc: CRTblDesc;
8   begin
9     Result := DBIERR_NA;
10    FillChar(TblDesc, SizeOf(CRTblDesc), 0);
11    StrPCopy(TblDesc.szTblName, Tbl.TableName);
12    TblDesc.bPack := True;
13    Result := DbiDoRestructure(Db.Handle, 1, @TblDesc, nil, nil, nil, False);
14  end;



Solve 2:

If you use the DBGrid and DBNavigator to delete records in a table which has unique 
fields, you will find that the table grows relentlessly and you can't re-enter the 
same data without packing the table first.

The following routine will pack and reindex a DBase and Paradox table, taking from 
a few seconds to a few minutes. Tested with a 650K DBaseIV file. Much quicker after 
the first call.

Just add the code below to the relevant sections. Call the function with your 
table's name, then wait while it grinds away. Returns True if the table is packed 
successfully.

15  uses
16    WinProcs, Classes, SysUtils, StdCtrls, Forms, Controls, DB, DBIProcs, DBITypes,
17    DBIErrs, DBTables;
18  
19  {Add to declarations}
20  
21  function PackTable(tbl: TTable): Boolean;
22  
23  {Add to Implementation}
24    function PackTable(tbl: TTable): Boolean;
25  
26      {Packs a DBaseIV (and Paradox?) table}
27    var
28      crtd: CRTblDesc;
29      db: TDataBase;
30    begin
31      try
32        Screen.Cursor := crHourglass;
33        Result := True;
34        with tbl do
35        begin
36          db := DataBase;
37          if Active then
38            Active := False;
39          if not db.Connected then
40            db.Connected := True;
41          FillChar(crtd, SizeOf(CRTblDesc), 0);
42          StrPCopy(crtd.szTblName, TableName);
43          crtd.bPack := True;
44          if DbiDoRestructure(db.Handle, 1, @crtd, nil, nil, nil, False) <> 
45  DBIERR_NONE then
46            Result := False;
47          Open;
48        end;
49      except
50        on Exception do {any exception}
51          Result := False;
52      end;
53      Screen.Cursor := crDefault;
54  end;



Solve 3:

Wouldn't it be great for the TTable component to have a method that does this? Just 
open up a TTable, connected it to a table on disk, call the method, and wham! The 
table's packed (Hmm.... I just might have to look into that). But short of that, 
you have to make direct calls to the BDE to accomplish this task. For dBase tables, 
it's easy. There's a single function called dbiPackTable that'll pack any dBase 
file. For Paradox files, you have to jump through a couple of hoops first, then 
call dbiDoRestructure because Paradox tables can only be packed within the context 
of a table restructure (Note: If you've restructured a table in Paradox or the 
Database Desktop, you'll notice a checkbox at the bottom of the restructure dialog 
called "Pack Table").

Below is a simple procedure for packing tables. I took most of the code right out 
of the online help (yes, there's really good stuff in there if you know where 
look), and made some alterations. The difference between what I did and what the 
help file lists is that instead of the formal parameter being a TTable, I require a 
fully qualified file name (path/name). This allows for greater flexibility - the 
procedure opens up its own TTable and works on it instead you having to create one 
yourself. I guess it might all boil down to semantics, but I still like my way 
better (so there!). Check out the code below:

55  procedure PackTable(TblName: string);
56  var
57    tbl: TTable;
58    cProps: CURProps;
59    hDb: hDBIDb;
60    TblDesc: CRTblDesc;
61  begin
62  
63    tbl := TTable.Create(nil);
64    with tbl do
65    begin
66      Active := False;
67      DatabaseName := ExtractFilePath(TblName);
68      TableName := ExtractFileName(TblName);
69      Exclusive := True;
70      Open;
71    end;
72  
73    // Added 23/7/2000 to make sure that the current path is the same as the table
74    //see note below
75  
76    SetCurrentDir(ExtractFilePath(TblName));
77  
78    // Make sure the table is open exclusively so we can get the db handle...
79    if not tbl.Active then
80      raise EDatabaseError.Create('Table must be opened to pack');
81  
82    if not tbl.Exclusive then
83      raise EDatabaseError.Create('Table must be opened exclusively to pack');
84  
85    // Get the table properties to determine table type...
86    Check(DbiGetCursorProps(tbl.Handle, cProps));
87  
88    // If the table is a Paradox table, you must call DbiDoRestructure...
89    if (cProps.szTableType = szPARADOX) then
90    begin
91      // Blank out the structure...
92      FillChar(TblDesc, sizeof(TblDesc), 0);
93      // Get the database handle from the table's cursor handle...
94      Check(DbiGetObjFromObj(hDBIObj(tbl.Handle), objDATABASE, hDBIObj(hDb)));
95      // Put the table name in the table descriptor...
96      StrPCopy(TblDesc.szTblName, tbl.TableName);
97      // Put the table type in the table descriptor...
98      StrPCopy(TblDesc.szTblType, cProps.szTableType);
99      // Set the Pack option in the table descriptor to TRUE...
100     TblDesc.bPack := True;
101     // Close the table so the restructure can complete...
102     tbl.Close;
103     // Call DbiDoRestructure...
104     Check(DbiDoRestructure(hDb, 1, @TblDesc, nil, nil, nil, False));
105   end
106   else
107     {// If the table is a dBASE table, simply call DbiPackTable...} if
108       (cProps.szTableType = szDBASE) then
109       Check(DbiPackTable(tbl.DBHandle, tbl.Handle, nil, szDBASE, True))
110     else
111       // Pack only works on Paradox or dBASE; nothing else...
112       raise EDatabaseError.Create('You can only pack Paradox or dBase tables!');
113 
114   with tbl do
115   begin
116     if Active then
117       Close;
118     Free;
119   end;
120 end;


See? Nothing fancy. What you should know is that all operations involving 
dbiDoRestructure revolve around a table descriptor type CRTblDesc. With this record 
type, you can set various field values, then execute dbiDoRestructure to make your 
changes. That's kind of the trick to making BDE calls in general. You typically 
work with some sort of record structure, then use that structure in one of the 
calls. I know I'm probably oversimplifying, but that's it in a nutshell. The point? 
Don't be scared of the BDE. More later!

I encourage you to look at the BDE online help under any dbi- subject. There are 
lots of code examples that will get you on your way.

NOTE: I received an email from Stewart Nightingale who said "When running PackTable straight after saving something to floppy it became obvious that packing a table must use the current directory for temporary tables and things - the current directory was "a:" and it came up with an error saying "No Disk in Drive a:". I put in the line "SetCurrentDir(ExtractFilePath(TblName));" at the top of the procedure so it would work properly ." I have added this line to the code sample shown above - use it if you wish, leave it out if you do not...........

			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC