diff --git a/source/childwin.pas b/source/childwin.pas index bc65ded2..437d851c 100644 --- a/source/childwin.pas +++ b/source/childwin.pas @@ -4073,7 +4073,7 @@ begin end; FProgressForm := TFrmQueryProgress.Create(Self); debug('RunThreadedQuery(): Launching asynchronous query.'); - res := ExecPostAsync(FConn,nil,FProgressForm.Handle,ds); + res := ExecPostAsync(FConn,FProgressForm.Handle,ds); WaitForQueryCompletion(FProgressForm, res, false); if res.Result in [MQR_CONNECT_FAIL,MQR_QUERY_FAIL] then begin @@ -4121,7 +4121,7 @@ begin * Set FQueryRunning to false } debug('RunThreadedQuery(): Launching asynchronous query.'); - Result := ExecMysqlStatementAsync (AQuery,FConn,nil,FProgressForm.Handle,RunAsyncPost); + Result := ExecMysqlStatementAsync (AQuery,FConn,FProgressForm.Handle,RunAsyncPost); { Repeatedly check if the query has finished by inspecting FQueryRunning Allow repainting of user interface diff --git a/source/mysqlquery.pas b/source/mysqlquery.pas index ecc8ad6b..ec1a1870 100644 --- a/source/mysqlquery.pas +++ b/source/mysqlquery.pas @@ -6,15 +6,6 @@ uses Windows, Messages, Classes, Db, ZConnection, ZDataSet, MysqlQueryThread, HeidiComp; const - - // Query execution mode - MQM_SYNC = 0; - MQM_ASYNC = 1; - - // Query status notification mode - MQN_EVENTPROC = 0; // via event procedure with Synchronize - MQN_WINMESSAGE = 1; // via window message WM_MYSQL_THREAD_NOTIFY - // Thread notification events MQE_INITED = 0; // initialized MQE_STARTED = 1; // query started @@ -42,14 +33,10 @@ type FMysqlConnectionIsOwned : Boolean; FMysqlDataset : TDataset; FThreadID : Integer; - FSyncMode : Integer; FQueryThread : TMysqlQueryThread; FEventName : String; FEventHandle : THandle; FSql : WideString; - FOnNotify : TMysqlQueryNotificationEvent; - function GetNotificationMode: Integer; - function GetConnectionID: Integer; function GetComment: String; function GetResult: Integer; function GetHasresultSet: Boolean; @@ -58,14 +45,13 @@ type public constructor Create (AOwner : TComponent; AConn : POpenConnProf); overload; destructor Destroy (); override; - procedure Query(ASql: WideString; AMode: Integer; ANotifyWndHandle : THandle; Callback: TAsyncPostRunner; ds: TDeferDataSet); + procedure Query(ASql: WideString; ANotifyWndHandle : THandle; Callback: TAsyncPostRunner; ds: TDeferDataSet); procedure SetMysqlDataset(ADataset : TDataset); procedure PostNotification (AQueryResult : TThreadResult; AEvent : Integer); procedure SetThreadResult(AResult : TThreadResult); property Result : Integer read GetResult; // Query result code property Comment : String read GetComment; // Textual information about the query result, includes error description - property ConnectionID : Integer read GetConnectionID; // Mysql connection ID property MysqlConnection : TZConnection read FMysqlConnection; property MysqlDataset : TDataset read FMysqlDataset; // Resultset property HasResultset : Boolean read GetHasresultSet; // Indicator of resultset availability @@ -73,13 +59,10 @@ type property Sql : WideString read FSql; // Query string property EventName : String read FEventName; // Operating system event name used for blocking mode property EventHandle : THandle read FEventHandle; - property NotificationMode : Integer read GetNotificationMode; - property OnNotify : TMysqlQueryNotificationEvent read FOnNotify write FOnNotify; // Event procedure used in MQN_EVENTPROC notification mode end; - function ExecMysqlStatementAsync(ASql : WideString; AConn : TOpenConnProf; ANotifyProc : TMysqlQueryNotificationEvent; AWndHandle : THandle; Callback: TAsyncPostRunner) : TMysqlQuery; - function ExecMysqlStatementBlocking(ASql : WideString; AConn : TOpenConnProf; AWndHandle : THandle) : TMysqlQuery; - function ExecPostAsync(AConn : TOpenConnProf; ANotifyProc : TMysqlQueryNotificationEvent; AWndHandle : THandle; ds: TDeferDataSet): TMysqlQuery; + function ExecMysqlStatementAsync(ASql : WideString; AConn : TOpenConnProf; AWndHandle : THandle; Callback: TAsyncPostRunner) : TMysqlQuery; + function ExecPostAsync(AConn : TOpenConnProf; AWndHandle : THandle; ds: TDeferDataSet): TMysqlQuery; implementation @@ -94,50 +77,26 @@ uses Wrapper function to simplify running a query in asynchronous mode This function will end right after the thread is created. - If ANotifyProc<>nil then status notifications will be send using this eventproc; - * use the ASender param to inspect the result - Otherwise status notifications are sent by the WM_MYSQL_THREAD_NOTIFY message; * use the WParam member of the AMessage parameter (a TMysqlQuery object) @param string SQL-statement @param TConnParams Connection credentials structure - @param TMysqlQueryNotificationEvent Notify procedure @param THandle Window handle to post thread status messages to } -function ExecMysqlStatementAsync(ASql : WideString; AConn : TOpenConnProf; ANotifyProc : TMysqlQueryNotificationEvent; AWndHandle : THandle; Callback: TAsyncPostRunner) : TMysqlQuery; +function ExecMysqlStatementAsync(ASql : WideString; AConn : TOpenConnProf; AWndHandle : THandle; Callback: TAsyncPostRunner) : TMysqlQuery; begin Result := TMysqlQuery.Create(nil,@AConn); - Result.OnNotify := ANotifyProc; - Result.Query(ASql,MQM_ASYNC,AWndHandle,Callback,nil); + Result.Query(ASql,AWndHandle,Callback,nil); end; -function ExecPostAsync(AConn : TOpenConnProf; ANotifyProc : TMysqlQueryNotificationEvent; AWndHandle : THandle; ds: TDeferDataSet): TMysqlQuery; +function ExecPostAsync(AConn : TOpenConnProf; AWndHandle : THandle; ds: TDeferDataSet): TMysqlQuery; begin Result := TMysqlQuery.Create(nil,@AConn); - Result.OnNotify := ANotifyProc; - Result.Query('',MQM_ASYNC,AWndHandle,nil,ds); + Result.Query('',AWndHandle,nil,ds); end; -{*** - Wrapper function to simplify running a query in blocking mode - Status notifications are sent by the WM_MYSQL_THREAD_NOTIFY message; - Use the WParam member of the AMessage parameter (a TMysqlQuery object) - - @param string The single SQL-statement to be executed - @param TConnParams Connection credentials structure - @param THandle Window handle to post thread status messages to - @return TMysqlQuery Query object returned to resolve status info and the data -} - -function ExecMysqlStatementBlocking(ASql : WideString; AConn : TOpenConnProf; AWndHandle : THandle) : TMysqlQuery; -begin - Result := TMysqlQuery.Create(nil,@AConn); - Result.Query(ASql,MQM_SYNC,AWndHandle,nil,nil); -end; - - { TMysqlQuery } @@ -194,24 +153,11 @@ begin Result := FQueryResult.Comment; end; -function TMysqlQuery.GetConnectionID: Integer; -begin - Result := FQueryResult.ConnectionID; -end; - function TMysqlQuery.GetHasresultSet: Boolean; begin Result := FMysqlDataset <> nil; end; -function TMysqlQuery.GetNotificationMode: Integer; -begin - if Assigned(FOnNotify) then - Result := MQN_EVENTPROC - else - Result := MQN_WINMESSAGE; -end; - function TMysqlQuery.GetResult: Integer; begin Result := FQueryResult.Result; @@ -220,62 +166,26 @@ end; procedure TMysqlQuery.PostNotification(AQueryResult: TThreadResult; AEvent : Integer); begin SetThreadResult(AQueryResult); - - if - (FSyncMode = MQM_ASYNC) and - (AEvent in [MQE_INITED,MQE_STARTED,MQE_FINISHED,MQE_FREED]) and - Assigned(FOnNotify) then begin - debug(Format('qry: Calling notify function, event type %d occurred.', [AEvent])); - FOnNotify(Self, AEvent); - end else begin - debug(Format('qry: Not calling notify function, event type %d occurred.', [AEvent])); - end; + debug(Format('qry: Not calling notify function, event type %d occurred.', [AEvent])); end; -procedure TMysqlQuery.Query(ASql: WideString; AMode: Integer; ANotifyWndHandle : THandle; Callback: TAsyncPostRunner; ds: TDeferDataSet); +procedure TMysqlQuery.Query(ASql: WideString; ANotifyWndHandle : THandle; Callback: TAsyncPostRunner; ds: TDeferDataSet); begin - // create thread object - FQueryThread := TMysqlQueryThread.Create(Self,FConn,ASql,AMode,Callback,ds); + FQueryThread := TMysqlQueryThread.Create(Self,FConn,ASql,Callback,ds); FQueryThread.NotifyWndHandle := ANotifyWndHandle; FThreadID := FQueryThread.ThreadID; FEventName := APPNAME+'_'+IntToStr(FThreadID); - FSyncMode := AMode; FSql := ASql; FEventHandle := CreateEvent ({*EVENT_MODIFY_STATE + SYNCHRONIZE*}nil, False, False, PChar(FEventName)); - case AMode of - MQM_SYNC: - begin - // exec query - debug(Format('qry: Starting query thread %d', [FQueryThread.ThreadID])); - FQueryThread.Resume(); - debug(Format('qry: Waiting for query thread %d', [FQueryThread.ThreadID])); - WaitForSingleObject (EventHandle, INFINITE); - debug(Format('qry: Done waiting for query thread %d', [FQueryThread.ThreadID])); - CloseHandle (EventHandle); - // read status - // free thread - end; - MQM_ASYNC: - begin - // exec query - debug(Format('qry: Starting query thread %d', [FQueryThread.ThreadID])); - FQueryThread.Resume(); - end; - end; + // exec query + debug(Format('qry: Starting query thread %d', [FQueryThread.ThreadID])); + FQueryThread.Resume(); end; -{*** - - @param - @param - - @result -} - procedure TMysqlQuery.SetMysqlDataset(ADataset: TDataset); begin FMysqlDataset := ADataset; @@ -286,8 +196,7 @@ begin try FQueryResult := AResult; except - // Todo: Find cause of sporadical AV here. Avoid annoyance in the meantime by - // suppressing AVs here which doesn't seem to have any (visible) problematic consequences. + raise Exception.Create('Assertion failed: Internal error in SetThreadResult().'); end; end; diff --git a/source/mysqlquerythread.pas b/source/mysqlquerythread.pas index f43e1ca5..cbfdf233 100644 --- a/source/mysqlquerythread.pas +++ b/source/mysqlquerythread.pas @@ -49,19 +49,12 @@ type TThreadResult = record ThreadID : Integer; - ConnectionID : Cardinal; Action : Integer; Sql : WideString; Result : Integer; Comment : String; end; - {*TMysqlConnectThread = class(TThread) - private - protected - public - end;*} - TMysqlQueryThread = class(TThread) private FMysqlConn : TZConnection; @@ -72,26 +65,20 @@ type FPostDataSet: TDeferDataSet; FResult : Integer; FComment : String; - FSyncMode : Integer; FNotifyWndHandle : THandle; - procedure ReportInit; - procedure ReportStart; - procedure ReportFinished; - procedure ReportFreed; function GetExceptionData(AException : Exception) : TExceptionData; protected procedure Execute; override; procedure SetState (AResult : Integer; AComment : String); procedure SetNotifyWndHandle (Value : THandle); procedure NotifyStatus (AEvent : Integer); - procedure NotifyStatusViaEventProc (AEvent : Integer); procedure NotifyStatusViaWinMessage (AEvent : Integer); function AssembleResult () : TThreadResult; function RunDataQuery (ASql : WideString; var ADataset : TDataset; out AExceptionData : TExceptionData; callback: TAsyncPostRunner) : Boolean; function RunUpdateQuery (ASql : WideString; var ADataset : TDataset; out AExceptionData : TExceptionData; callback: TAsyncPostRunner) : Boolean; function QuerySingleCellAsInteger (ASql : WideString) : Integer; public - constructor Create (AOwner : TObject; AConn : TOpenConnProf; ASql : WideString; ASyncMode : Integer; Callback: TAsyncPostRunner; APostDataSet: TDeferDataSet); + constructor Create (AOwner : TObject; AConn : TOpenConnProf; ASql : WideString; Callback: TAsyncPostRunner; APostDataSet: TDeferDataSet); destructor Destroy; override; property NotifyWndHandle : THandle read FNotifyWndHandle write SetNotifyWndHandle; end; @@ -110,17 +97,13 @@ begin ZeroMemory (@Result,SizeOf(Result)); Result.ThreadID := ThreadID; - try - Result.ConnectionID := FMysqlConn.GetThreadId; - except - end; Result.Action := 1; Result.Sql := FSql; Result.Result := FResult; Result.Comment := FComment; end; -constructor TMysqlQueryThread.Create (AOwner : TObject; AConn : TOpenConnProf; ASql : WideString; ASyncMode : Integer; Callback: TAsyncPostRunner; APostDataSet: TDeferDataSet); +constructor TMysqlQueryThread.Create (AOwner : TObject; AConn : TOpenConnProf; ASql : WideString; Callback: TAsyncPostRunner; APostDataSet: TDeferDataSet); var mc : TZConnection; begin @@ -128,7 +111,6 @@ begin FOwner := AOwner; FConn := AConn; - FSyncMode := ASyncMode; FCallback := Callback; FPostDataSet := APostDataSet; mc := TMysqlQuery(FOwner).MysqlConnection; @@ -144,7 +126,6 @@ begin mc.Port := AConn.MysqlParams.Port; FreeOnTerminate := True; - end; destructor TMysqlQueryThread.Destroy; @@ -153,15 +134,11 @@ begin end; - - - procedure TMysqlQueryThread.NotifyStatus(AEvent: Integer); var h : THandle; qr : TThreadResult; begin - if AEvent = MQE_FINISHED then begin debug(Format('qry: Setting result', [AEvent])); qr := AssembleResult(); @@ -169,34 +146,14 @@ begin // trigger query finished event h := OpenEvent (EVENT_MODIFY_STATE,False,PChar(TMysqlQuery(FOwner).EventName)); debug('qry: Signalling completion via event.'); - if not SetEvent (h) then debug(Format('qry: Assertion failed: Error %d signaling event', [GetLastError])); + if not SetEvent (h) then raise Exception.Create(Format('Assertion failed: Error %d signaling event', [GetLastError])); CloseHandle(h); end; - - case TMysqlQuery(FOwner).NotificationMode of - MQN_EVENTPROC: NotifyStatusViaEventProc(AEvent); - MQN_WINMESSAGE: NotifyStatusViaWinMessage(AEvent); - end; - -end; - -procedure TMysqlQueryThread.NotifyStatusViaEventProc(AEvent: Integer); -begin - if FSyncMode=MQM_ASYNC then - begin - case AEvent of - MQE_INITED: Synchronize(ReportInit); - MQE_STARTED: Synchronize(ReportStart); - MQE_FINISHED: Synchronize(ReportFinished); - MQE_FREED: Synchronize(ReportFreed); - end; - - end; + NotifyStatusViaWinMessage(AEvent); end; procedure TMysqlQueryThread.NotifyStatusViaWinMessage(AEvent: Integer); begin - debug('qry: Signalling completion via message.'); debug(Format('qry: Posting status %d via WM_MYSQL_THREAD_NOTIFY message', [AEvent])); PostMessage(FNotifyWndHandle,WM_MYSQL_THREAD_NOTIFY,Integer(FOwner),AEvent); end; @@ -234,11 +191,6 @@ begin end else begin try r := RunDataQuery (FSql,TDataSet(q),ex,FCallback); - //if r then begin - //if q.State=dsBrowse then begin - // WTF? - //end; - //end; TMysqlQuery(FOwner).SetMysqlDataset(q); if r then SetState (MQR_SUCCESS,'SUCCESS') @@ -280,46 +232,6 @@ begin end; end; -procedure TMysqlQueryThread.ReportStart(); -var - qr : TThreadResult; -begin - qr := AssembleResult(); - - if FOwner <> nil then - TMysqlQuery (FOwner).PostNotification(qr,MQE_STARTED); -end; - -procedure TMysqlQueryThread.ReportFinished(); -var - qr : TThreadResult; -begin - qr := AssembleResult(); - - if FOwner <> nil then - TMysqlQuery (FOwner).PostNotification(qr,MQE_FINISHED); -end; - -procedure TMysqlQueryThread.ReportInit(); -var - qr : TThreadResult; -begin - qr := AssembleResult(); - - if FOwner <> nil then - TMysqlQuery (FOwner).PostNotification(qr,MQE_INITED); -end; - -procedure TMysqlQueryThread.ReportFreed; -var - qr : TThreadResult; -begin - qr := AssembleResult(); - - if FOwner <> nil then - TMysqlQuery (FOwner).PostNotification(qr,MQE_FREED); -end; - function TMysqlQueryThread.RunDataQuery(ASql: WideString; var ADataset: TDataset; out AExceptionData : TExceptionData; callback: TAsyncPostRunner): Boolean; var @@ -364,7 +276,6 @@ begin except On E: Exception do AExceptionData := GetExceptionData(E); - //MessageDlg( 'SQL Error: '+ CRLF + E.Message, mtError, [mbOK], 0 ); end; FreeAndNil (q); @@ -377,6 +288,7 @@ end; procedure TMysqlQueryThread.SetState(AResult: Integer; AComment: String); begin + debug(Format('qry: Setting status %d with comment %s', [AResult, AComment])); FResult := AResult; FComment := AComment; end; diff --git a/source/queryprogress.pas b/source/queryprogress.pas index e7f14ed9..e6f328de 100644 --- a/source/queryprogress.pas +++ b/source/queryprogress.pas @@ -58,15 +58,11 @@ begin begin debug('qry: Setting running flag to ''true''.'); end; - MQE_STARTED: - begin - end; MQE_FINISHED: begin debug('qry: Setting running flag to ''false'' and closing dialog.'); Close(); end; - MQE_FREED:; end; end;