Recent

Author Topic: How te create a functions which returns a Query (or datasource)  (Read 637 times)

Hansvb

  • Sr. Member
  • ****
  • Posts: 429
Hi,

I would like to create a function that returns a query (or a datasource).
What I have so far is below.

Main screen is under a temporary test button:
Code: Pascal  [Select][+][-]
  1. procedure TFrm_Main.Button1Click(Sender: TObject);
  2. var
  3.   MaintainAppdatabase : TMaintainAppdatabase;
  4.   Query : TSQLQuery;
  5.   ds : tDataSource;
  6. begin
  7.   try
  8.     MaintainAppdatabase := TMaintainAppdatabase.Create();
  9.     Query := TSQLQuery.Create(nil);
  10.     Query :=  MaintainAppdatabase.SelectAllItems();  // Query gets empty.  <<-- this goes wrong SIGSEGV
  11.  
  12.     ds := tDataSource.Create(nil);
  13.     ds.DataSet := Query;
  14.  
  15.     DBGridMain.DataSource := ds;
  16.     if assigned(Query) then Query.Free;
  17.     ds.free;
  18.  
  19.     MaintainAppdatabase.Free;
  20.   finally
  21.     // TODO;
  22.   end;
  23. end;      


In a separate unit (MaintainAppdatabase) is the function that the query or data source should return. That is:

Code: Pascal  [Select][+][-]
  1. function TMaintainAppdatabase.SelectAllItems() : TSQLQuery;
  2. var
  3.   selectSql : String;
  4.   Query     : TSQLQuery;
  5. begin
  6.   selectSql := 'select * from ' + TableName.ITEMS;
  7.  
  8.   try
  9.       SQLite3Conn.Close();
  10.       SQLite3Conn.DatabaseName := AppDatabaseFile;
  11.       SQLite3Conn.Open;
  12.       SQLTransaction.Active := True;
  13.  
  14.       Query := TSQLQuery.Create(nil);
  15.       Query.SQL.Text := selectSql;
  16.       Query.DataBase := SQLite3Conn;
  17.       Query.Open;
  18.  
  19.       ResultQuery :=  Query;  // ResultQuery is a TSQLQuery
  20.       Result := ResultQuery;
  21.  
  22.       Query.Close;
  23.       SQLite3Conn.Close();
  24.       Query.Free;
  25.  
  26.       SQLite3Conn.Close();
  27.     except
  28.       on E : Exception do
  29.         begin
  30.           Frm_Main.Logging.WriteToLogError('Fout opgetreden bij het lezen van de tabel ' + TableName.ITEMS);
  31.           Frm_Main.Logging.WriteToLogError(rsMessage);
  32.           Frm_Main.Logging.WriteToLogError(E.Message);
  33.         end;
  34.     end;
  35. end;  
  36.  

Where am I going wrong?

Zvoni

  • Hero Member
  • *****
  • Posts: 1502
Re: How te create a functions which returns a Query (or datasource)
« Reply #1 on: June 17, 2022, 02:04:03 pm »
First codeblock, Line 9: Remove it
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Hansvb

  • Sr. Member
  • ****
  • Posts: 429
Re: How te create a functions which returns a Query (or datasource)
« Reply #2 on: June 17, 2022, 02:18:57 pm »
When i remove that line then de SIGSEGV is gone. But the function is still wrong. Query gets empty in the second code block. Line 24 in the second code block is the problem.

MarkMLl

  • Hero Member
  • *****
  • Posts: 5561
Re: How te create a functions which returns a Query (or datasource)
« Reply #3 on: June 17, 2022, 02:40:23 pm »
When i remove that line then de SIGSEGV is gone. But the function is still wrong. Query gets empty in the second code block. Line 24 in the second code block is the problem.

Because you've just freed whatever your result points to.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Hansvb

  • Sr. Member
  • ****
  • Posts: 429
Re: How te create a functions which returns a Query (or datasource)
« Reply #4 on: June 17, 2022, 02:49:03 pm »
I know. How can I avoid that or first make a copy? before I free the query.
My workaround will be the use of a data module I think.

MarkMLl

  • Hero Member
  • *****
  • Posts: 5561
Re: How te create a functions which returns a Query (or datasource)
« Reply #5 on: June 17, 2022, 03:18:56 pm »
I know. How can I avoid that or first make a copy? before I free the query.
My workaround will be the use of a data module I think.

Assume you can't without opening a new query to the server.

Having multiple references to the same object is, at best, perilous.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Hansvb

  • Sr. Member
  • ****
  • Posts: 429
Re: How te create a functions which returns a Query (or datasource)
« Reply #6 on: June 17, 2022, 03:28:30 pm »
I see. With a datamodule it works fine. I will use that.

MarkMLl

  • Hero Member
  • *****
  • Posts: 5561
Re: How te create a functions which returns a Query (or datasource)
« Reply #7 on: June 17, 2022, 04:13:04 pm »
Remember that there's no rule that says that a query (etc.) opened in a function has to be closed there, or that an object created in a function has to be freed there.

The limit is whether you're confident that you understand the code that you're writing, and a part of that is properly documenting or at least commenting the behaviour of each function: i.e. something like "It's the caller's responsibility to close and free the TQuery created in this function".

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

BrunoK

  • Sr. Member
  • ****
  • Posts: 364
  • Retired programmer
Re: How te create a functions which returns a Query (or datasource)
« Reply #8 on: June 17, 2022, 06:13:29 pm »
First codeblock, Line 9: Remove it
that, and another likely problem is in Second codeblock you pass "Query" as the result; but that's only a reference copy to the "Query" created at line 14, then before returning, you free the "Result" instance at line 24 of 2nd block. You  may have an apparently valid function return, but that wont last long in the caller because the instance may have been altered due to recycling of the freed memory.

MarkMLl

  • Hero Member
  • *****
  • Posts: 5561
Re: How te create a functions which returns a Query (or datasource)
« Reply #9 on: June 17, 2022, 10:32:28 pm »
You  may have an apparently valid function return, but that wont last long in the caller because the instance may have been altered due to recycling of the freed memory.

I was going to point out that I said that hours ago, but you highlight an important issue: the data might look valid when first referenced, but then be overwritten unpredictably. And calling a method or writing to a property in an object that's already been freed is a recipe for disaster :-)

And using FreeAndNil() is no solution if one's already copied the pointer that represents the object, because it will only nil the pointer that it's directly applied to rather than wiping the object itself.

MarkMLl
« Last Edit: June 18, 2022, 12:14:24 pm by MarkMLl »
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018