📄 ibsqlmonitor.pas
字号:
{************************************************************************}
{ }
{ Borland Delphi Visual Component Library }
{ InterBase Express core components }
{ }
{ Copyright (c) 1998-2001 Borland Software Corporation }
{ }
{ InterBase Express is based in part on the product }
{ Free IB Components, written by Gregory H. Deatz for }
{ Hoagland, Longo, Moran, Dunst & Doukas Company. }
{ Free IB Components is used under license. }
{ }
{ The contents of this file are subject to the InterBase }
{ Public License Version 1.0 (the "License"); you may not }
{ use this file except in compliance with the License. You may obtain }
{ a copy of the License at http://www.borland.com/interbase/IPL.html }
{ Software distributed under the License is distributed on }
{ an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
{ express or implied. See the License for the specific language }
{ governing rights and limitations under the License. }
{ The Original Code was created by InterBase Software Corporation }
{ and its successors. }
{ Portions created by Borland Software Corporation are Copyright }
{ (C) Borland Software Corporation. All Rights Reserved. }
{ Contributor(s): Jeff Overcash }
{ }
{************************************************************************}
unit IBSQLMonitor;
interface
uses
SysUtils,
{$IFDEF MSWINDOWS}
Windows, Messages,
{$ENDIF}
{$IFDEF LINUX}
Libc, QForms,
{$ENDIF}
Classes, IB, IBUtils, IBSQL, IBCustomDataSet, IBDatabase, IBServices, IBXConst;
{$IFDEF MSWINDOWS}
const
WM_MIN_IBSQL_MONITOR = WM_USER;
WM_MAX_IBSQL_MONITOR = WM_USER + 512;
WM_IBSQL_SQL_EVENT = WM_MIN_IBSQL_MONITOR + 1;
{$ENDIF}
type
TIBCustomSQLMonitor = class;
{ TIBSQLMonitor }
TSQLEvent = procedure(EventText: String; EventTime : TDateTime) of object;
TIBCustomSQLMonitor = class(TComponent)
private
{$IFDEF MSWINDOWS}
FHWnd: HWND;
{$ENDIF}
FOnSQLEvent: TSQLEvent;
FTraceFlags: TTraceFlags;
FEnabled: Boolean;
{$IFDEF MSWINDOWS}
procedure MonitorWndProc(var Message : TMessage);
{$ENDIF}
procedure SetEnabled(const Value: Boolean);
protected
property OnSQL: TSQLEvent read FOnSQLEvent write FOnSQLEvent;
property TraceFlags: TTraceFlags read FTraceFlags write FTraceFlags;
property Enabled : Boolean read FEnabled write SetEnabled default true;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Release;
{$IFDEF MSWINDOWS}
property Handle : HWND read FHwnd;
{$ENDIF}
end;
TIBSQLMonitor = class(TIBCustomSQLMonitor)
published
property OnSQL;
property TraceFlags;
property Enabled;
end;
IIBSQLMonitorHook = interface
['{CF65434C-9B75-4298-BA7E-E6B85B3C769D}']
procedure RegisterMonitor(SQLMonitor : TIBCustomSQLMonitor);
procedure UnregisterMonitor(SQLMonitor : TIBCustomSQLMonitor);
procedure ReleaseMonitor(Arg : TIBCustomSQLMonitor);
procedure SQLPrepare(qry: TIBSQL);
procedure SQLExecute(qry: TIBSQL);
procedure SQLFetch(qry: TIBSQL);
procedure DBConnect(db: TIBDatabase);
procedure DBDisconnect(db: TIBDatabase);
procedure TRStart(tr: TIBTransaction);
procedure TRCommit(tr: TIBTransaction);
procedure TRCommitRetaining(tr: TIBTransaction);
procedure TRRollback(tr: TIBTransaction);
procedure TRRollbackRetaining(tr: TIBTransaction);
procedure ServiceAttach(service: TIBCustomService);
procedure ServiceDetach(service: TIBCustomService);
procedure ServiceQuery(service: TIBCustomService);
procedure ServiceStart(service: TIBCustomService);
procedure SendMisc(Msg : String);
function GetTraceFlags : TTraceFlags;
function GetMonitorCount : Integer;
procedure SetTraceFlags(const Value : TTraceFlags);
function GetEnabled : boolean;
procedure SetEnabled(const Value : Boolean);
property TraceFlags: TTraceFlags read GetTraceFlags write SetTraceFlags;
property Enabled : Boolean read GetEnabled write SetEnabled;
end;
function MonitorHook: IIBSQLMonitorHook;
procedure EnableMonitoring;
procedure DisableMonitoring;
function MonitoringEnabled: Boolean;
implementation
uses
contnrs, IBHeader, Db;
type
{ TIBSQLMonitorHook }
TIBSQLMonitorHook = class(TInterfacedObject, IIBSQLMonitorHook)
private
FTraceFlags: TTraceFlags;
FEnabled: Boolean;
FEventsCreated : Boolean;
procedure CreateEvents;
protected
procedure WriteSQLData(Text: String; DataType: TTraceFlag);
public
constructor Create;
destructor Destroy; override;
procedure RegisterMonitor(SQLMonitor : TIBCustomSQLMonitor);
procedure UnregisterMonitor(SQLMonitor : TIBCustomSQLMonitor);
procedure ReleaseMonitor(Arg : TIBCustomSQLMonitor);
procedure SQLPrepare(qry: TIBSQL); virtual;
procedure SQLExecute(qry: TIBSQL); virtual;
procedure SQLFetch(qry: TIBSQL); virtual;
procedure DBConnect(db: TIBDatabase); virtual;
procedure DBDisconnect(db: TIBDatabase); virtual;
procedure TRStart(tr: TIBTransaction); virtual;
procedure TRCommit(tr: TIBTransaction); virtual;
procedure TRCommitRetaining(tr: TIBTransaction); virtual;
procedure TRRollback(tr: TIBTransaction); virtual;
procedure TRRollbackRetaining(tr: TIBTransaction); virtual;
procedure ServiceAttach(service: TIBCustomService); virtual;
procedure ServiceDetach(service: TIBCustomService); virtual;
procedure ServiceQuery(service: TIBCustomService); virtual;
procedure ServiceStart(service: TIBCustomService); virtual;
procedure SendMisc(Msg : String);
function GetEnabled: Boolean;
function GetTraceFlags: TTraceFlags;
function GetMonitorCount : Integer;
procedure SetEnabled(const Value: Boolean);
procedure SetTraceFlags(const Value: TTraceFlags);
property TraceFlags: TTraceFlags read GetTraceFlags write SetTraceFlags;
property Enabled : Boolean read GetEnabled write SetEnabled default true;
end;
{ There are two possible objects. One is a trace message object.
This object holds the flag of the trace type plus the message.
The second object is a Release object. It holds the handle that
the CM_RELEASE message is to be queued to. }
TTraceObject = Class(TObject)
FDataType : TTraceFlag;
FMsg : String;
FTimeStamp : TDateTime;
public
constructor Create(Msg : String; DataType : TTraceFlag); overload;
constructor Create(obj : TTraceObject); overload;
end;
TReleaseObject = Class(TObject)
FHandle : THandle;
public
constructor Create(Handle : THandle);
end;
TWriterThread = class(TThread)
private
{ Private declarations }
FMsgs : TObjectList;
protected
procedure Lock;
Procedure Unlock;
procedure BeginWrite;
procedure EndWrite;
procedure Execute; override;
procedure WriteToBuffer;
public
constructor Create;
destructor Destroy; override;
procedure WriteSQLData(Msg : String; DataType : TTraceFlag);
procedure ReleaseMonitor(HWnd : THandle);
end;
TReaderThread = class(TThread)
private
st : TTraceObject;
FMonitors : TObjectList;
{ Private declarations }
protected
procedure BeginRead;
procedure EndRead;
procedure ReadSQLData;
procedure Execute; override;
public
constructor Create;
destructor Destroy; override;
procedure AddMonitor(Arg : TIBCustomSQLMonitor);
procedure RemoveMonitor(Arg : TIBCustomSQLMonitor);
end;
const
CM_BASE = $B000;
CM_RELEASE = CM_BASE + 33;
MonitorHookNames: array[0..5] of String = (
'IB.SQL.MONITOR.Mutex4_1', {do not localize}
'IB.SQL.MONITOR.SharedMem4_1', {do not localize}
'IB.SQL.MONITOR.WriteEvent4_1', {do not localize}
'IB.SQL.MONITOR.WriteFinishedEvent4_1', {do not localize}
'IB.SQL.MONITOR.ReadEvent4_1', {do not localize}
'IB.SQL.MONITOR.ReadFinishedEvent4_1' {do not localize}
);
cMonitorHookSize = 1024;
cMaxBufferSize = cMonitorHookSize - (4 * SizeOf(Integer)) - SizeOf(TDateTime);
cDefaultTimeout = 500; { 1 seconds }
var
FSharedBuffer,
FWriteLock,
FWriteEvent,
FWriteFinishedEvent,
FReadEvent,
FReadFinishedEvent : THandle;
FBuffer : PChar;
FMonitorCount,
FReaderCount,
FTraceDataType,
FBufferSize : PInteger;
FTimeStamp : PDateTime;
FWriterThread : TWriterThread;
FReaderThread : TReaderThread;
_MonitorHook: TIBSQLMonitorHook;
bDone: Boolean;
CS : TRTLCriticalSection;
{ TIBCustomSQLMonitor }
constructor TIBCustomSQLMonitor.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FTraceFlags := [tfqPrepare .. tfMisc];
FEnabled := true;
if not (csDesigning in ComponentState) then
begin
{$IFDEF MSWINDOWS}
FHWnd := AllocateHWnd(MonitorWndProc);
{$ENDIF}
MonitorHook.RegisterMonitor(self);
end;
end;
destructor TIBCustomSQLMonitor.Destroy;
begin
if not (csDesigning in ComponentState) then
begin
if FEnabled then
MonitorHook.UnregisterMonitor(self);
{$IFDEF MSWINDOWS}
DeallocateHwnd(FHWnd);
{$ENDIF}
end;
inherited Destroy;
end;
{$IFDEF MSWINDOWS}
procedure TIBCustomSQLMonitor.MonitorWndProc(var Message: TMessage);
var
st : TTraceObject;
begin
case Message.Msg of
WM_IBSQL_SQL_EVENT:
begin
st := TTraceObject(Message.LParam);
if (Assigned(FOnSQLEvent)) and
(st.FDataType in FTraceFlags) then
FOnSQLEvent(st.FMsg, st.FTimeStamp);
st.Free;
end;
CM_RELEASE :
Free;
else
DefWindowProc(FHWnd, Message.Msg, Message.WParam, Message.LParam);
end;
end;
{$ENDIF}
procedure TIBCustomSQLMonitor.Release;
begin
MonitorHook.ReleaseMonitor(self);
end;
procedure TIBCustomSQLMonitor.SetEnabled(const Value: Boolean);
begin
if Value <> FEnabled then
begin
FEnabled := Value;
if not (csDesigning in ComponentState) then
if FEnabled then
Monitorhook.RegisterMonitor(self)
else
MonitorHook.UnregisterMonitor(self);
end;
end;
{ TIBSQLMonitorHook }
constructor TIBSQLMonitorHook.Create;
begin
inherited Create;
FEventsCreated := false;
FTraceFlags := [tfQPrepare..tfMisc];
FEnabled := true;
end;
procedure TIBSQLMonitorHook.CreateEvents;
{$IFDEF MSWINDOWS}
var
Sa : TSecurityAttributes;
Sd : TSecurityDescriptor;
function OpenLocalEvent(Idx: Integer): THandle;
begin
result := OpenEvent(EVENT_ALL_ACCESS, true, PChar(MonitorHookNames[Idx]));
if result = 0 then
IBError(ibxeCannotCreateSharedResource, [GetLastError]);
end;
function CreateLocalEvent(Idx: Integer; InitialState: Boolean): THandle;
begin
result := CreateEvent(@sa, true, InitialState, PChar(MonitorHookNames[Idx]));
if result = 0 then
IBError(ibxeCannotCreateSharedResource, [GetLastError]);
end;
begin
{ Setup Secureity so anyone can connect to the MMF/Mutex/Events. This is
needed when IBX is used in a Service. }
InitializeSecurityDescriptor(@Sd,SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(@Sd,true,nil,false);
Sa.nLength := SizeOf(Sa);
Sa.lpSecurityDescriptor := @Sd;
Sa.bInheritHandle := true;
FSharedBuffer := CreateFileMapping($FFFFFFFF, @sa, PAGE_READWRITE,
0, cMonitorHookSize, PChar(MonitorHookNames[1]));
if GetLastError = ERROR_ALREADY_EXISTS then
begin
FSharedBuffer := OpenFileMapping(FILE_MAP_ALL_ACCESS, false, PChar(MonitorHookNames[1]));
if (FSharedBuffer = 0) then
IBError(ibxeCannotCreateSharedResource, [GetLastError]);
FBuffer := MapViewOfFile(FSharedBuffer, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if FBuffer = nil then
IBError(ibxeCannotCreateSharedResource, [GetLastError]);
FMonitorCount := PInteger(FBuffer + cMonitorHookSize - SizeOf(Integer));
FReaderCount := PInteger(PChar(FMonitorCount) - SizeOf(Integer));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -