Board index » delphi » DbiDoRestructure to modify more than one field at a time (Part One)

DbiDoRestructure to modify more than one field at a time (Part One)

Taken from this web page:
"http://www.borland.com/devsupport/bde/bdeapiex/dbidorestructure.html"
is the following DbiDoRestructure example: (works perfectly on one field)
procedure ChangeField(Table: TTable; Field: TField; Rec: ChangeRec);
var
  Props: CURProps;
  hDb: hDBIDb;
  TableDesc: CRTblDesc;
  pFields: pFLDDesc;
  pOp: pCROpType;
  B: byte;

begin
  // Initialize the pointers...
  pFields := nil; pOp := nil;
  // Make sure the table is open exclusively so we can get the db handle...
  if Table.Active = False then
    raise EDatabaseError.Create('Table must be opened to restructure');
  if Table.Exclusive = False then
    raise EDatabaseError.Create('Table must be opened exclusively to
restructure');

  Check(DbiSetProp(hDBIObj(Table.Handle), curxltMODE, integer(xltNONE)));
  // Get the table properties to determine table type...
  Check(DbiGetCursorProps(Table.Handle, Props));
  // Make sure the table is either Paradox or dBASE...
  if (Props.szTableType <> szPARADOX) and (Props.szTableType <> szDBASE)
then
    raise EDatabaseError.Create('Field altering can only occur on Paradox' +
                ' or dBASE tables');
  // Allocate memory for the field descriptor...
  pFields := AllocMem(Table.FieldCount * sizeof(FLDDesc));
  // Allocate memory for the operation descriptor...
  pOp := AllocMem(Table.FieldCount * sizeof(CROpType));
  try
    // Set the pointer to the index in the operation descriptor to put
    // crMODIFY (This means a modification to the record is going to
happen)...
    Inc(pOp, Field.Index);
    pOp^ := crMODIFY;
    Dec(pOp, Field.Index);
    // Fill the field descriptor with the existing field information...
    Check(DbiGetFieldDescs(Table.Handle, pFields));
    // Set the pointer to the index in the field descriptor to make the
    // midifications to the field
    Inc(pFields, Field.Index);

    // If the szName portion of the ChangeRec has something in it, change
it...
    if StrLen(Rec.szName) > 0 then
      pFields^.szName := Rec.szName;
    // If the iType portion of the ChangeRec has something in it, change
it...
    if Rec.iType > 0 then
      pFields^.iFldType := Rec.iType;
    // If the iSubType portion of the ChangeRec has something in it, change
it...
    if Rec.iSubType > 0 then
      pFields^.iSubType := Rec.iSubType;
    // If the iLength portion of the ChangeRec has something in it, change
it...
    if Rec.iLength > 0 then
      pFields^.iUnits1 := Rec.iLength;
    // If the iPrecision portion of the ChangeRec has something in it,
change it...
    if Rec.iPrecision > 0 then
      pFields^.iUnits2 := Rec.iPrecision;
    Dec(pFields, Field.Index);

    for B := 1 to Table.FieldCount do begin
      pFields^.iFldNum := B;
      Inc(pFields, 1);
    end;
    Dec(pFields, Table.FieldCount);

    // Blank out the structure...
    FillChar(TableDesc, sizeof(TableDesc), 0);
    //  Get the database handle from the table's cursor handle...
    Check(DbiGetObjFromObj(hDBIObj(Table.Handle), objDATABASE,
hDBIObj(hDb)));
    // Put the table name in the table descriptor...
    StrPCopy(TableDesc.szTblName, Table.TableName);
    // Put the table type in the table descriptor...
    StrPCopy(TableDesc.szTblType, Props.szTableType);
    // The following three lines are necessary when doing any field
restructure
    // operations on a table...

    // Set the field count for the table
    TableDesc.iFldCount := Table.FieldCount;
    // Link the operation descriptor to the table descriptor...
    TableDesc.pecrFldOp := pOp;
    // Link the field descriptor to the table descriptor...
    TableDesc.pFldDesc := pFields;
    // Close the table so the restructure can complete...
    Table.Close;
    // Call DbiDoRestructure...
    Check(DbiDoRestructure(hDb, 1, @TableDesc, nil, nil, nil, FALSE));
  finally
    if pFields <> nil then
      FreeMem(pFields);
    if pOp <> nil then
      FreeMem(pOp);
  end;
end;

 

Re:DbiDoRestructure to modify more than one field at a time (Part One)


Part Two:

What I am trying to do is modify this procedure to change more than one
field at a time

Below is my attempt.  What happen is that the *last* field I pass into the
Field Descriptor gets modified, but the earlier ones do not.  I have wrapped
this into a component, so I will include the button proc that calls the
component.

procedure TForm2.SpeedButton3Click(Sender: TObject);
var
  chngrec1, chngrec2:tChangeInfo;
begin
table3.open;
chngrec1 := tChangeInfo.create;
chngrec1.iType := bde.fldINT32;
Restruct.addModifyField('DistributorID',chngrec1);

