TUniQuery.BreakExec working correctly with PostgreSQL?

Discussion of open issues, suggestions and bugs regarding UniDAC (Universal Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
Oma Hans
Posts: 5
Joined: Mon 15 Oct 2012 13:30

TUniQuery.BreakExec working correctly with PostgreSQL?

Post by Oma Hans » Mon 15 Oct 2012 14:27

Hello,

we're having a problem using the TUniQuery.BreakExec method (UniDAC 4.5.9) with PostgreSQL 8.4. While it works fine when using SQLite, with PG the call to TUniQuery.Open never returns if BreakExec gets called and the thread calling the Open method keeps running 'forever' at 100% load (keeping one CPU core busy).

I created a simple demo project to reproduce the problem:

- GUI sets up TUniQuery/TUniConnection and a worker thread (TThread descendant) and passes a reference to the UniQuery object to the thread, then resumes the thread.
- Thread does nothing except calling UniQuery.Open (so as soon as Open returns the thread finishes)
- the GUI thread uses MsgWaitForMultipleObjects to wait for the thread to finish and then displays the resulting data set in a grid
- on the form there is a button which can be used to call UniQuery.BreakExec (again using a reference of the same query instance passed to the worker thread)

Worker thread:

Code: Select all

interface
  TQueryThread = Class(TThread)
  private
    fQuery : TUniQuery;
  protected
    procedure Execute; override;
  public
    constructor Create(aQuery : TUniQuery); reintroduce;

    property Query : TUniQuery
      read fQuery;
  End;

implementation
{ TQueryThread }

constructor TQueryThread.Create(aQuery: TUniQuery);
begin
  inherited Create(true);

  fQuery := aQuery;
end;

procedure TQueryThread.Execute;
begin
  //The following Open call never returns if using PostgreSQL
  //and BreakExec called while query running. This thread causes 
  //100% cpu load after BreakExec call (see form code below)
  //SQLite works fine, though
  fQuery.Open; 
  if fQuery.Fetched then
    outputdebugstring('query completed')
  else if fQuery.Fetching then
    outputdebugstring('query aborted');
end;
Relevant form code:

Code: Select all

procedure TForm1.OpenQuery(aQuery: TUniQuery);
var
  t: array of THandle;
  n: Cardinal;
begin
  //aQuery.SQL.Text = 'SELECT * FROM test'
  worker := TQueryThread.Create(aQuery);
  try
    worker.Resume;
    setLength(t, 1);
    t[0] := worker.Handle;
    while true do
      begin
        n := MsgWaitForMultipleObjects(length(t), t[0], false, INFINITE, QS_ALLINPUT);
        case n of
          WAIT_OBJECT_0: break;
        else
          Application.ProcessMessages;
        end;
      end;
  finally
    worker.Terminate;
    worker.WaitFor;
    FreeAndNil(worker);
  end;
end;

procedure TForm1.btn_BreakExecClick(Sender: TObject);
begin
  if Assigned(worker) then
    //PostgreSQL: thread never finishes but causes 100% load after this call
    worker.Query.BreakExec;  
end;
I can't figure out the problem, especially as the same code runs fine (query is aborted successfully, thread finishes gracefully) when used on a SQLite DB. Is there something wrong with how I use BreakExec?

I could upload the complete project somewhere if needed.

ZEuS
Devart Team
Posts: 240
Joined: Thu 05 Apr 2012 07:32

Re: TUniQuery.BreakExec working correctly with PostgreSQL?

Post by ZEuS » Tue 16 Oct 2012 08:42

We have checked your sample and haven't found any problems except the following one.
Due to the specific character of the query cancellation process in PostgreSQL, the TUniQuery.Open method normally raises a "canceling statement due to user request" exception when the BreakExec method is called. So, try to wrap the fQuery.Open method call in the "try ... except" block in order to let the thread Execute method finish correctly.

Oma Hans
Posts: 5
Joined: Mon 15 Oct 2012 13:30

Re: TUniQuery.BreakExec working correctly with PostgreSQL?

Post by Oma Hans » Tue 16 Oct 2012 10:57

Thanks for your response.

Nice to hear it's working for you. I tried wrapping the .Open call in try/except as you suggested but unfortunately that didn't help. As I said, the Open call never returns, neither with an exception nor normally, so the exception block is never reached. The thread keeps running, as can be seen in Delphi's "Thread Status" debugging window and/or Sysinternals ProcessExplorer, and never leaves the .Open method.

In my first post I forgot to mention we're using Delphi 2007. So after reading your response I loaded the test project in Delphi XE, hoping that would fix it, but the behavior was the same there. I then tried a recent PosgreSQL server version (9.2.1) - still no luck.

I'd highly appreciate any further thoughts or input on this. Would it help if I uploaded my test project somewhere for you to have a look?

ZEuS
Devart Team
Posts: 240
Joined: Thu 05 Apr 2012 07:32

Re: TUniQuery.BreakExec working correctly with PostgreSQL?

Post by ZEuS » Tue 16 Oct 2012 12:07

Since the problem cannot be reproduced in our test application, please send your test project to eugeniyz*devart*com, and we will try to reproduce the problem using it.

Oma Hans
Posts: 5
Joined: Mon 15 Oct 2012 13:30

Re: TUniQuery.BreakExec working correctly with PostgreSQL?

Post by Oma Hans » Tue 16 Oct 2012 13:26

Thanks for taking the time! You've got mail.

ZEuS
Devart Team
Posts: 240
Joined: Thu 05 Apr 2012 07:32

Re: TUniQuery.BreakExec working correctly with PostgreSQL?

Post by ZEuS » Wed 17 Oct 2012 09:45

We have reproduced the problem using your test project.
Thank you for the information. We have fixed the error and will include the fix in the nearest UniDAC build (we plan to release the next build in this month).

Oma Hans
Posts: 5
Joined: Mon 15 Oct 2012 13:30

Re: TUniQuery.BreakExec working correctly with PostgreSQL?

Post by Oma Hans » Thu 01 Nov 2012 11:09

That's great news! Thanks a lot for your time and support. Looking forward to the next release.

Sorry for the late response, I haven't been in the office for 2 weeks and couldn't check this forum.

Post Reply