#1  
Old 2nd April 2020, 12:56 AM
magosk magosk is offline
Member
 
Join Date: Nov 2010
Posts: 31
Default Getting Access Violation with 4.5017+

Hi. I am working on migrating our applications from Delphi XE7 to 10.3.3, and as a part of that project I am also upgrading our third party libraries. When testing one of our (real-world) migrated applications I encountered a reproducible access violation in connection to database code. After ruling out that the problem was related to 10.3.3 (by compiling it in XE7 with the same new packages and getting the same error), I turned my attention against NexusDB which is the database we use. Previously we had NexusDB 4.1302 in production, and I upgraded to 4.5018 when starting the migration project. First I checked with your latest release 4.5020 but still had the same error. Then I saw that there was a breaking change in 4.5017 regarding string fields. My next step was to try with 4.5016 and alas, now the error was gone in both XE7 and 10.3.3. I would like to ask for help if I can adapt our code to work with the latest version, or possibly to verify that there is a bug in the latest version(s). The code involved (which I have not written myself) looks like this:

Code:
procedure SetCDSFields(CDS: TClientDataSet; FieldInfos: Array of TFieldInfo);

  procedure AddField(I: TFieldInfo);
  var
    F: TField;
  begin
    F := I.FieldClass.Create(CDS);
    F.FieldName := I.FieldName;
    F.Name := CDS.Name + I.FieldName;
    F.Size := I.Size;
    F.FieldKind := I.FieldKind;
    F.Index := CDS.FieldCount;
    F.DataSet := CDS;
  end;

var
  FieldInfo: TFieldInfo;
begin
  if CDS.Active then
  begin
    CDS.EmptyDataSet;
    CDS.Close;
    CDS.FieldDefs.Clear;
    CDS.Fields.Clear;
  end;

  for FieldInfo in FieldInfos do
    AddField(FieldInfo);
  CDS.CreateDataSet;
end;

procedure SetCDSFields(CDS: TClientDataSet; SourceDS: TDataSet);
var
  i: Integer;
  FieldInfos: TArray<TFieldInfo>;
begin
  SetLength(FieldInfos, SourceDS.FieldDefs.Count);
  for i := 0 to SourceDS.FieldDefs.Count - 1 do
    FieldInfos[i] := FieldInfo(
      SourceDS.FieldDefs[i].FieldClass,
      SourceDS.Fields[i].FieldName,
      SourceDS.Fields[i].Size,
      fkData);
  SetCDSFields(CDS, FieldInfos);
end;

    procedure TransferDataFromQueryToTempCDS(Query: TnxQuery; 
      TempCDS: TClientDataSet);
    var
      i: Integer;
    begin
      SetCDSFields(TempCDS, Query);
      Query.First;
      while not Query.Eof do
      begin
        TempCDS.Append;
        for i := 0 to Query.Fields.Count-1 do
          TempCDS.Fields[i].Value := Query.Fields[i].Value;
        TempCDS.Post;
        CalloutFlagFieldManager.AddFlags(TempCDS['CalloutID'], 
           TempCDS['CalloutElementID']);
        Query.Next;
      end;
    end;
The AV comes when you execute CDS.CreateDataSet (as a result of calling SetCDSFields(TempCDS, Query) in the TransferDataFromQueryToTempCDS method).

Feedback on this would be much appreciated. A temporary workaround would of course be to run with 4.5016, but that is not a very good solution for the future.

Best regards

Magnus Oskarsson
  #2  
Old 2nd April 2020, 01:34 AM
Thorsten Engler [NDA]
 
Posts: n/a
Default Re: Getting Access Violation with 4.5017+

Hi,

Could you please provide a standalone testcase that demonstrates the problem so
I can analyse it under the debugger?

Cheers,
Thorsten

magosk wrote:

