////////////////////////////////////////////////// // DB Access Components // Copyright © 1998-2007 Core Lab. All right reserved. // SQLMonitor supports // Created: 17.11.99 ////////////////////////////////////////////////// {$IFNDEF CLR} {$I Dac.inc} unit DASQLMonitor; {$ENDIF} interface uses {$IFDEF LINUX} Types, {$ELSE} {$ENDIF} SysUtils, Classes, DB, MemData, DBAccess, DBMonitorClient, DBMonitorIntf; const teStart = 1; teCommit = 2; teRollback = 3; type TDATraceFlag = (tfQPrepare, tfQExecute, tfQFetch, tfError, tfStmt, tfConnect, tfTransact, tfBlob, tfService, tfMisc, tfParams); TDATraceFlags = set of TDATraceFlag; TMonitorOption = (moDialog, moSQLMonitor, moDBMonitor, moCustom, moHandled); TMonitorOptions = set of TMonitorOption; TOnSQLEvent = procedure (Sender: TObject; Text: string; Flag: TDATraceFlag) of object; { TCustomDASQLMonitor } TDASQLMonitorClass = class of TCustomDASQLMonitor; TCustomDASQLMonitor = class(TComponent) private FActive: boolean; FTraceFlags: TDATraceFlags; FOptions: TMonitorOptions; FStreamedActive: boolean; {$IFDEF WIN32} FRegistered: boolean; FSMClient: IUnknown; NeedUninitialize :boolean; {$ENDIF} {$IFNDEF LINUX} FDBMonitor: IDBMonitor; {$ENDIF} procedure SetActive(Value: boolean); procedure SetOptions(Value: TMonitorOptions); protected FOnSQLEvent: TOnSQLEvent; { component routines } procedure Loaded; override; procedure CheckActive; { Borland's SQL Monitor support } procedure RegisterClient; virtual; procedure UnRegisterClient; virtual; procedure AddStatement(const St: string); procedure SMClientSignal(Sender: TObject; Data: Integer); { DBMonitor support } procedure OnConnect(const Username, Server, St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); procedure OnDisconnect(const Username, Server, St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); procedure OnTransact(const St: string; Component: TComponent; TransactEvent: integer; ATracePoint: TTracePoint; var AMessageID: Cardinal); procedure OnPrepare(const SQL: string; var Params: TSQLParams; const St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); procedure OnUnprepare(const SQL: string; var Params: TSQLParams; const St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); procedure OnExecute(const SQL: string; var Params: TSQLParams; const St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); procedure OnError(ErrorStr: string); procedure OnCustomMessage(const St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); procedure PrepareExecuteMessage(const SQL: string; var Params: TSQLParams; const St: string; Component: TComponent; ATracePoint: TTracePoint; EventType: TEventType; var AMessageID: Cardinal); function GetCompHandle(Comp: TComponent): string; function GetParent(Component: TComponent; Index: integer): TComponent; virtual; function GetParentCount(Component: TComponent): integer; virtual; procedure InternalSQLPrepare(Component: TComponent; const SQL: string; Params: TDAParams; ATracePoint: TTracePoint; var MessageID: Cardinal); procedure InternalSQLUnprepare(Component: TComponent; const SQL: string; Params: TDAParams; ATracePoint: TTracePoint; var MessageID: Cardinal); procedure InternalSQLExecute(Component: TComponent; const SQL: string; Params: TDAParams; const Caption: string; ATracePoint: TTracePoint; var MessageID: Cardinal); virtual; procedure InternalDBConnect(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); procedure InternalDBDisconnect(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); procedure InternalTRStart(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); virtual; procedure InternalTRCommit(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); virtual; procedure InternalTRRollback(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); virtual; procedure InternalDBError(Exception: EDAError); procedure InternalCustomMessage(Connection: TCustomDAConnection; const Msg: string; var AMessageID: Cardinal); class function GetMonitor: TCustomDASQLMonitor; virtual; public class procedure SQLPrepare(Component: TComponent; const SQL: string; Params: TDAParams; var MessageID: Cardinal; BeforeEvent: boolean); class procedure SQLUnprepare(Component: TComponent; const SQL: string; Params: TDAParams; var MessageID: Cardinal; BeforeEvent: boolean); class procedure SQLExecute(Component: TComponent; const SQL: string; Params: TDAParams; const Caption: string; var MessageID: Cardinal; BeforeEvent: boolean); class procedure DBConnect(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); class procedure DBDisconnect(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); class procedure TRStart(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); virtual; class procedure TRCommit(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); virtual; class procedure TRRollback(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); virtual; class procedure DBError(Exception: EDAError); class procedure CustomMessage(Connection: TCustomDAConnection; const Msg: string; var MessageID: Cardinal); class function HasMonitor: boolean; class function GetParamDataType(Param: TDAParam): string; virtual; class function GetParamParamType(Param: TDAParam): string; virtual; class function GetParamValue(Param: TDAParam): string; virtual; class function GetParam(Param: TDAParam; var SQLParam: TSQLParam): string; class function GetParams(Params: TDAParams; var SQLParams: TSQLParams): string; overload; class function GetParams(Params: TDAParams): string; overload; class function GetCaption: string; virtual; class procedure ShowDebug(Component: TComponent; const SQL: string; Params: TDAParams; const Caption: string); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property Active: boolean read FActive write SetActive default True; property TraceFlags: TDATraceFlags read FTraceFlags write FTraceFlags default [tfQPrepare, tfQExecute, tfError, tfConnect, tfTransact, tfParams, tfMisc]; property Options: TMonitorOptions read FOptions write SetOptions default [moDialog, moSQLMonitor, moDBMonitor, moCustom]; property OnSQL: TOnSQLEvent read FOnSQLEvent write FOnSQLEvent; end; var ShowDebugFormProc: procedure (DASQLMonitorClass: TDASQLMonitorClass; Component: TComponent; SQL: string; Params: TDAParams; Caption: string); function GetComponentID(Component: TComponent): cardinal; function GetComponentName(Component: TComponent): string; implementation uses MemUtils {$IFNDEF WIN32} ; {$ELSE} , ActiveX; const Class_SMClient: TGUID = '{CB9879E2-4395-11D0-9FFC-00A0248E4B9A}'; type ISMClient = interface(IUnknown) ['{CB9879E1-4395-11D0-9FFC-00A0248E4B9A}'] function RegisterClient(ID: Integer; Name: PChar; Instance, SignalProc: Pointer): WordBool; stdcall; function AddStatement(Statement: PChar; Len: Integer): WordBool; stdcall; end; {$ENDIF} function GetComponentID(Component: TComponent): cardinal; begin {$IFDEF CLR} if Component = nil then Result := 0 else {$ENDIF} Result := Cardinal(Component{$IFDEF CLR}.GetHashCode{$ENDIF}); if Result <> 0 then if (Component is TCustomDADataSet) then Result := Result xor Reverse4(GetComponentID(TCustomDADataSet(Component).Connection)) else if (Component is TCustomDASQL) then Result := Result xor Reverse4(GetComponentID(TCustomDASQL(Component).Connection)); end; function GetComponentName(Component: TComponent): string; begin if Component.Name <> '' then Result := Component.Name else Result := Component.ClassName + ' ($' + IntToHex(GetComponentID(Component), 8) + ')'; end; { TCustomDASQLMonitor } const fmtConnectInfo = 'Username=%s'#13#10'Server=%s'; constructor TCustomDASQLMonitor.Create(AOwner: TComponent); begin inherited Create(AOwner); FActive := False; FOptions := [moDialog, moSQLMonitor, moDBMonitor, moCustom]; FTraceFlags := [tfQPrepare, tfQExecute, tfError, tfConnect, tfTransact, tfParams, tfMisc]; FStreamedActive := True; if (csDesigning in ComponentState) or (AOwner = nil) or not (csReading in AOwner.ComponentState) then Active := True end; destructor TCustomDASQLMonitor.Destroy; begin Active := False; {$IFDEF WIN32} if NeedUninitialize then CoUninitialize; {$ENDIF} inherited; end; class procedure TCustomDASQLMonitor.SQLPrepare(Component: TComponent; const SQL: string; Params: TDAParams; var MessageID: Cardinal; BeforeEvent: boolean); var Monitor: TCustomDASQLMonitor; begin Monitor := GetMonitor; if Assigned(Monitor) then if BeforeEvent then Monitor.InternalSQLPrepare(Component, TrimRight(SQL), Params, tpBeforeEvent, MessageID) else Monitor.InternalSQLPrepare(Component, TrimRight(SQL), Params, tpAfterEvent, MessageID) else if BeforeEvent then ShowDebug(Component, TrimRight(SQL), Params, 'Prepare'); end; class procedure TCustomDASQLMonitor.SQLUnprepare(Component: TComponent; const SQL: string; Params: TDAParams; var MessageID: Cardinal; BeforeEvent: boolean); var Monitor: TCustomDASQLMonitor; begin Monitor := GetMonitor; if Assigned(Monitor) then if BeforeEvent then Monitor.InternalSQLUnprepare(Component, TrimRight(SQL), Params, tpBeforeEvent, MessageID) else Monitor.InternalSQLUnprepare(Component, TrimRight(SQL), Params, tpAfterEvent, MessageID) else if BeforeEvent then ShowDebug(Component, TrimRight(SQL), Params, 'Unprepare'); end; class procedure TCustomDASQLMonitor.SQLExecute(Component: TComponent; const SQL: string; Params: TDAParams; const Caption: string; var MessageID: Cardinal; BeforeEvent: boolean); var Monitor: TCustomDASQLMonitor; ACaption: string; begin Monitor := GetMonitor; if Assigned(Monitor) then if BeforeEvent then Monitor.InternalSQLExecute(Component, SQL, Params, Caption, tpBeforeEvent, MessageID) else Monitor.InternalSQLExecute(Component, SQL, Params, Caption, tpAfterEvent, MessageID) else begin if Caption = '' then ACaption := 'Execute' else ACaption := Caption; if BeforeEvent then ShowDebug(Component, SQL, Params, ACaption); end; end; class procedure TCustomDASQLMonitor.DBConnect(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); var Monitor: TCustomDASQLMonitor; begin Monitor := GetMonitor; if Assigned(Monitor) then if BeforeEvent then Monitor.InternalDBConnect(Connection, tpBeforeEvent, MessageID) else Monitor.InternalDBConnect(Connection, tpAfterEvent, MessageID) end; class procedure TCustomDASQLMonitor.DBDisconnect(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); var Monitor: TCustomDASQLMonitor; begin Monitor := GetMonitor; if Assigned(Monitor) then if BeforeEvent then Monitor.InternalDBDisconnect(Connection, tpBeforeEvent, MessageId) else Monitor.InternalDBDisconnect(Connection, tpAfterEvent, MessageId); end; class procedure TCustomDASQLMonitor.TRStart(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); var Monitor: TCustomDASQLMonitor; begin Monitor := GetMonitor; if Assigned(Monitor) then if BeforeEvent then Monitor.InternalTRStart(Connection, tpBeforeEvent, MessageID) else Monitor.InternalTRStart(Connection, tpAfterEvent, MessageID); end; class procedure TCustomDASQLMonitor.TRCommit(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); var Monitor: TCustomDASQLMonitor; begin Monitor := GetMonitor; if Assigned(Monitor) then if BeforeEvent then Monitor.InternalTRCommit(Connection, tpBeforeEvent, MessageID) else Monitor.InternalTRCommit(Connection, tpAfterEvent, MessageID); end; class procedure TCustomDASQLMonitor.TRRollback(Connection: TCustomDAConnection; var MessageID: Cardinal; BeforeEvent: boolean); var Monitor: TCustomDASQLMonitor; begin Monitor := GetMonitor; if Assigned(Monitor) then if BeforeEvent then Monitor.InternalTRRollback(Connection, tpBeforeEvent, MessageID) else Monitor.InternalTRRollback(Connection, tpAfterEvent, MessageID); end; class procedure TCustomDASQLMonitor.DBError(Exception: EDAError); var Monitor: TCustomDASQLMonitor; begin Monitor := GetMonitor; if Assigned(Monitor) then Monitor.InternalDBError(Exception); end; class procedure TCustomDASQLMonitor.CustomMessage(Connection: TCustomDAConnection; const Msg: string; var MessageID: Cardinal); var Monitor: TCustomDASQLMonitor; begin Monitor := GetMonitor; if Assigned(Monitor) then Monitor.InternalCustomMessage(Connection, Msg, MessageID); end; class function TCustomDASQLMonitor.GetParamDataType(Param: TDAParam): string; begin Result := FieldTypeNames[Param.DataType]; if Param.DataType in [ftString,ftFixedChar,ftWideString] then Result := Result + '[' + IntToStr(Length(Param.AsString)) + ']'; end; class function TCustomDASQLMonitor.GetParamParamType(Param: TDAParam): string; begin case Param.ParamType of ptInput: Result := 'IN'; ptOutput: Result := 'OUT'; ptInputOutput: Result := 'IN/OUT'; ptResult: Result := 'RESULT'; else Result := ''; end; end; class function TCustomDASQLMonitor.GetParamValue(Param: TDAParam): string; begin Result := ''; if Param.IsNull then Result := '' else case Param.DataType of ftDate: Result := DateToStr(Param.AsDate); ftDateTime: Result := Param.AsString; ftBlob, ftMemo{$IFDEF VER10P}, ftWideMemo{$ENDIF}: begin Result := ''; end; ftCursor: Result := ''; ftString, ftFixedChar, ftWideString: Result := '''' + Param.AsString + ''''; ftBytes, ftVarBytes: Result := '' else Result := Param.AsString; end; end; function ConcatWith(const Args: array of string; const AConcatWith: string): string; var i: integer; begin Result := ''; for i := 0 to Length(Args)-1 do begin if Args[i] <> '' then if Result <> '' then Result := Result + AConcatWith + Args[i] else Result := Args[i]; end; end; class function TCustomDASQLMonitor.GetParam(Param: TDAParam; var SQLParam: TSQLParam): string; begin SQLParam.Name := Param.Name; SQLParam.DataType := GetParamDataType(Param); SQLParam.ParamType := GetParamParamType(Param); SQLParam.Value := GetParamValue(Param); Result := ':' + Param.Name + '(' + ConcatWith([SQLParam.DataType, SQLParam.ParamType],',') + ConcatWith([')', SQLParam.Value], '='); end; class function TCustomDASQLMonitor.GetParams(Params: TDAParams; var SQLParams: TSQLParams): string; var i: integer; begin Result := ''; if Params <> nil then begin SetLength(SQLParams, Params.Count); for i := 0 to Params.Count - 1 do Result := Result + GetParam(Params[i], SQLParams[i]) + ' '#13#10; end; end; class function TCustomDASQLMonitor.GetParams(Params: TDAParams): string; var SQLParams: TSQLParams; begin Result := GetParams(Params, SQLParams); end; class procedure TCustomDASQLMonitor.ShowDebug(Component: TComponent; const SQL: string; Params: TDAParams; const Caption: string); begin if Assigned(ShowDebugFormProc) then ShowDebugFormProc(Self, Component, SQL, Params, Caption); end; class function TCustomDASQLMonitor.GetMonitor: TCustomDASQLMonitor; begin Result := nil; end; class function TCustomDASQLMonitor.GetCaption: string; begin Result := 'DataAccess'; end; function TCustomDASQLMonitor.GetCompHandle(Comp: TComponent): string; var Conn: TCustomDAConnection; begin if moHandled in Options then begin Result := ' [' + Comp.Name + '$' + IntToHex(GetComponentID(Comp), 8); if Comp is TCustomDADataSet then Conn := TCustomDADataSet(Comp).Connection else if Comp is TCustomDASQL then Conn := TCustomDASQL(Comp).Connection else Conn := nil; if Conn <> nil then Result := Result + '; ' + Conn.Name + '$' + IntToHex(GetComponentID(Conn), 8); Result := Result + '] '; end else Result := ''; end; function TCustomDASQLMonitor.GetParent(Component: TComponent; Index: integer): TComponent; begin if (Component is TCustomDASQL) then Result := TCustomDASQL(Component).Connection else if (Component is TCustomDADataSet) then Result := TCustomDADataSet(Component).Connection else Result := nil; end; function TCustomDASQLMonitor.GetParentCount(Component: TComponent): integer; begin Result := 1; end; procedure TCustomDASQLMonitor.InternalSQLPrepare(Component: TComponent; const SQL: string; Params: TDAParams; ATracePoint: TTracePoint; var MessageID: Cardinal); var ParamSt: string; SQLParams: TSQLParams; ASQL: string; begin CheckActive; if Active and (tfQPrepare in TraceFlags) then begin if ((moDialog in Options) and (not((moCustom in Options) or (csDesigning in ComponentState)) or ((Component is TCustomDADataSet) and TCustomDADataSet(Component).Debug or (Component is TCustomDASQL) and TCustomDASQL(Component).Debug))) and (ATracePoint = tpBeforeEvent) then ShowDebug(Component, SQL, Params, 'Prepare'); ParamSt := TrimRight(GetParams(Params, SQLParams)); if (moSQLMonitor in Options) and (ATracePoint <> tpAfterEvent) then begin AddStatement('SQL Prepare' + GetCompHandle(Component) + ': ' + SQL); if (ParamSt <> '') and (tfParams in TraceFlags) then AddStatement(ParamSt); end; OnPrepare(SQL, SQLParams, 'SQL Prepare' + GetCompHandle(Component) + ': ' + SQL + #13#10 + ParamSt, Component, ATracePoint, MessageID); if Assigned(FOnSQLEvent) and (ATracePoint <> tpAfterEvent) then begin if ParamSt <> '' then ASQL := SQL + #13#10 + ParamSt else ASQL := SQL; FOnSQLEvent(Component, 'Prepare: ' + ASQL, tfQPrepare); end; end; end; procedure TCustomDASQLMonitor.InternalSQLUnprepare(Component: TComponent; const SQL: string; Params: TDAParams; ATracePoint: TTracePoint; var MessageID: Cardinal); var ParamSt: string; SQLParams: TSQLParams; ASQL: string; begin CheckActive; if Active and (tfQPrepare in TraceFlags) then begin if ((moDialog in Options) and (not ((moCustom in Options) or (csDesigning in ComponentState)) or ((Component is TCustomDADataSet) and TCustomDADataSet(Component).Debug or (Component is TCustomDASQL) and TCustomDASQL(Component).Debug))) and (ATracePoint = tpBeforeEvent) then ShowDebug(Component, SQL, Params, 'Unprepare'); ParamSt := TrimRight(GetParams(Params, SQLParams)); if (moSQLMonitor in Options) then begin AddStatement('SQL Unprepare' + GetCompHandle(Component) + ': ' + SQL); if (ParamSt <> '') and (tfParams in TraceFlags) then AddStatement(ParamSt); end; OnUnprepare(SQL, SQLParams, 'SQL Unprepare' + GetCompHandle(Component) + ': ' + SQL + #13#10 + ParamSt, Component, ATracePoint, MessageID); if Assigned(FOnSQLEvent) and (ATracePoint <> tpAfterEvent) then begin if ParamSt <> '' then ASQL := SQL + #13#10 + ParamSt else ASQL := SQL; FOnSQLEvent(Component, 'Unprepare: ' + ASQL, tfQPrepare); end; end; end; procedure TCustomDASQLMonitor.InternalSQLExecute(Component:TComponent; const SQL: string; Params: TDAParams; const Caption: string; ATracePoint: TTracePoint; var MessageID: Cardinal); var ParamSt: string; St: string; SQLParams: TSQLParams; ASQL: string; begin CheckActive; if Active and (tfQExecute in TraceFlags) then begin if (moDialog in Options) and (not ((moCustom in Options) or (csDesigning in ComponentState)) or ((Component is TCustomDADataSet) and TCustomDADataSet(Component).Debug or (Component is TCustomDASQL) and TCustomDASQL(Component).Debug)) and (ATracePoint = tpBeforeEvent) then begin if Caption = '' then St := 'Execute' else St := Caption; ShowDebug(Component, SQL, Params, St); end; ParamSt := TrimRight(GetParams(Params, SQLParams)); if (moSQLMonitor in Options) and (ATracePoint <> tpAfterEvent) then begin St := 'SQL Execute'; if Caption <> '' then St := St + ' [' + Caption + ']'; AddStatement(St + GetCompHandle(Component) + ': '{#13#10} + SQL); if (ParamSt <> '') and (tfParams in TraceFlags) then AddStatement(ParamSt); end; OnExecute(SQL, SQLParams, 'SQL Execute' + GetCompHandle(Component) + ': ' + SQL + #13#10 + ParamSt, Component, ATracePoint, MessageID); if Assigned(FOnSQLEvent) and (ATracePoint <> tpAfterEvent) then begin if ParamSt <> '' then ASQL := SQL + #13#10 + ParamSt else ASQL := SQL; FOnSQLEvent(Component, ASQL, tfQExecute); end; end; end; procedure TCustomDASQLMonitor.InternalDBConnect(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); var St: string; begin CheckActive; if Active and (tfConnect in TraceFlags) then begin St := 'Connect: ' + Connection.Username + '@' + Connection.Server + GetCompHandle(Connection); if (moSQLMonitor in Options) and (ATracePoint <> tpAfterEvent) then AddStatement(St); OnConnect(Connection.Username, Connection.Server, St, Connection, ATracePoint, MessageID); if Assigned(FOnSQLEvent) and (ATracePoint <> tpAfterEvent) then FOnSQLEvent(Connection, St, tfConnect); end; end; procedure TCustomDASQLMonitor.InternalDBDisconnect(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); var St: string; begin CheckActive; if Active and (tfConnect in TraceFlags) then begin St := 'Disconnect: ' + Connection.Username + '@' + Connection.Server + GetCompHandle(Connection); if (moSQLMonitor in Options) and (ATracePoint <> tpAfterEvent) then AddStatement(St); OnDisconnect(Connection.Username, Connection.Server, St, Connection, ATracePoint, MessageID); if Assigned(FOnSQLEvent) and (ATracePoint <> tpAfterEvent) then FOnSQLEvent(Connection, St, tfConnect); end; end; procedure TCustomDASQLMonitor.InternalTRStart(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); var St: string; begin CheckActive; if Active and (tfTransact in TraceFlags) then begin St := 'Start: ' + Connection.Username + '@' + Connection.Server + GetCompHandle(Connection); if (moSQLMonitor in Options) and (ATracePoint <> tpAfterEvent) then AddStatement(St); OnTransact(St, Connection, teStart, ATracePoint, MessageID); if Assigned(FOnSQLEvent) and (ATracePoint <> tpAfterEvent) then FOnSQLEvent(Connection, St, tfTransact); end; end; procedure TCustomDASQLMonitor.InternalTRCommit(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); var St: string; begin CheckActive; if Active and (tfTransact in TraceFlags) then begin St := 'Commit: ' + Connection.Username + '@' + Connection.Server + GetCompHandle(Connection); if (moSQLMonitor in Options) and (ATracePoint <> tpAfterEvent) then AddStatement(St); OnTransact(St, Connection, teCommit, ATracePoint, MessageID); if Assigned(FOnSQLEvent) and (ATracePoint <> tpAfterEvent) then FOnSQLEvent(Connection, St, tfTransact); end; end; procedure TCustomDASQLMonitor.InternalTRRollback(Connection: TCustomDAConnection; ATracePoint: TTracePoint; var MessageID: Cardinal); var St: string; begin CheckActive; if Active and (tfTransact in TraceFlags) then begin St := 'Rollback: ' + Connection.Username + '@' + Connection.Server + GetCompHandle(Connection); if (moSQLMonitor in Options) and (ATracePoint <> tpAfterEvent) then AddStatement(St); OnTransact(St, Connection, teRollback, ATracePoint, MessageID); if Assigned(FOnSQLEvent) and (ATracePoint <> tpAfterEvent) then FOnSQLEvent(Connection, St, tfTransact); end; end; procedure TCustomDASQLMonitor.InternalDBError(Exception: EDAError); var St: string; begin CheckActive; if Active and (tfError in TraceFlags) then begin St := 'Error: ' + Exception.Message; if (moSQLMonitor in Options) then AddStatement(St); OnError(Exception.Message); if Assigned(FOnSQLEvent) then FOnSQLEvent(Exception, St, tfError); end; end; procedure TCustomDASQLMonitor.InternalCustomMessage(Connection: TCustomDAConnection; const Msg: string; var AMessageID: Cardinal); begin CheckActive; if Active and (tfMisc in TraceFlags) then begin if (moSQLMonitor in Options) then AddStatement(Msg); OnCustomMessage(Msg, Connection, tpBeforeEvent, AMessageID); OnCustomMessage(Msg, Connection, tpAfterEvent, AMessageID); if Assigned(FOnSQLEvent) then FOnSQLEvent(Connection, Msg, tfMisc); end; end; { Borland's SQL Monitor support } procedure TCustomDASQLMonitor.RegisterClient; {$IFDEF WIN32} var Title: string; {$ENDIF} begin {$IFDEF WIN32} if not FRegistered and (GetMonitor = Self) then if Succeeded(CoInitialize(nil)) then begin if not Succeeded(CoCreateInstance(Class_SMClient, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IUnknown, FSMClient)) then begin CoUninitialize; Exit; end; Title := ApplicationTitle; if csDesigning in ComponentState then Title := Title + ': ' + GetCaption; try (FSMClient as ISMClient).RegisterClient(Integer(Self), PChar(Title), Self, @TCustomDASQLMonitor.SMClientSignal); FRegistered := True; except end; end; {$ENDIF} end; procedure TCustomDASQLMonitor.UnRegisterClient; begin {$IFDEF WIN32} FSMClient := nil; if FRegistered then begin FRegistered := False; CoUninitialize; end; {$ENDIF} end; procedure TCustomDASQLMonitor.AddStatement(const St: string); begin {$IFDEF WIN32} if Assigned(FSMClient) then (FSMClient as ISMClient).AddStatement(PChar(St), Length(St)); {$ENDIF} end; { 0 none 1 Prepare 2 Execute 4 Error 8 Statement 16 Connect/Disconnect 32 Transaction 64 Blob 128 Misc 256 Vendor call 512 Input params 1024 Fetch} procedure TCustomDASQLMonitor.SMClientSignal(Sender: TObject; Data: Integer); begin FTraceFlags := TDATraceFlags(Word(Data)); end; procedure TCustomDASQLMonitor.SetActive(Value: boolean); begin FStreamedActive := Value; if not (csReading in ComponentState) and (Value <> FActive) then begin FActive := Value; if moSQLMonitor in Options then if FActive then RegisterClient else UnRegisterClient; {$IFDEF MSWINDOWS} if moDBMonitor in Options then if FActive then begin {$IFDEF CLR} FDBMonitor := GetDBMonitor; if FDBMonitor <> nil then FDBMonitor.SetCaption(GetCaption); {$ELSE} if not NeedUninitialize then NeedUninitialize := Succeeded(CoInitialize(nil)); FDBMonitor := GetDBMonitor; if FDBMonitor <> nil then FDBMonitor.SetCaption(PChar(GetCaption)); {$ENDIF} end else begin FDBMonitor := nil; end; {$ENDIF} end; end; procedure TCustomDASQLMonitor.SetOptions(Value: TMonitorOptions); begin FOptions := Value; if FActive then begin if moSQLMonitor in FOptions then RegisterClient else UnRegisterClient; {$IFDEF WIN32} if moDBMonitor in FOptions then begin if not NeedUninitialize then NeedUninitialize := Succeeded(CoInitialize(nil)); FDBMonitor := GetDBMonitor; if FDBMonitor <> nil then FDBMonitor.SetCaption(PChar(GetCaption)); end else begin FDBMonitor := nil; end; {$ENDIF} end; end; procedure TCustomDASQLMonitor.OnConnect(const Username, Server, St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); {$IFDEF MSWINDOWS} var Msg: TMonitorMessage; ParamStr: string; {$ENDIF} begin {$IFDEF MSWINDOWS} if FDBMonitor <> nil then begin with Msg do begin MessageID := AMessageID; EventType := Integer(etConnect); TracePoint := Integer(ATracePoint); ObjectID := GetComponentID(Component); OwnerID := 0; OwnerName := ''; ParamStr := Format(fmtConnectInfo, [Username, Server]); {$IFDEF CLR} ObjectName := GetComponentName(Component); Description := St; FDBMonitor.OnEvent(Msg, ParamStr); {$ELSE} ObjectName := PChar(GetComponentName(Component)); Description := PChar(St); FDBMonitor.OnEvent(Msg, PChar(ParamStr)); {$ENDIF} end; if ATracePoint = tpBeforeEvent then AMessageID := Msg.MessageID; end; {$ENDIF} end; procedure TCustomDASQLMonitor.OnDisconnect(const Username, Server, St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); {$IFDEF MSWINDOWS} var Msg: TMonitorMessage; {$ENDIF} begin {$IFDEF MSWINDOWS} if FDBMonitor <> nil then begin with Msg do begin MessageID := AMessageID; EventType := Integer(etDisconnect); TracePoint := Integer(ATracePoint); ObjectID := GetComponentID(Component); OwnerID := 0; OwnerName := ''; {$IFDEF CLR} ObjectName := GetComponentName(Component); Description := St; FDBMonitor.OnEvent(Msg, ''); {$ELSE} ObjectName := PChar(GetComponentName(Component)); Description := PChar(St); FDBMonitor.OnEvent(Msg, nil); {$ENDIF} end; if ATracePoint = tpBeforeEvent then AMessageID := Msg.MessageID; end; {$ENDIF} end; procedure TCustomDASQLMonitor.OnError(ErrorStr: string); {$IFDEF MSWINDOWS} var Msg: TMonitorMessage; {$ENDIF} begin {$IFDEF MSWINDOWS} if FDBMonitor <> nil then begin with Msg do begin TracePoint := Integer(tpAfterEvent); EventType := Integer(etError); Description := ''; end; {$IFDEF CLR} FDBMonitor.OnEvent(Msg, ErrorStr); {$ELSE} FDBMonitor.OnEvent(Msg, PChar(ErrorStr)); {$ENDIF} end; {$ENDIF} end; procedure TCustomDASQLMonitor.OnCustomMessage(const St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); {$IFDEF MSWINDOWS} var Msg: TMonitorMessage; {$ENDIF} begin {$IFDEF MSWINDOWS} if FDBMonitor <> nil then begin with Msg do begin MessageID := AMessageID; EventType := Integer(etConnect); TracePoint := Integer(ATracePoint); ObjectID := GetComponentID(Component); OwnerID := 0; OwnerName := ''; {$IFDEF CLR} ObjectName := GetComponentName(Component); Description := St; FDBMonitor.OnEvent(Msg, ''); {$ELSE} ObjectName := PChar(GetComponentName(Component)); Description := PChar(St); FDBMonitor.OnEvent(Msg, nil); {$ENDIF} end; if ATracePoint = tpBeforeEvent then AMessageID := Msg.MessageID; end; {$ENDIF} end; procedure TCustomDASQLMonitor.PrepareExecuteMessage(const SQL: string; var Params: TSQLParams; const St: string; Component: TComponent; ATracePoint: TTracePoint; EventType: TEventType; var AMessageID: Cardinal); {$IFDEF MSWINDOWS} var RowsAffected: integer; Connection: TComponent; Msg: TMonitorMessage; {$IFNDEF CLR} PParam: PSQLParam; {$ENDIF} {$ENDIF} begin {$IFDEF MSWINDOWS} if FDBMonitor <> nil then begin RowsAffected := 0; if (Component is TCustomDASQL) then RowsAffected := TCustomDASQL(Component).RowsAffected else if (Component is TCustomDADataSet) then RowsAffected := TCustomDADataSet(Component).RowsAffected; Connection := GetParent(Component, 0); with Msg do begin MessageID := AMessageID; EventType := Integer(etExecute); TracePoint := Integer(ATracePoint); ObjectID := GetComponentID(Component); OwnerID := GetComponentID(Connection); {$IFDEF CLR} ObjectName := GetComponentName(Component); if Connection <> nil then OwnerName := GetComponentName(Connection) else OwnerName := ''; Description := St; FDBMonitor.OnExecute(Msg, SQL, Params, Length(Params), RowsAffected); {$ELSE} ObjectName := PChar(GetComponentName(Component)); if Connection <> nil then OwnerName := PChar(GetComponentName(Connection)) else OwnerName := ''; Description := PChar(St); PParam := nil; if Length(Params) > 0 then PParam := @Params[0]; FDBMonitor.OnExecute(Msg, PChar(SQL), PParam, Length(Params), RowsAffected); {$ENDIF} end; if ATracePoint = tpBeforeEvent then AMessageID := Msg.MessageID; end; {$ENDIF} end; procedure TCustomDASQLMonitor.OnExecute(const SQL: string; var Params: TSQLParams; const St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); begin PrepareExecuteMessage(SQL, Params, St, Component, ATracePoint, etExecute, AMessageID); end; procedure TCustomDASQLMonitor.OnPrepare(const SQL: string; var Params: TSQLParams; const St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); begin PrepareExecuteMessage(SQL, Params, St, Component, ATracePoint, etPrepare, AMessageID); end; procedure TCustomDASQLMonitor.OnUnprepare(const SQL: string; var Params: TSQLParams; const St: string; Component: TComponent; ATracePoint: TTracePoint; var AMessageID: Cardinal); begin PrepareExecuteMessage(SQL, Params, St, Component, ATracePoint, etPrepare, AMessageID); end; procedure TCustomDASQLMonitor.OnTransact(const St: string; Component: TComponent; TransactEvent: integer; ATracePoint: TTracePoint; var AMessageID: Cardinal); {$IFDEF MSWINDOWS} var Msg: TMonitorMessage; i: integer; Parent: TComponent; {$ENDIF} begin {$IFDEF MSWINDOWS} if FDBMonitor <> nil then begin with Msg do begin MessageID := AMessageID; case TransactEvent of teCommit: EventType := Integer(etCommit); teRollback: EventType := Integer(etRollback); else EventType := Integer(etMisc); end; TracePoint := Integer(ATracePoint); ObjectID := GetComponentID(Component); {$IFDEF CLR} ObjectName := GetComponentName(Component); Description := St; {$ELSE} ObjectName := PChar(GetComponentName(Component)); Description := PChar(St); {$ENDIF} for i := 0 to GetParentCount(Component) - 1 do begin Parent := GetParent(Component, i); OwnerID := GetComponentID(Parent); if Parent <> nil then OwnerName := {$IFNDEF CLR}PChar{$ENDIF}(GetComponentName(Parent)) else OwnerName := ''; {$IFDEF CLR} FDBMonitor.OnEvent(Msg, ''); {$ELSE} FDBMonitor.OnEvent(Msg, nil) {$ENDIF} end; end; if ATracePoint = tpBeforeEvent then AMessageID := Msg.MessageID; end; {$ENDIF} end; class function TCustomDASQLMonitor.HasMonitor: boolean; begin Result := GetMonitor <> nil; end; procedure TCustomDASQLMonitor.Loaded; begin inherited Loaded; CheckActive; end; procedure TCustomDASQLMonitor.CheckActive; begin Active := FStreamedActive; end; initialization ShowDebugFormProc := nil; end.