chngrec2 := tChangeInfo.create;
chngrec2.iType := bde.fldINT32;
Restruct.addModifyField('EndUserID',chngrec2);

restruct.ChangeFields;

table3.open;

end;

****************************

procedure tRestructionator.ChangeFields;//(Table: TTable; Field: TField;
Rec: ChangeRec);
var
  Props: CURProps;
  hDb: hDBIDb;
  TableDesc: CRTblDesc;
  pFields: pFLDDesc;
  pOp: pCROpType;
  B: byte;
  i : integer;
  Field : tField;
  ChangeRec : tChangeInfo;
begin
  // Initialize the pointers...
  pFields := nil; pOp := nil;
  // Make sure the table is open exclusively so we can get the db handle...
  if fModifyTable.Active = False then
    raise EDatabaseError.Create('Table must be opened to restructure');
  if fModifyTable.Exclusive = False then
    raise EDatabaseError.Create('Table must be opened exclusively to
restructure');

  Check(DbiSetProp(hDBIObj(fModifyTable.Handle), curxltMODE,
integer(xltNONE)));
  // Get the table properties to determine table type...
  Check(DbiGetCursorProps(fModifyTable.Handle, Props));
  // Make sure the table is either Paradox or dBASE...
  if (Props.szTableType <> szPARADOX) and (Props.szTableType <> szDBASE)
then
    raise EDatabaseError.Create('Field altering can only occur on Paradox' +
                ' or dBASE tables');
  // Allocate memory for the field descriptor...
  pFields := AllocMem(fModifyTable.FieldCount * sizeof(FLDDesc));
  // Allocate memory for the operation descriptor...
  pOp := AllocMem(fModifyTable.FieldCount * sizeof(CROpType));

  try
      for i := 0 to fModifyFields.Count - 1 do
      begin
      ChangeRec := tChangeInfo(fModifyFields.objects[i]);
        try
          Field := fModifyTable.fieldByName(fModifyFields[i]);
        except on e: exception do
          begin
          // got the field name wrong?
          showmessage('Error in FieldByName: '+e.Message);
          continue;
          end;
        end;
      // Set the pointer to the index in the operation descriptor to put
      // crMODIFY (This means a modification to the record is going to
happen)...
      Inc(pOp, Field.Index);
      pOp^ := crMODIFY;
      Dec(pOp, Field.Index);
      // Fill the field descriptor with the existing field information...
      Check(DbiGetFieldDescs(fModifyTable.Handle, pFields));
      // Set the pointer to the index in the field descriptor to make the
      // modifications to the field
      Inc(pFields, Field.Index);

      // If the szName portion of the ChangeRec has something in it, change
it...
      if StrLen(ChangeRec.szName) > 0 then
        pFields^.szName := ChangeRec.szName;
      // If the iType portion of the ChangeRec has something in it, change
it...
      if ChangeRec.iType > 0 then
        pFields^.iFldType := ChangeRec.iType;
      // If the iSubType portion of the ChangeRec has something in it,
change it...
      if ChangeRec.iSubType > 0 then
        pFields^.iSubType := ChangeRec.iSubType;
      // If the iLength portion of the ChangeRec has something in it, change
it...
      if ChangeRec.iLength > 0 then
        pFields^.iUnits1 := ChangeRec.iLength;
      // If the iPrecision portion of the ChangeRec has something in it,
change it...
      if ChangeRec.iPrecision > 0 then
        pFields^.iUnits2 := ChangeRec.iPrecision;
      Dec(pFields, Field.Index);
      end;//for loop

    for B := 1 to fModifyTable.FieldCount do begin
      pFields^.iFldNum := B;
      Inc(pFields, 1);
    end;
    Dec(pFields, fModifyTable.FieldCount);

    // Blank out the structure...
    FillChar(TableDesc, sizeof(TableDesc), 0);
    // Get the database handle from the table's cursor handle...
    Check(DbiGetObjFromObj(hDBIObj(fModifyTable.Handle),
                           objDATABASE, hDBIObj(hDb)));
    // Put the table name in the table descriptor...
    StrPCopy(TableDesc.szTblName, fModifyTable.TableName);
    // Put the table type in the table descriptor...
    StrPCopy(TableDesc.szTblType, Props.szTableType);
    // The following three lines are necessary when doing any field
restructure
    // operations on a table...
    // Set the field count for the table
    TableDesc.iFldCount := fModifyTable.FieldCount;
    // Link the operation descriptor to the table descriptor...
    TableDesc.pecrFldOp := pOp;
    // Link the field descriptor to the table descriptor...
    TableDesc.pFldDesc := pFields;

    // Close the table so the restructure can complete...
    fModifyTable.Close;
    // Call DbiDoRestructure...
    Check(DbiDoRestructure(hDb, 1, @TableDesc, 'TestChanged'{nil}, nil, nil,
FALSE));
  finally
    if pFields <> nil then
      FreeMem(pFields);
    if pOp <> nil then
      FreeMem(pOp);
  end;
end;

Other Threads