>
> Hi. I am working on migrating our applications from Delphi XE7 to
> 10.3.3, and as a part of that project I am also upgrading our third
> party libraries. When testing one of our (real-world) migrated
> applications I encountered a reproducible access violation in connection
> to database code. After ruling out that the problem was related to
> 10.3.3 (by compiling it in XE7 with the same new packages and getting
> the same error), I turned my attention against NexusDB which is the
> database we use. Previously we had NexusDB 4.1302 in production, and I
> upgraded to 4.5018 when starting the migration project. First I checked
> with your latest release 4.5020 but still had the same error. Then I saw
> that there was a breaking change in 4.5017 regarding string fields. My
> next step was to try with 4.5016 and alas, now the error was gone in
> both XE7 and 10.3.3. I would like to ask for help if I can adapt our
> code to work with the latest version, or possibly to verify that there
> is a bug in the latest version(s). The code involved (which I have not
> written myself) looks like this:
>
>
> Code:
> --------------------
>
> procedure SetCDSFields(CDS: TClientDataSet; FieldInfos: Array of
> TFieldInfo);
> procedure AddField(I: TFieldInfo);
> var
> F: TField;
> begin
> F := I.FieldClass.Create(CDS);
> F.FieldName := I.FieldName;
> F.Name := CDS.Name + I.FieldName;
> F.Size := I.Size;
> F.FieldKind := I.FieldKind;
> F.Index := CDS.FieldCount;
> F.DataSet := CDS;
> end;
>
> var
> FieldInfo: TFieldInfo;
> begin
> if CDS.Active then
> begin
> CDS.EmptyDataSet;
> CDS.Close;
> CDS.FieldDefs.Clear;
> CDS.Fields.Clear;
> end;
>
> for FieldInfo in FieldInfos do
> AddField(FieldInfo);
> CDS.CreateDataSet;
> end;
>
> procedure SetCDSFields(CDS: TClientDataSet; SourceDS: TDataSet);
> var
> i: Integer;
> FieldInfos: TArray<TFieldInfo>;
> begin
> SetLength(FieldInfos, SourceDS.FieldDefs.Count);
> for i := 0 to SourceDS.FieldDefs.Count - 1 do
> FieldInfos[i] := FieldInfo(
> SourceDS.FieldDefs[i].FieldClass,
> SourceDS.Fields[i].FieldName,
> SourceDS.Fields[i].Size,
> fkData);
> SetCDSFields(CDS, FieldInfos);
> end;
>
> procedure TransferDataFromQueryToTempCDS(Query: TnxQuery;
> TempCDS: TClientDataSet);
> var
> i: Integer;
> begin
> SetCDSFields(TempCDS, Query);
> Query.First;
> while not Query.Eof do
> begin
> TempCDS.Append;
> for i := 0 to Query.Fields.Count-1 do
> TempCDS.Fields[i].Value := Query.Fields[i].Value;
> TempCDS.Post;
> CalloutFlagFieldManager.AddFlags(TempCDS['CalloutID'],
> TempCDS['CalloutElementID']);
> Query.Next;
> end;
> end;
>
> --------------------
>
>
> The AV comes when you execute CDS.CreateDataSet (as a result of calling
> SetCDSFields(TempCDS, Query) in the TransferDataFromQueryToTempCDS
> method).
>
> Feedback on this would be much appreciated. A temporary workaround would
> of course be to run with 4.5016, but that is not a very good solution
> for the future.
>
> Best regards
>
> Magnus Oskarsson


  #3  
Old 2nd April 2020, 05:47 PM
magosk magosk is offline
Member
 
Join Date: Nov 2010
Posts: 31
Default

Quote:
Originally Posted by Thorsten Engler [NDA] View Post
Hi,

Could you please provide a standalone testcase that demonstrates the problem so
I can analyse it under the debugger?

Cheers,
Thorsten
Thanks for the reply Thorsten, I will try to squeeze in some time to do that and get back to you. I just wanted to check first if you saw something obvious in our code that needed change.

/Magnus
  #4  
Old 4th April 2020, 01:53 AM
magosk magosk is offline
Member
 
Join Date: Nov 2010
Posts: 31
Default

Hi again, just wanted to tell you that I have been busy with other things but have made an attempt now to extract some of the code from the real-world application and create a small self-contained test case. So far I cannot reproduce the error using a simple test table. I will have to dig into it a bit deeper to see if I can duplicate the problem, but will likely not have time for that until next week.

/Magnus
  #5  
Old 7th April 2020, 01:53 AM
magosk magosk is offline
Member
 
Join Date: Nov 2010
Posts: 31
Default Problem replicated

Hi again. Now I have finally triggered an access violation in the test program. I started to add more and more fields into a table corresponding to the fields in the rel-world application query. After adding a second string field I get the error. But it is a bit strange: if I remove some of the other fields I do not get the error. Anyway, now you can check this in the debugger. It has possibly something to do with

nxdb.TnxStringField.Bind

I see that method both in the Call Stack window in Delphi and in the call stack dump from the real world application (although they do not look entirely identical). I attach the test project. Hope this helps you locate the problem and find a fix/workaround.

Best regards

Magnus Oskarsson
Attached Files
File Type: zip nxQueryToCDSTest.zip (7.0 KB, 3 views)
  #6  
Old 7th April 2020, 02:22 AM
Thorsten Engler [NDA]
 
Posts: n/a
Default Re: Getting Access Violation with 4.5017+

Your code is adding a TnxStringField field object to a TClientDataSet.

Don't do that. You can't just add classed of field types from one class of
TDataSet to a totally different class of TDataSet.


magosk wrote:

>
> Hi again. Now I have finally triggered an access violation in the test
> program. I started to add more and more fields into a table
> corresponding to the fields in the rel-world application query. After
> adding a second string field I get the error. But it is a bit strange:
> if I remove some of the other fields I do not get the error. Anyway, now
> you can check this in the debugger. It has possibly something to do with
>
>
> nxdb.TnxStringField.Bind
>
> I see that method both in the Call Stack window in Delphi and in the
> call stack dump from the real world application (although they do not
> look entirely identical). I attach the test project. Hope this helps you
> locate the problem and find a fix/workaround.
>
> Best regards
>
> Magnus Oskarsson
>
>
> +-------------------------------------------------------------------+
> > Filename: nxQueryToCDSTest.zip |
> > Download: http://www.nexusdb.com/forums/attachment.php?attachmentid=1990|

