2010. szeptember 26., vasárnap
How to restructure a TTable
Problem/Question/Abstract:
How to restructure a TTable
Answer:
unit TTableRestruct;
{Freeware by Brett W. Fleming 1999
SetOperation method added by Bill Todd 1999}
interface
uses
BDE, DbTables;
type
TTableRestructure = class(TObject)
private
function GetField(Index: Integer): PFLDDesc;
function GetFieldLength(Index: Integer): Word;
function GetFieldName(Index: Integer): string;
function GetFieldType(Index: Integer): Word;
function GetFieldUnits(Index: Integer): Word;
function GetOperation(Index: Integer): PCROpType;
procedure SetFieldLength(Index: Integer; const Value: Word);
procedure SetFieldType(Index: Integer; const Value: Word);
procedure SetFieldUnits(Index: Integer; const Value: Word);
procedure SetFieldName(Index: Integer; const Value: string);
procedure DetailError(ErrorCode: DbiResult);
procedure SetOperation(Index: Integer; OpType: PCROpType);
protected
Fields: PFLDDesc;
Operations: PCROpType;
LocalFieldCount: Integer;
procedure DestroyFieldDescriptors;
public
constructor Create;
destructor Destroy; override;
function AddField: Integer;
function DeleteField(Index: Integer): Boolean;
function FindField(Name: string): Integer;
procedure LoadTableStructure(Table: TTable);
procedure SaveTableStructure(Table: TTable);
procedure PrintStructure;
property FieldCount: Integer read LocalFieldCount;
property FieldLength[Index: Integer]: Word read GetFieldLength write SetFieldLength;
property FieldName[Index: Integer]: string read GetFieldName write SetFieldName;
property FieldType[Index: Integer]: Word read GetFieldType write SetFieldType;
property FieldUnits[Index: Integer]: Word read GetFieldUnits write SetFieldUnits;
property Field[Index: Integer]: PFLDDesc read GetField;
property Operation[Index: Integer]: pCROpType read GetOperation write SetOperation;
end;
implementation
uses
SysUtils, Dialogs;
{Purpose:
To add a new field to the table
Parameters:
None
Effects:
A new blank field descriptor is created and added to the internal list of
Field Descriptors which is reallocated to accomodate the new field
Returns:
Index of the new field in the array, or -1 if the operation failed}
function TTableRestructure.AddField: Integer;
var
NewField: PFLDDesc;
NewOperation: pCROpType;
begin
Result := -1;
if (Fields <> nil) then
begin
ReallocMem(Fields, (LocalFieldCount + 1) * SizeOf(FLDDesc));
ReallocMem(Operations, (LocalFieldCount + 1) * SizeOf(CROpType));
{Move to the new field and empty it out}
NewField := Fields;
Inc(NewField, LocalFieldCount);
FillChar(NewField^, SizeOf(FLDDesc), 0);
NewField^.iFldNum := LocalFieldCount + 1;
{Move to the new operation and set it to add}
NewOperation := Operations;
Inc(NewOperation, LocalFieldCount);
NewOperation^ := crAdd;
Inc(LocalFieldCount);
{Return the new fields index}
Result := LocalFieldCount - 1;
end;
end;
{Purpose: To create a new instance of this class and initialize it's data
Parameters: None
Effects: See purpose}
constructor TTableRestructure.Create;
begin
Fields := nil;
Operations := nil;
LocalFieldCount := 0;
end;
{Purpose:
To delete a specific field from the tables description
Parameters:
Index - Index of the field that is to be removed
Effects:
The field is removed from the array of Field Descriptors and the memory that contains the list
is reallocated
Returns:
True if the operation was successfull, False otherwise}
function TTableRestructure.DeleteField(Index: Integer): Boolean;
var
FieldBefore,
FieldAfter: PFLDDesc;
OperationBefore,
OperationAfter: PCROpType;
begin
Result := False;
if (Fields <> nil) and (LocalFieldCount > 0) and (Index >= 0) and (Index < LocalFieldCount) then
begin
{Find the spot before and after the field to delete}
FieldBefore := Fields;
FieldAfter := Fields;
Inc(FieldBefore, Index);
Inc(FieldAfter, Index + 1);
{Find the spot before and after the operation to delete}
OperationBefore := Operations;
OperationAfter := Operations;
Inc(OperationBefore, Index);
Inc(OperationAfter, Index + 1);
{Now copy the data over the field to delete}
Move(FieldAfter^, FieldBefore^, (LocalFieldCount - Index) * SizeOf(FLDDesc));
Move(OperationAfter^, OperationBefore^, (LocalFieldCount - Index) * SizeOf(CROpType));
{Now shrink the allocated memory}
Dec(LocalFieldCount);
ReallocMem(Fields, LocalFieldCount * SizeOf(FLDDesc));
ReallocMem(Operations, LocalFieldCount * SizeOf(CROpType));
Result := True;
end;
end;
{Purpose: To destroy an instance of this class and any memory that was allocated
Parameters: None
Effects: See purpose}
destructor TTableRestructure.Destroy;
begin
DestroyFieldDescriptors;
end;
{Purpose: To destroy an array of field descriptors
Parameters: None
Effects: The Field Descriptors are freed, and the pointer set to nil}
procedure TTableRestructure.DestroyFieldDescriptors;
begin
if Fields <> nil then
begin
FreeMem(Fields);
Fields := nil;
FreeMem(Operations);
Operations := nil;
LocalFieldCount := 0;
end;
end;
{Purpose: To show the details of any Error returned by the BDE routines
Parameters: ErrorCode - Code returned byt the BDE
Effects: None}
procedure TTableRestructure.DetailError(ErrorCode: DbiResult);
var
ErrorInfo: DBIErrInfo;
ErrorString: string;
ErrorString2: string;
begin
if (ErrorCode <> dbiERR_NONE) then
begin
Check(DbiGetErrorInfo(True, ErrorInfo));
if (ErrorCode = ErrorInfo.iError) then
begin
ErrorString := 'Error Number: ' + IntToStr(ErrorInfo.iError) + #10 + #13;
ErrorString := ErrorString + 'Error Code: ' + string(ErrorInfo.szErrcode) + #10 + #13;
if (StrLen(ErrorInfo.szContext[1]) <> 0) then
ErrorString := ErrorString + 'Context1: ' + string(ErrorInfo.szContext[1]) + #10 + #13;
if (StrLen(ErrorInfo.szContext[2]) <> 0) then
ErrorString := ErrorString + 'Context2: ' + string(ErrorInfo.szContext[2]) + #10 + #13;
if (StrLen(ErrorInfo.szContext[3]) <> 0) then
ErrorString := ErrorString + 'Context3: ' + string(ErrorInfo.szContext[3]) + #10 + #13;
if (StrLen(ErrorInfo.szContext[4]) <> 0) then
ErrorString := ErrorString + 'Context4: ' + string(ErrorInfo.szContext[4]) + #10 + #13;
end
else
begin
SetLength(ErrorString2, dbiMaxMsgLen + 1);
Check(DbiGetErrorString(ErrorCode, PChar(ErrorString2)));
SetLength(ErrorString2, StrLen(PChar(ErrorString2)));
ErrorString := ErrorString + ErrorString2;
end;
ShowMessage(ErrorString);
end;
end;
{Purpose: To find a particular field's index by it's name
Parameters: Name - Name of the field to find in the current list of fields
Effects: None
Returns: Index of the field if found, or -1 if not found}
function TTableRestructure.FindField(Name: string): Integer;
var
Index: Integer;
begin
Result := -1;
Index := FieldCount - 1;
while (Index >= 0) and (Result < 0) do
begin
if CompareText(FieldName[Index], Name) = 0 then
Result := Index;
Dec(Index);
end;
end;
{Purpose: To return a pointer to a specified Field Descriptor
Parameters: Index - Index of the field descriptor
Effects: None
Returns: Pointer to a Field Descriptor or nil if Index isn't valid}
function TTableRestructure.GetField(Index: Integer): PFLDDesc;
begin
Result := nil;
if (Fields <> nil) and (Index >= 0) and (Index < LocalFieldCount) then
begin
Result := Fields;
Inc(Result, Index);
end;
end;
{Purpose: Get method for the FieldLength property
Parameters: Index - Index of a field descriptor
Effects: None
Returns: Length of the specified field or 0 if not field not found}
function TTableRestructure.GetFieldLength(Index: Integer): Word;
var
Field: PFLDDesc;
begin
Result := 0;
Field := GetField(Index);
if Field <> nil then
Result := Field^.iLen;
end;
{Purpose: Get method for the FieldName property
Parameters: Index - Index of a field descriptor
Effects: None
Returns: Name of the specified field or '' if not field not found}
function TTableRestructure.GetFieldName(Index: Integer): string;
var
Field: PFLDDesc;
begin
Result := '';
Field := GetField(Index);
if Field <> nil then
Result := string(Field^.szName);
end;
{Purpose: Get method for the FieldType property
Parameters: Index - Index of a field descriptor
Effects: None
Returns: Type of the specified field or -1 if not field not found}
function TTableRestructure.GetFieldType(Index: Integer): Word;
var
Field: PFLDDesc;
begin
Result := 0;
Field := GetField(Index);
if Field <> nil then
Result := Field^.iFldType;
end;
{Purpose: Get method for the FieldUnits property
Parameters: Index - Index of a field descriptor
Effects: None
Returns: Units1 of the specified field or -1 if not field not found}
function TTableRestructure.GetFieldUnits(Index: Integer): Word;
var
Field: PFLDDesc;
begin
Result := 0;
Field := GetField(Index);
if Field <> nil then
Result := Field^.iUnits1;
end;
{Purpose: To get a pointer to an operation type
Parameters: Index - Index of the operation that is desired
Effects: None
Returns: See purpose}
function TTableRestructure.GetOperation(Index: Integer): PCROpType;
begin
Result := nil;
if (Index >= 0) and (Index < FieldCount) then
begin
Result := Operations;
Inc(Result, Index);
end;
end;
{Purpose: To assign a new operation.
Parameters: Index - Index of the operation that is desired
Effects: None
Returns: None}
procedure TTableRestructure.SetOperation(Index: Integer; OpType: PCROpType);
var
ModifyOperations: PCROpType;
begin
ModifyOperations := Operations;
Inc(ModifyOperations, Index);
ModifyOperations^ := crModify;
end;
{Purpose:
To load in the table structure of the specified table
Parameters:
Table - Table whose structure will be loaded into memory
Effects:
Any previous structure is destroyed and replaced by the new structure if the table could be
opened successfully}
procedure TTableRestructure.LoadTableStructure(Table: TTable);
var
Index: Integer;
Field: PFLDDesc;
begin
DestroyFieldDescriptors;
if (Table <> nil) then
begin
Table.Open;
LocalFieldCount := Table.FieldCount;
Fields := AllocMem(LocalFieldCount * SizeOf(FLDDesc));
try
Operations := AllocMem(LocalFieldCount * SizeOf(CROpType));
try
FillChar(Operations^, LocalFieldCount * SizeOf(CROpType), crNOOP);
Check(DbiGetFieldDescs(Table.Handle, Fields));
Field := Fields;
for Index := 1 to LocalFieldCount do
begin
Field^.iFldNum := Index;
Inc(Field);
end;
except
FreeMem(Operations);
Operations := nil;
raise;
end;
except
FreeMem(Fields);
Fields := nil;
raise;
end;
end;
end;
{Purpose: No real purpose, other than for dumping out the current field data
Parameters: None
Effects: None}
procedure TTableRestructure.PrintStructure;
var
Index: Integer;
Field: pFLDDesc;
Op: PCROpType;
Item: string;
List: string;
begin
List := '# - Op - Type - Name' + #10#13;
Field := Fields;
Op := Operations;
for Index := 0 to LocalFieldCount - 1 do
begin
Item := Format('%d - %x - %d - %s', [Field^.iFldNum, Byte(Op^), FieldType[Index], Field^.szName]);
List := List + Item + #10 + #13;
Inc(Field);
Inc(Op);
end;
ShowMessage(List);
end;
{Purpose:
To modify a existing table to match the given field descriptors
Parameters:
Table - Table whose structure will be replaced by the structure in memory
Effects:
The table's structure is modified to match the current structure in memory. Once this is done, changes
can not be undone.}
procedure TTableRestructure.SaveTableStructure(Table: TTable);
var
TableDesc: CRTblDesc;
hDb: hDBIDb;
begin
Table.Open;
FillChar(TableDesc, sizeof(TableDesc), 0);
{Get the database handle from the table's cursor handle...}
Check(DbiGetObjFromObj(hDBIObj(Table.Handle), objDATABASE, hDBIObj(hDb)));
StrPCopy(TableDesc.szTblName, Table.TableName);
TableDesc.iFldCount := LocalFieldCount;
TableDesc.pecrFldOp := Operations;
TableDesc.pFldDesc := Fields;
Table.Close;
DetailError(DbiDoRestructure(hDb, 1, @TableDesc, nil, nil, nil, False));
end;
{Purpose: Set method for the FieldLength property
Parameters: Index - Index of the Field to modify / Value - New length of the field
Effects: The field descriptor is modified to reflect the change}
procedure TTableRestructure.SetFieldLength(Index: Integer; const Value: Word);
var
Field: PFLDDesc;
Operation: PCROpType;
begin
Field := GetField(Index);
if Field <> nil then
begin
Field^.iLen := Value;
Operation := GetOperation(Index);
if Operation^ <> crAdd then
Operation^ := crMODIFY;
end;
end;
{Purpose: Set method for the FieldName property
Parameters: Index - Index of the Field to modify / Value - New Name of the field
Effects: The field descriptor is modified to reflect the change}
procedure TTableRestructure.SetFieldName(Index: Integer; const Value: string);
var
Field: PFLDDesc;
Operation: PCROpType;
begin
Field := GetField(Index);
if Field <> nil then
begin
StrPCopy(Field^.szName, Value);
Operation := GetOperation(Index);
if Operation^ <> crAdd then
Operation^ := crMODIFY;
end;
end;
{Purpose: Set method for the FieldType property
Parameters: Index - Index of the Field to modify / Value - New Type of the field
Effects: The field descriptor is modified to reflect the change}
procedure TTableRestructure.SetFieldType(Index: Integer; const Value: Word);
var
Field: PFLDDesc;
Operation: PCROpType;
begin
Field := GetField(Index);
if Field <> nil then
begin
Field^.iFldType := Value;
Operation := GetOperation(Index);
if Operation^ <> crAdd then
Operation^ := crMODIFY;
end;
end;
{Purpose: Set method for the FieldUnits property
Parameters: Index - Index of the Field to modify / Value - New units of the field
Effects: The field descriptor is modified to reflect the change}
procedure TTableRestructure.SetFieldUnits(Index: Integer; const Value: Word);
var
Field: PFLDDesc;
Operation: PCROpType;
begin
Field := GetField(Index);
if Field <> nil then
begin
Field^.iUnits1 := Value;
Operation := GetOperation(Index);
if Operation^ <> crAdd then
Operation^ := crMODIFY;
end;
end;
end.
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése