Recent

Author Topic: Adding a field to TDbf at runtime  (Read 6593 times)

maurobio

  • Hero Member
  • *****
  • Posts: 623
  • Ecology is everything.
    • GitHub
Adding a field to TDbf at runtime
« on: December 09, 2021, 10:53:38 pm »
Dear ALL,

I have a Dbase file with the following structure:

Quote
Field   Type   Field Size   Decimal
C_REG   C   10   0
N_DISP   N   1   0
N_TIPO   N   2   0
N_ESPE   N   5   0
N_SEXO   N   2   0
C_CAMP   C   16   0
N_PROJ   N   3   0
N_AMBI   N   2   0
D_DETE   C   10   0
N_ENTR   N   1   0
D_ENTR   C   10   0
N_SECO   N   4   0
N_LIQI   N   4   0
N_LAMI   N   4   0
N_TCOL   N   3   0
N_REGI   N   2   0
N_SIGLA   N   2   0
I would like to add a new integer field ('N_NOME') to this file at runtime.

Here is my code (partially adapted from https://forum.lazarus.freepascal.org/index.php?topic=21006.0):

Code: Pascal  [Select][+][-]
  1. program SGCFix;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Classes, SysUtils, Dbf, db, Dbf_Common;
  7.  
  8. var
  9.   ADbf: TDbf;
  10.   //AField: TField;
  11.   AFields: array of TField;
  12.   Temf: TIntegerField;
  13.   i: integer;
  14.  
  15. begin
  16.   ADbf := TDbf.Create(nil);
  17.   ADbf.FilePath := 'data' + DirectorySeparator;
  18.   ADbf.Exclusive := True;
  19.   ADbf.TableName := 'DADOS.dbf';
  20.   ADbf.Open;
  21.   ADbf.Close;
  22.    
  23.   SetLength(AFields, ADbf.FieldDefs.Count);
  24.   for i:=0 to ADbf.FieldDefs.Count - 1 do
  25.         AFields[i] := ADbf.FieldDefs[i].CreateField(ADbf);
  26.   Temf := TIntegerField.Create(nil);
  27.   Temf.FieldKind := fkCalculated;
  28.   Temf.FieldName := 'N_NOME';
  29.   Temf.DataSet := ADbf;
  30.   ADbf.Open;
  31.   ADbf.Edit;
  32.   ADbf.Post;
  33.   for i := Low(AFields) to High(AFields) do
  34.         AFields[i].Free;
  35.   SetLength(AFields, 0);
  36.   Temf.Free;
  37.   ADbf.Close;
  38.  
  39.   WriteLn('-- done -- ');      
  40. end.
  41.  
  42.  

It compiles without errors, but it does nothing: the new field is not added and the file is not modified.

Could anyone out there give a hand?

Thanks in advance!

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Delphi 7.0 Personal Edition
Lazarus 2.0.12 - FPC 3.2.0 on GNU/Linux Mint 19.1, Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

korba812

  • Sr. Member
  • ****
  • Posts: 396
Re: Adding a field to TDbf at runtime
« Reply #1 on: December 10, 2021, 12:05:24 am »
Do you want to change dbf file structure or add a calculated field? The post you are referring to is for a calculated field.
If you want to change dbf file structure then use TDbf.RestructureTable method. Here's an example (it is about deleting a field, but it should be helpful):
https://forum.lazarus.freepascal.org/index.php?topic=8567.0

maurobio

  • Hero Member
  • *****
  • Posts: 623
  • Ecology is everything.
    • GitHub
Re: Adding a field to TDbf at runtime
« Reply #2 on: December 10, 2021, 12:36:06 am »
Hi, @korba512!

Thanks a lot for your reply! I rewrote my code according to the example you pointed out:

Code: Pascal  [Select][+][-]
  1. program SGCFix;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Classes, SysUtils, Dbf, db, Dbf_Common;
  7.  
  8. var
  9.   SGCDbf: TDbf;
  10.   FieldDefs: TDbfFieldDefs;
  11.  
  12. begin
  13.   SGCDbf := TDbf.Create(nil);
  14.   SGCDbf.FilePath := 'data' + DirectorySeparator;
  15.   SGCDbf.Exclusive := True;
  16.   SGCDbf.TableName := 'DADOS.dbf';
  17.   SGCDbf.Open;
  18.   FieldDefs := TDbfFieldDefs.Create(nil);
  19.   FieldDefs.Assign(SGCDbf.DbfFieldDefs);
  20.   FieldDefs.Close;
  21.   FieldDefs.Add('N_NOME', ftInteger, 0, True);
  22.   SGCDbf.RestructureTable(FieldDefs, False);  
  23.   SGCDbf.Close;
  24.   SGCDbf.Free;
  25.   FieldDefs.Free;
  26.   WriteLn('-- done -- ');      
  27. end.
  28.  

... but it still does not work. Now, the compiler returns several error messages, apparently related to the TDbfFieldDefs type which seems not to be recognized:

Quote
Free Pascal Compiler version 3.2.0 [2021/02/21] for i386
Copyright (c) 1993-2020 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling SGCfix.lpr
SGCfix.lpr(10,14) Error: Identifier not found "TDbfFieldDefs"
SGCfix.lpr(10,27) Error: Error in type definition
SGCfix.lpr(18,16) Error: Identifier not found "TDbfFieldDefs"
SGCfix.lpr(19,13) Error: Illegal qualifier
SGCfix.lpr(20,13) Error: Illegal qualifier
SGCfix.lpr(21,13) Error: Illegal qualifier
SGCfix.lpr(22,36) Error: Incompatible type for arg no. 1: Got "<erroneous type>", expected "TDbfFieldDefs"
SGCfix.lpr(25,13) Error: Illegal qualifier
SGCfix.lpr(29) Fatal: There were 8 errors compiling module, stopping
Fatal: Compilation aborted
Error: C:\lazarus\fpc\3.2.0\bin\i386-win32\ppc386.exe returned an error exitcode

Any hints?

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Delphi 7.0 Personal Edition
Lazarus 2.0.12 - FPC 3.2.0 on GNU/Linux Mint 19.1, Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

wp

  • Hero Member
  • *****
  • Posts: 11923
Re: Adding a field to TDbf at runtime
« Reply #3 on: December 10, 2021, 12:45:58 am »
If you want to add a calculated field you must provide a handler for the Dataset's OnCalcFields event which has the purpose the calculate the value(s) for the calculated field(s). Note that the "normal" fields are not accessible here, only those that you recreated yourself for the AFields array.

The attached sample contains two "regular" fields, "A" and "B". At runtime a third field "C" is created as calculated field which calculates the sum of A and B.
« Last Edit: December 10, 2021, 12:51:01 am by wp »

maurobio

  • Hero Member
  • *****
  • Posts: 623
  • Ecology is everything.
    • GitHub
Re: Adding a field to TDbf at runtime
« Reply #4 on: December 10, 2021, 01:04:26 am »
Hi, @wp!

Thanks for your reply. In fact, I do not want a 'calculated field' - this was mistakenly taken from an example I found here on the forum. I just want to add a field at runtime.

The example pointed out by @korba512 seems to be similar to what I need, but as I wrote in my previous reply, I got compiler errors because of a seemingly unrecognized type.

With best wishes,
« Last Edit: December 10, 2021, 12:51:25 pm by maurobio »
UCSD Pascal / Burroughs 6700 / Master Control Program
Delphi 7.0 Personal Edition
Lazarus 2.0.12 - FPC 3.2.0 on GNU/Linux Mint 19.1, Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

Handoko

  • Hero Member
  • *****
  • Posts: 5158
  • My goal: build my own game engine using Lazarus
Re: Adding a field to TDbf at runtime
« Reply #5 on: December 10, 2021, 03:19:30 am »
Maybe:

Code: Pascal  [Select][+][-]
  1. program Test;
  2.  
  3. uses
  4.   Classes, SysUtils, Dbf, db, dbf_fields;
  5.  
  6. var
  7.   SGCDbf: Tdbf;
  8.   FieldDefs: TDbfFieldDefs;
  9.   NewFieldDef: TDbfFieldDef;
  10.  
  11. begin
  12.   SGCDbf := TDbf.Create(nil);
  13.   SGCDbf.FilePath := 'data' + DirectorySeparator;
  14.   SGCDbf.Exclusive := True;
  15.   SGCDbf.TableName := 'DADOS.dbf';
  16.   SGCDbf.Open;
  17.   FieldDefs := TDbfFieldDefs.Create(nil);
  18.   FieldDefs.Assign(SGCDbf.DbfFieldDefs);
  19.   NewFieldDef := FieldDefs.AddFieldDef;
  20.   NewFieldDef.FieldName := 'N_NOME';
  21.   NewFieldDef.FieldType := ftInteger;
  22.   NewFieldDef.Required := True;
  23.   SGCDbf.RestructureTable(FieldDefs, True);
  24.   FieldDefs.Free;
  25.   SGCDbf.Close;
  26.   SGCDbf.Free
  27.  end.
« Last Edit: December 10, 2021, 03:36:54 am by Handoko »

maurobio

  • Hero Member
  • *****
  • Posts: 623
  • Ecology is everything.
    • GitHub
Re: Adding a field to TDbf at runtime
« Reply #6 on: December 10, 2021, 12:58:02 pm »
Hi, @Handoku!

Thanks a lot, not only for your reply, but for your post at another thread (https://forum.lazarus.freepascal.org/index.php/topic,8567.0.html), which has been pointed out to me by @korba512 and that effectively provided a working solution to my problem.

I was sure that some unit was missing where TDbfFieldDefs was declared, but I could not find out which one. The TDbf tutorial does not mention the dbf_fields unit in the section "What to put in in your uses section"(https://wiki.lazarus.freepascal.org/Lazarus_Tdbf_Tutorial#What_to_put_in_your_uses_section) and so I got lost.

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Delphi 7.0 Personal Edition
Lazarus 2.0.12 - FPC 3.2.0 on GNU/Linux Mint 19.1, Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

Handoko

  • Hero Member
  • *****
  • Posts: 5158
  • My goal: build my own game engine using Lazarus
Re: Adding a field to TDbf at runtime
« Reply #7 on: December 10, 2021, 04:19:24 pm »

 

TinyPortal © 2005-2018