> +-------------------------------------------------------------------+


  #7  
Old 7th April 2020, 06:06 PM
magosk magosk is offline
Member
 
Join Date: Nov 2010
Posts: 31
Default

Quote:
Originally Posted by Thorsten Engler [NDA] View Post
Your code is adding a TnxStringField field object to a TClientDataSet.

Don't do that. You can't just add classed of field types from one class of
TDataSet to a totally different class of TDataSet.
Thanks for the feedback Thorsten. As said I was not really familiar with this code to begin with, but what you say makes sense. The reason this worked before is that you before 4.5017 used the standard Delphi field component types in NexusDB for the field types that were involved here, am I right? This also leads to another question.

We actually have a nxDBClientMethods unit as well with some methods designed to work with combinations of NexusDB data sets and client data sets. To migrate this code (without totally refactoring it) I could write a nxSetCDSFields method that has knowledge of NexusDB specific types. Besides TnxStringField <-> TStringField, are there any other NexusDB specific field classes I need to be aware of?

Best regards

Magnus Oskarsson
  #8  
Old 7th April 2020, 06:39 PM
Thorsten Engler [NDA]
 
Posts: n/a
Default Re: Getting Access Violation with 4.5017+

magosk wrote:

> Thanks for the feedback Thorsten. As said I was not really familiar with
> this code to begin with, but what you say makes sense. The reason this
> worked before is that you before 4.5017 used the standard Delphi field
> component types in NexusDB for the field types that were involved here,
> am I right?

That's correct. But there were already NexusDB specific field classes in use
for other field types before, so you had a chance to hit this issue already.


> We actually have a nxDBClientMethods unit as well with some methods
> designed to work with combinations of NexusDB data sets and client data
> sets. To migrate this code (without totally refactoring it) I could
> write a nxSetCDSFields method that has knowledge of NexusDB specific
> types. Besides TnxStringField <-> TStringField, are there any other
> NexusDB specific field classes I need to be aware of?


You should be asking your dataset what field class it wants for a specific
field type:

function TDataset.GetFieldClass(FieldType: TFieldType): TFieldClass;

  #9  
Old 7th April 2020, 10:22 PM
magosk magosk is offline
Member
 
Join Date: Nov 2010
Posts: 31
Default

Thanks Thorsten, this is good input for a more general approach that requires no knowledge of NexusDB, although the GetFieldClass method is a protected member of TDataSet (and is not overridden or made public for TClientDataSet). But I checked its implementation and it simply uses the DefaultFieldClasses mapping between TFieldType and TFieldClass. So I changed our code like this:

Code:
procedure SetCDSFields(CDS: TClientDataSet; SourceDS: TDataSet);
var
  i: Integer;
  FieldInfos: TArray<TFieldInfo>;
begin
  SetLength(FieldInfos, SourceDS.FieldDefs.Count);
  for i := 0 to SourceDS.FieldDefs.Count - 1 do
    FieldInfos[i] := FieldInfo(
      DefaultFieldClasses[SourceDS.FieldDefs[i].DataType],
      SourceDS.FieldDefs[i].Name,
      SourceDS.FieldDefs[i].Size,
      fkData);
  SetCDSFields(CDS, FieldInfos);
end;
There are probably more things you can do about this code, e.g. is the own-defined type TFieldInfo really needed? But I want to touch as little as possible at this point of my migration project (which affects very many applications). Unless you have some objection to what I write here, I am considering this case closed. Thanks again for your support on this.

Best regards

Magnus Oskarsson
  #10  
Old 7th April 2020, 10:35 PM
Thorsten Engler [NDA]
 
Posts: n/a
Default Re: Getting Access Violation with 4.5017+

magosk wrote:

> Thanks Thorsten, this is good input for a more general approach that
> requires no knowledge of NexusDB, although the GetFieldClass method is a
> protected member of TDataSet (and is not overridden or made public for
> TClientDataSet). But I checked its implementation and it simply uses the
> DefaultFieldClasses mapping between TFieldType and TFieldClass.


That is incorrect. The implementation in TDataSet does that, yes. But it's a
virtual method and derived dataset classes can and will override the method to
do something else.

What you can do is:

type
TDataSetHacker = class(TDataSet);

....
var
CDS: TClientDataSet;
begin
....
x := TDataSetHacker(CDS).GetFieldClass(FieldType);


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Access Violation David Rose nexusdb.public.support 16 25th November 2016 02:00 AM
Access Violation in EM David Rose nexusdb.public.support 5 6th March 2015 12:20 AM
Access Violation David Rose nexusdb.public.support 2 12th February 2015 10:15 PM
Access Violation Wolfgang nexusdb.public.support 8 5th June 2012 04:59 PM
v2.02 Access Violation David Charron nexusdb.public.support.sql 1 14th September 2005 12:30 PM


All times are GMT +11. The time now is 07:17 PM.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.