In my (Delphi Sydney, Win 10) application I use BDE (yes even today). I want to modify its existed (Paradox) tables when I change/alter/drop fields. I found a freeware component (TFieldUpdate v1.1, by Nathanial Woolls) that works except that it can't drop fields and works for a field at a time. So I found here (http://www.delphigroups.info/2/5a/37309.html) another code snipet that hasn't these limitations. I modified it as bellow
procedure RestructureTable;
var
dirP: DBITBLNAME;
hDb: hDbiDb;
rslt: DBIResult;
TblDesc: CRTblDesc;
CProps: CURProps;
PfldDescOldTable, PfldDescNewTable: pFLDDesc;
pOpType, pOpType0: pCROpType;
bdec : TBDECallback;
i: Integer;
s: String;
oldTable : TTable;
const fieldsModified : boolean = FALSE;
fieldsAdded : boolean = FALSE;
fieldsDroped : boolean = FALSE;
function oldFieldFound : integer;
var j : integer;
begin
result := -1;
for j := 0 to T.Fields.Count - 1 do begin
if compareText(PfldDescOldTable^.szName,T.Fields[j].fieldName) = 0
then begin
result := j;
break;
end;
end;
end;
function newFieldFound(s : string) : boolean;
var p: pFLDDesc;
var i : integer;
begin
result := FALSE;
p := PfldDescOldTable;
for i := 0 to TblDesc.iFldCount-1 do begin
if compareText(p^.szName,s) = 0
then begin
result := TRUE;
break;
end;
inc(p);
end;
end;
begin
// Table must not used by other user
s := changeFileExt(T.DatabaseName+'\'+T.TableName,'.lck');
F := TFilestream.Create(s,fmCreate or fmShareExclusive);
oldTable := TTable.Create(nil);
oldTable.DatabaseName := T.DatabaseName;
oldTable.TableName := T.TableName;
oldTable.Open;
Check(DbiGetDirectory(oldTable.DBHandle, False, dirP));
Check(DbiGetCursorProps(oldTable.Handle, CProps));
nFields := CProps.iFields;
if nFields < T.Fields.Count
then nFields := T.Fields.Count;
PfldDescOldTable := allocMem(nFields * sizeof(FLDDesc));
PfldDescNewTable := PfldDescOldTable;
pOpType := allocMem(nFields * sizeof(CROpType));
pOpType0 := pOpType;
try
Check(DbiGetFieldDescs(oldTable.Handle, PfldDescOldTable));
FillChar(TblDesc, sizeof(CRTblDesc), #0);
StrPCopy(TblDesc.szTblName, oldTable.TableName);
StrCopy(TblDesc.szTblType, szParadox);
TblDesc.iFldCount := 0;
FillChar(pOpType^, nFields * sizeof(CROpType), #0);
for i := 1 to CProps.iFields do begin
PfldDescOldTable^.iFldNum := 0;
pOpType^ := crADD;
j := oldFieldFound; // j = field.index (0...)
if j > -1 // if field remains... add it to TblDesc
then begin
Inc(TblDesc.iFldCount);
if PfldDescNewTable <> PfldDescOldTable then
Move(PfldDescOldTable^,PfldDescNewTable^,sizeof(FLDDesc));
if PfldDescNewTable^.iFldType <> FieldTypeToBDEFieldInt(T.Fields[j].DataType)
then begin
PfldDescNewTable^.iFldType := FieldTypeToBDEFieldInt(T.Fields[j].DataType);
fieldsModified := TRUE;
end;
if PfldDescNewTable^.iFldType <> FieldTypeToBDEFieldInt(T.Fields[j].DataType)
then begin
PfldDescNewTable^.iFldType := FieldTypeToBDEFieldInt(T.Fields[j].DataType);
fieldsModified := TRUE;
end;
if PfldDescNewTable^.iUnits1 <> T.Fields[j].Size
then begin
PfldDescNewTable^.iUnits1 := T.Fields[j].Size;
fieldsModified := TRUE;
end;
inc(PfldDescNewTable,1);
end
else fieldsDroped := TRUE; // else drop it
inc(PfldDescOldTable,1);
inc(pOpType,1);
end;
dec(PfldDescOldTable ,CProps.iFields);
// add new fields
for i := 0 to T.Fields.Count-1 do
if T.fields[i].FieldKind = fkData then
begin
if not newFieldFound(T.fields[i].FieldName) then begin // add it to TblDesc
StrCopy(PfldDescNewTable^.szName, pANSIchar(AnsiString(T.fields[i].FieldName)));
PfldDescNewTable^.iFldType := FieldTypeToBDEFieldInt(T.Fields[i].DataType);
PfldDescNewTable^.iUnits1 := T.Fields[i].Size;
Inc(TblDesc.iFldCount);
pOpType^ := crADD;
inc(PfldDescNewTable,1);
inc(pOpType,1);
fieldsAdded := TRUE;
end;
end;
PfldDescNewTable := PfldDescOldTable;
pOpType := pOpType0;
TblDesc.pecrFldOp := pOpType;
TblDesc.pfldDesc := PfldDescNewTable;
oldTable.Close;
if fieldsModified
or fieldsAdded
or fieldsDroped then begin
//bdec := TBDECallback.Create(nil,oldTable.Handle,cbGENPROGRESS,@cbDataBuff, SizeOf(cbDataBuff),ProgressCallback,TRUE) ;
Check(DbiOpenDatabase(nil, nil, dbiReadWrite, dbiOpenExcl, nil, 0,nil, nil, hDb));
Check(DbiSetDirectory(hDb, Dirp));
Check(DbiDoRestructure(hDb, 1, @TblDesc, nil , nil, nil, FALSE));
end;
finally
FreeMem(PfldDescOldTable, (CProps.iFields) * sizeof(FLDDesc));
FreeMem(pOpType, (CProps.iFields ) * sizeof(CROpType));
oldTable.Free;
F.Free;
//bdec.Free;
deleteFile(s);
end;
end;
and it works fine except that it returns the altered table with all records but their fields empty.
I delete all indexes and all non data fields and the problem remains.
Can somebody tell me what i missed, please ?
EDIT
To reproduce the problem :
- Create a new VCL forms application
- Put a TTable component named T and link it to an existing Paradox table
- Put a TDataSource and a TDBGrid linked with table T
- In the fields editor load all fields
- Modify/add/drop some of them
- In the onFormCreate event run the above routine and you will get the restructured table with all fields of all records without value (empty)
EDIT 2 :
```
function FieldTypeToBDEFieldInt(FieldType: TFieldType): Word;
begin
Result := fldUNKNOWN;
case FieldType of
ftUnknown : result := fldUNKNOWN;
ftString : result := fldZSTRING;
ftSmallint : result := fldPDXSHORT;
ftInteger : result := 267; //fldINT16;// I changed it to 267 because this value i see in the table's field descriptor (with fldINT32 = ftLargeInt = 6 I had uncompatibility)
ftWord : result := fldUINT16;
ftBoolean : result := fldBOOL;
ftFloat : result := fldFLOAT;
ftCurrency : result := fldPDXMONEY;
ftBCD : result := fldBCD;
ftDate : result := fldDATE;
ftTime : result := fldTIME;
ftDateTime : result := fldPDXDATETIME;
ftBytes : result := fldBYTES;
ftVarBytes : result := fldVARBYTES;
ftAutoInc : result := fldPDXAUTOINC;
ftBlob : result := fldPDXBINARYBLOB; //fldBLOB;
ftMemo : result := fldPDXMEMO;
ftGraphic : result := fldPDXGRAPHIC;
ftFmtMemo : result := fldPDXFMTMEMO;
ftParadoxOle : result := fldPDXOLEBLOB;
ftTypedBinary : result := fldPDXBINARYBLOB;
ftCursor : result := fldCURSOR;
ftFixedChar : result := fldPDXCHAR;
ftWideString : result := fldZSTRING;
ftLargeInt : result := fldINT32;
ftADT : result := fldADT;
ftArray : result := fldARRAY;
ftReference : result := fldREF;
ftVariant : result := fldUNKNOWN;
end;
end;