Exception by insert/append records "column 'xxx' specified more than once'"

Discussion of open issues, suggestions and bugs regarding PgDAC (PostgreSQL Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
Goodwin
Posts: 5
Joined: Thu 16 Feb 2012 08:34

Exception by insert/append records "column 'xxx' specified more than once'"

Post by Goodwin » Fri 29 Jun 2012 08:53

Hello, we found this error in the components, version 3.1.5.0. It can be reproduced by following steps:
1. create table where are some blob and non-blob fields
2. open table with the table component, let say table is named 'Usedtablename'
3. call on the connection the statement 'delete from Usedtablename'
4. call on the component the function 'refresh'
5. call on the component the function append or insert
6. define the field values
7. call post
8. the exception from the subject appears.

The error is in the unit DBAccess, in the method TCustomDADataSet.GetCurrentKeys. The part in the section where keyFieldCount = 0 is wrong, there should be performed a local modification of the field list (to throw away of the blob and object fields), but it modifies the whole field definition cache... We have fixed it by following code:

Code: Select all

procedure TCustomDADataSet.GetCurrentKeys(out KeyFields: TFieldArray; out Values: variant);
var
  KeyFieldDescs, DataFieldDescs 
  (* start of modifications for the fix *)
  , LoadedDataFieldDescs
  (* end of modifications for the fix *)
  : TFieldDescArray;
  KeyFieldsCount, DataFieldsCount: integer;
  i, j: integer;
  RecBuf: TRecordBuffer;
  TmpVar: variant;
  Delta: integer;
  EmptyRecBuf: boolean;
begin
  DataFieldDescs := nil;

  Assert(FDataSetService <> nil);
  FDataSetService.GetKeyFieldDescs(KeyFieldDescs);
  KeyFieldsCount := Length(KeyFieldDescs);
  SetLength(KeyFields, KeyFieldsCount);
  Values := Unassigned;

  EmptyRecBuf := not GetActiveRecBuf(RecBuf);

  if KeyFieldsCount = 1 then begin
    KeyFields[0] := GetField(KeyFieldDescs[0]);
    if not EmptyRecBuf then
      Data.GetFieldAsVariant(KeyFieldDescs[0].FieldNo, RecBuf, Values);
  end
  else
  if KeyFieldsCount > 1 then begin
    Values := VarArrayCreate([0, KeyFieldsCount - 1], varVariant);
    for i := 0 to KeyFieldsCount - 1 do begin
      KeyFields[i] := GetField(KeyFieldDescs[i]);
      Values[i] := Unassigned;
      if not EmptyRecBuf then begin
        Data.GetFieldAsVariant(KeyFieldDescs[i].FieldNo, RecBuf, TmpVar);
        Values[i] := TmpVar;
      end;
    end;
  end
  else begin
    (* Start of modifications for fix *)
    FDataSetService.GetDataFieldDescs(LoadedDataFieldDescs);
    DataFieldsCount := Length(LoadedDataFieldDescs);

    (* The dataFieldDesc array was originally returned only 
     * as a pointer to the global storage
     * That's why the modification of the array bellow caused problems ...
     * The obtained array is copied before modifying the array content now  
     *)
    SetLength(DataFieldDescs, DataFieldsCount);
    for I := 0 to DataFieldsCount - 1 do begin
      DataFieldDescs[i] := LoadedDataFieldDescs[i];
    end;

    (* End of modification for fix *)

    if DataFieldsCount > 0 then begin
      Delta := 0;
      Assert(FDataSetService.FSQLGenerator <> nil);
      for i := DataFieldsCount - 1 downto 0 do
        if FDataSetService.FSQLGenerator.IsBlobDataType(DataFieldDescs[i].DataType) or
          FDataSetService.FSQLGenerator.IsObjectDataType(DataFieldDescs[i].DataType) //TODO:
        then begin
          Inc(Delta);
          for j := i to DataFieldsCount - Delta - 1 do
            DataFieldDescs[j] := DataFieldDescs[j + 1];
        end;
      SetLength(KeyFields, DataFieldsCount - Delta);
      Values := VarArrayCreate([0, DataFieldsCount - Delta - 1], varVariant);
      for i := 0 to DataFieldsCount - Delta - 1 do begin
        KeyFields[i] := GetField(DataFieldDescs[i]);
      {$IFNDEF CLR}
        Values[i] := Unassigned;
      {$ENDIF}
        if not EmptyRecBuf then begin
          Data.GetFieldAsVariant(DataFieldDescs[i].FieldNo, RecBuf, TmpVar);
          Values[i] := TmpVar;
        end;
      end;
    end;
  end;
end;

AlexP
Devart Team
Posts: 5530
Joined: Tue 10 Aug 2010 11:35

Re: Exception by insert/append records "column 'xxx' specified more than once'"

Post by AlexP » Mon 02 Jul 2012 09:29

hello,

We cannot reproduce the problem you have described after performing the given steps. Please send us the script for creating and filling the tables, and the piece of Delphi code reproducing the problem. In addition, try to reproduce the problem on the latest PgDAC version 3.2.7.

Post Reply