-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathu_StatementHandleCache.pas
242 lines (210 loc) · 6.07 KB
/
u_StatementHandleCache.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
unit u_StatementHandleCache;
interface
uses
Windows,
SysUtils,
Classes,
odbcsql,
i_StatementHandleCache;
type
TStatementNotifyProc = procedure (Ptr: Pointer; Action: TListNotification) of object;
TStatementList = class(TList)
private
FOnNotify: TStatementNotifyProc;
protected
procedure Notify(Ptr: Pointer; Action: TListNotification); override;
public
function ExtractLast(var APtr: Pointer): Boolean;
end;
TStatementHandleNonCached = class(TInterfacedObject, IStatementHandleCache)
protected
FDBCHandlePtr: PSQLHandle;
protected
{ IStatementHandleCache }
procedure FreeStatement(const AStatementHandle: SQLHANDLE); virtual;
function GetStatementHandle(var AStatementHandle: SQLHANDLE): SQLRETURN; virtual;
procedure SyncStatements; virtual;
procedure GetStatistics(out AUsedCount, AUnusedCount: Integer); virtual;
public
constructor Create(
const ADBCHandlePtr: PSQLHandle
);
end;
TStatementHandleCache = class(TStatementHandleNonCached, IStatementHandleCache)
private
FSync: IReadWriteSync;
FUsedList: TStatementList;
FUnusedList: TStatementList;
private
procedure DoOnNotify(Ptr: Pointer; Action: TListNotification);
protected
procedure CleanupStatementToKeepInList(const AStatementHandle: SQLHANDLE); virtual;
protected
{ IStatementHandleCache }
procedure FreeStatement(const AStatementHandle: SQLHANDLE); override;
function GetStatementHandle(var AStatementHandle: SQLHANDLE): SQLRETURN; override;
procedure SyncStatements; override;
procedure GetStatistics(out AUsedCount, AUnusedCount: Integer); override;
public
constructor Create(
const ADBCHandlePtr: PSQLHandle
);
destructor Destroy; override;
end;
TStatementFetchableCache = class(TStatementHandleCache)
protected
procedure CleanupStatementToKeepInList(const AStatementHandle: SQLHANDLE); override;
end;
implementation
uses
u_Synchronizer;
{ TStatementHandleCache }
procedure TStatementHandleCache.CleanupStatementToKeepInList(const AStatementHandle: SQLHANDLE);
begin
// ïóñòî!
end;
constructor TStatementHandleCache.Create(const ADBCHandlePtr: PSQLHandle);
begin
inherited Create(ADBCHandlePtr);
FSync := MakeSyncRW_Var(Self, False);
FUsedList := TStatementList.Create;
FUsedList.FOnNotify := DoOnNotify;
FUnusedList := TStatementList.Create;
FUnusedList.FOnNotify := DoOnNotify;
end;
destructor TStatementHandleCache.Destroy;
begin
FSync.BeginWrite;
try
// free all items
FUnusedList.Clear;
FreeAndNil(FUnusedList);
FUsedList.Clear;
FreeAndNil(FUsedList);
finally
FSync.EndWrite;
end;
inherited;
FSync := nil;
end;
procedure TStatementHandleCache.DoOnNotify(Ptr: Pointer; Action: TListNotification);
begin
if (lnDeleted=Action) then begin
// free statement handle
inherited FreeStatement(Ptr);
end;
end;
procedure TStatementHandleCache.FreeStatement(const AStatementHandle: SQLHANDLE);
var
VUsedPtr: Pointer;
begin
FSync.BeginWrite;
try
// extract from used list ...
VUsedPtr := FUsedList.Extract(AStatementHandle);
if (VUsedPtr<>nil) then begin
// ... and put to unused
FUnusedList.Add(AStatementHandle);
// cleanup internals
CleanupStatementToKeepInList(AStatementHandle);
end else begin
// ... bit if not found - free statement
inherited FreeStatement(AStatementHandle);
end;
finally
FSync.EndWrite;
end;
end;
function TStatementHandleCache.GetStatementHandle(var AStatementHandle: SQLHANDLE): SQLRETURN;
begin
FSync.BeginWrite;
try
// if has unused ...
if FUnusedList.ExtractLast(AStatementHandle) then begin
// ... get it
Result := SQL_SUCCESS;
end else begin
// else make new
Result := inherited GetStatementHandle(AStatementHandle);
if not SQL_SUCCEEDED(Result) then
Exit;
end;
// put it to list of used statements
FUsedList.Add(AStatementHandle);
finally
FSync.EndWrite;
end;
end;
procedure TStatementHandleCache.GetStatistics(out AUsedCount, AUnusedCount: Integer);
begin
//inherited;
FSync.BeginRead;
try
AUsedCount := FUsedList.Count;
AUnusedCount := FUnusedList.Count;
finally
FSync.EndRead;
end;
end;
procedure TStatementHandleCache.SyncStatements;
begin
//inherited;
FSync.BeginWrite;
try
// clear list of unused statements
FUnusedList.Clear;
finally
FSync.EndWrite;
end;
end;
{ TStatementList }
function TStatementList.ExtractLast(var APtr: Pointer): Boolean;
begin
Result := (Count>0);
if Result then begin
APtr := List^[(Count-1)];
List[(Count-1)] := nil;
Delete(Count-1);
Notify(APtr, lnExtracted);
end else begin
APtr := nil;
end;
end;
procedure TStatementList.Notify(Ptr: Pointer; Action: TListNotification);
begin
inherited;
FOnNotify(Ptr, Action);
end;
{ TStatementHandleNonCached }
constructor TStatementHandleNonCached.Create(const ADBCHandlePtr: PSQLHandle);
begin
inherited Create;
FDBCHandlePtr := ADBCHandlePtr;
end;
procedure TStatementHandleNonCached.FreeStatement(const AStatementHandle: SQLHANDLE);
begin
// free handle
SQLFreeHandle(SQL_HANDLE_STMT, AStatementHandle);
end;
function TStatementHandleNonCached.GetStatementHandle(var AStatementHandle: SQLHANDLE): SQLRETURN;
begin
// allocate handle
Result := SQLAllocHandle(SQL_HANDLE_STMT, FDBCHandlePtr^, AStatementHandle);
end;
procedure TStatementHandleNonCached.GetStatistics(out AUsedCount, AUnusedCount: Integer);
begin
AUsedCount := 0;
AUnusedCount := 0;
end;
procedure TStatementHandleNonCached.SyncStatements;
begin
// empty!
end;
{ TStatementFetchableCache }
procedure TStatementFetchableCache.CleanupStatementToKeepInList(const AStatementHandle: SQLHANDLE);
begin
SQLFreeStmt(AStatementHandle, SQL_CLOSE);
SQLFreeStmt(AStatementHandle, SQL_UNBIND);
SQLFreeStmt(AStatementHandle, SQL_RESET_PARAMS);
end;
end.