Lucas Steffen
Lucas Steffen

Reputation: 1364

Delphi, pass an array of out parameters

I have a dozens of functions that queries one table, check if it has a record on a gigantic array, updating or inserting as needed.

It looks something like this:

function UpdateTableA;
var
    AFieldA,
    AFieldB,
    (...),
    AFieldZ: TField;
begin
    FSqlQuery.SQL.Text :=
        'select fielda, fieldb, (...), fieldz '+
        'from tablea '+
        'where id in (0, 1, 5, 7, 8, (...))'
    ;
    FClientDataset.Open; // this client is connected to FSqlQuery

    AFieldA := FClientDataset.FieldByName('fielda');
    AFieldB := FClientDataset.FieldByName('fieldb');
    (...)
    AFieldZ := FClientDataset.FieldByName('fieldz');

    for Obj in GLongArray do
    begin
        if FClientDataset.locate('id', Obj.id, []) then
            FClientDataset.Edit
        else
            FClientDataset.Insert;

        AFieldA.AsInteger := Obj.ValueA;
        AFieldB.AsInteger := Obj.ValueB;
        (...)
    end;
end;

Can I create a function in which I pass all the TField variables inside an array and initialize them there?

Something like this: (pseudo code)

function SetTFields(AFields: array of out TField);
begin
    for I := 0 to FClientDataset.Fields.Count-1 do
        AFields[I] := FClientDataset.Fields[I];
end;

and after opening FClientDataset, use it like this:

SetTFields([AFieldA, AFieldB, AFieldC, AFieldD, etc])
or this:
SetTFields([@AFieldA, @AFieldB, @AFieldC, @AFieldD, etc])

If not, is there some similar way to do it that doesn't involve copying a lot of variables?

Upvotes: 1

Views: 134

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598011

You can use something like this:

type
  PField: ^TField;

function SetTFields(AFields: array of PField);
begin
  for I := 0 to FClientDataset.Fields.Count-1 do
    AFields[I]^ := FClientDataset.Fields[I];
end;

function UpdateTableA;
var
  AFieldA,
  AFieldB,
  (...),
  AFieldZ: TField;
begin
  FSqlQuery.SQL.Text := 'select fielda, fieldb, (...), fieldz '+
    'from tablea '+
    'where id in (0, 1, 5, 7, 8, (...))';
  FClientDataset.Open; // this client is connected to FSqlQuery

  SetTFields([@AFieldA, @AFieldB, (...), @AFieldZ]);

  for Obj in GLongArray do
  begin
    if FClientDataset.Locate('id', Obj.id, []) then
      FClientDataset.Edit
    else
      FClientDataset.Insert;

    AFieldA.AsInteger := Obj.ValueA;
    AFieldB.AsInteger := Obj.ValueB;
    (...)
  end;
end;

Or, you can use a dynamic array instead of individual variables, eg:

type
  TFieldArray: array of TField;

function SetTFields(out AFields: TFieldArray);
begin
  SetLength(AFields, FClientDataset.Fields.Count);
  for I := 0 to FClientDataset.Fields.Count-1 do
    AFields[I] := FClientDataset.Fields[I];
end;

function UpdateTableA;
var
  AFields: TFieldArray;
begin
  FSqlQuery.SQL.Text := 'select fielda, fieldb, (...), fieldz '+
    'from tablea '+
    'where id in (0, 1, 5, 7, 8, (...))';
  FClientDataset.Open; // this client is connected to FSqlQuery

  SetTFields(AFields);

  for Obj in GLongArray do
  begin
    if FClientDataset.Locate('id', Obj.id, []) then
      FClientDataset.Edit
    else
      FClientDataset.Insert;

    AFields[0].AsInteger := Obj.ValueA;
    AFields[1].AsInteger := Obj.ValueB;
    (...)
  end;
end;

Upvotes: 4

Related Questions