1 {*********************************************************}
3 { Zeos Database Objects }
5 {*********************************************************}
7 {@********************************************************}
8 { Copyright (c) 1999-2012 Zeos Development Group }
10 { License Agreement: }
12 { This library is distributed in the hope that it will be }
13 { useful, but WITHOUT ANY WARRANTY; without even the }
14 { implied warranty of MERCHANTABILITY or FITNESS FOR }
15 { A PARTICULAR PURPOSE. See the GNU Lesser General }
16 { Public License for more details. }
18 { The source code of the ZEOS Libraries and packages are }
19 { distributed under the Library GNU General Public }
20 { License (see the file COPYING / COPYING.ZEOS) }
21 { with the following modification: }
22 { As a special exception, the copyright holders of this }
23 { library give you permission to link this library with }
24 { independent modules to produce an executable, }
25 { regardless of the license terms of these independent }
26 { modules, and to copy and distribute the resulting }
27 { executable under terms of your choice, provided that }
28 { you also meet, for each linked independent module, }
29 { the terms and conditions of the license of that module. }
30 { An independent module is a module which is not derived }
31 { from or based on this library. If you modify this }
32 { library, you may extend this exception to your version }
33 { of the library, but you are not obligated to do so. }
34 { If you do not wish to do so, delete this exception }
35 { statement from your version. }
38 { The project web site is located on: }
39 { http://zeos.firmos.at (FORUM) }
40 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
41 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
43 { http://www.sourceforge.net/projects/zeoslib. }
46 { Zeos Development Group. }
47 {********************************************************@}
58 Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Contnrs, DateUtils, SysUtils, Types,
60 ZCompatibility, ZClasses, ZURL, ZDbcConnection, ZDbcIntfs, ZPlainDriver,
64 TConnectionPool = class;
66 { This class searchs for timed out connections in a pool and destroy them.
67 Maybe it would be nice to have a global instance to check all pools. This
68 way, we could avoid creating many threads. }
69 TConnectionTimeoutThread = class(TThread)
71 FConnectionPool: TConnectionPool;
73 procedure Execute; override;
75 constructor Create(const ConnectionPool: TConnectionPool);
78 { This class keeps a pool of connections which shares the same URL.
79 When a new connection is needed, it looks first if there is an available
80 connection in the pool, and returns it. If there is no connection available,
81 it creates a new one. Each created connection will be returned automatically
82 to the pool when it is not used anymore. }
83 TConnectionPool = class
85 FConnections: array of IZConnection;
86 FConnectionsReturnTimes: array of TDateTime;
88 FConnectionTimeout: Integer;
89 FConnectionTimeoutThread: TConnectionTimeoutThread;
90 FCriticalSection: TCriticalSection;
91 FCriticalSectionDriverManager: TCriticalSection;
92 FDefaultAutoCommit: Boolean;
93 FDefaultTransactIsolationLevel: TZTransactIsolationLevel;
94 FMaxConnections: Integer;
101 How many time a pooled connection will be kept in the pool. Zero = infinite
103 The maximum numbers of connections this pool will hold. Zero = infinite
105 True - When a pool reach its maximum number of connections and someone
106 tries to acquire a new one, it waits until a connection is
108 False - Raises an exception instead of wait }
109 constructor Create(const URL: string; const ConnectionTimeout: Integer = 0; const MaxConnections: Integer = 0; const Wait: Boolean = True);
110 destructor Destroy; override;
111 function Acquire: IZConnection;
112 procedure ReturnToPool(const Connection: IZConnection);
115 { This class embedds a real connection and redirects all methods to it.
116 When it is droped or closed, it returns the real connection to the pool. }
118 { TZDbcPooledConnection }
120 TZDbcPooledConnection = class(TZCodePagedObject, IZConnection)
122 FConnection: IZConnection;
123 FConnectionPool: TConnectionPool;
124 FAutoEncodeStrings: Boolean;
125 FUseMetadata: Boolean;
126 {$IFDEF ZEOS_TEST_ONLY}
129 function GetConnection: IZConnection;
130 protected // IZConnection
131 FClientCodePage: String;
132 procedure CheckCharEncoding(CharSet: String;
133 const DoArrange: Boolean = False);
134 function GetClientCodePageInformations: PZCodePage; //EgonHugeist
135 function GetAutoEncodeStrings: Boolean; //EgonHugeist
136 procedure SetAutoEncodeStrings(const Value: Boolean);
137 function CreateStatement: IZStatement;
138 function PrepareStatement(const SQL: string): IZPreparedStatement;
139 function PrepareCall(const SQL: string): IZCallableStatement;
140 function CreateStatementWithParams(Info: TStrings): IZStatement;
141 function PrepareStatementWithParams(const SQL: string; Info: TStrings): IZPreparedStatement;
142 function PrepareCallWithParams(const SQL: string; Info: TStrings): IZCallableStatement;
143 function CreateNotification(const Event: string): IZNotification;
144 function CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence;
145 function NativeSQL(const SQL: string): string;
146 procedure SetAutoCommit(Value: Boolean);
147 function GetAutoCommit: Boolean;
150 procedure PrepareTransaction(const transactionid: string);
151 procedure CommitPrepared(const transactionid: string);
152 procedure RollbackPrepared(const transactionid: string);
153 function PingServer: Integer;
154 function EscapeString(Value : RawByteString) : RawByteString;
157 function IsClosed: Boolean;
158 function GetDriver: IZDriver;
159 function GetIZPlainDriver: IZPlainDriver;
160 function GetMetadata: IZDatabaseMetadata;
161 function GetParameters: TStrings;
162 function GetClientVersion: Integer;
163 function GetHostVersion: Integer;
164 procedure SetReadOnly(Value: Boolean);
165 function IsReadOnly: Boolean;
166 procedure SetCatalog(const Value: string);
167 function GetCatalog: string;
168 procedure SetTransactionIsolation(Value: TZTransactIsolationLevel);
169 function GetTransactionIsolation: TZTransactIsolationLevel;
170 function GetWarnings: EZSQLWarning;
171 procedure ClearWarnings;
172 function UseMetadata: boolean;
173 procedure SetUseMetadata(Value: Boolean);
175 constructor Create(const ConnectionPool: TConnectionPool);
176 destructor Destroy; override;
177 function GetBinaryEscapeString(const Value: RawByteString): String; overload;
178 function GetBinaryEscapeString(const Value: TByteDynArray): String; overload;
179 function GetEscapeString(const Value: ZWideString): ZWideString; overload; virtual;
180 function GetEscapeString(const Value: RawByteString): RawByteString; overload; virtual;
181 function GetEncoding: TZCharEncoding;
182 function GetConSettings: PZConSettings;
183 {$IFDEF ZEOS_TEST_ONLY}
184 function GetTestMode : Byte;
185 procedure SetTestMode(Mode: Byte);
190 TZDbcPooledConnectionDriver = class(TZAbstractDriver)
192 PoolList: TObjectList;
193 URLList: TStringList;
194 function GetEmbeddedURL(const URL: String): String;
196 //function GetSupportedProtocols: TStringDynArray; override;
197 function Connect(const URL: TZURL): IZConnection; override;
198 function GetClientVersion(const URL: string): Integer; override;
199 function AcceptsURL(const URL: string): Boolean; override;
200 function GetPropertyInfo(const URL: string; Info: TStrings): TStrings; override;
201 function GetMajorVersion: Integer; override;
202 function GetMinorVersion: Integer; override;
203 function GetSubVersion: Integer; override;
205 constructor Create; override;
206 destructor Destroy; override;
212 constructor TConnectionPool.Create(const URL: string; const ConnectionTimeout: Integer = 0; const MaxConnections: Integer = 0; const Wait: Boolean = True);
217 FSlotsInUse := TBits.Create;
218 FCriticalSection := TCriticalSection.Create;
219 FCriticalSectionDriverManager := TCriticalSection.Create;
221 FMaxConnections := MaxConnections;
222 if FMaxConnections = 0 then
224 SetLength(FConnections, 10);
225 SetLength(FConnectionsReturnTimes, 10);
226 FSlotsInUse.Size := 10;
230 SetLength(FConnections, FMaxConnections);
231 SetLength(FConnectionsReturnTimes, FMaxConnections);
232 FSlotsInUse.Size := FMaxConnections;
236 // If there is a connection timeout, an instance of TConnectionTimeoutThread
237 // will monitor all unused connections and drop them when they timeout.
239 FConnectionTimeout := ConnectionTimeout;
240 if FConnectionTimeout <> 0 then
241 FConnectionTimeoutThread := TConnectionTimeoutThread.Create(Self);
244 destructor TConnectionPool.Destroy;
246 if FConnectionTimeoutThread <> nil then
248 FConnectionTimeoutThread.Terminate;
249 FConnectionTimeoutThread.WaitFor;
250 FConnectionTimeoutThread.Free;
253 SetLength(FConnections, 0);
255 FCriticalSection.Free;
256 FCriticalSectionDriverManager.Free;
261 function TConnectionPool.Acquire: IZConnection;
270 FCriticalSection.Enter;
272 // Try to get an existing connection
274 while I < FSlotsInUse.Size do
276 if (FConnections[I] <> nil) and (not FSlotsInUse[I]) then
279 // Test for dead connections
280 FConnections[I].Rollback; // PingServer did not work (tested with FB)
281 FSlotsInUse[I] := True;
284 // An exception can be raised when the dead connection is dropped
286 FConnections[I] := nil;
296 // Try to get a free slot if there is no existing connection available
297 if I = FSlotsInUse.Size then
300 while I < FSlotsInUse.Size do
302 if (FConnections[I] = nil) and (not FSlotsInUse[I]) then
304 FSlotsInUse[I] := True;
311 // Increase the pool if there is no free slot in the pool
312 if I = FSlotsInUse.Size then
314 if FMaxConnections = 0 then
316 SetLength(FConnections, Length(FConnections) + 10);
317 SetLength(FConnectionsReturnTimes, Length(FConnectionsReturnTimes) + 10);
318 FSlotsInUse.Size := FSlotsInUse.Size + 10;
319 FSlotsInUse[I] := True;
323 FCriticalSection.Leave;
326 if I < FSlotsInUse.Size then
329 // No connection available. Wait and try again later
333 raise Exception.Create(ClassName + '.Acquire'+LineEnding+'O pool de conexatingiu o limite maximo');
334 //2013-10-13 mse: please replace non ASCII characters (>127) by the
335 //#nnn notation in order to have encoding independent sources
339 // If there is no connection in the pool, create a new one.
340 // This block is separated from the block above because there could be some
341 // delay to create a connection, and it would not be nice to keep the critical
342 // section locked during this delay.
344 if FConnections[I] = nil then
347 // I had a strong feeling that DriverManager is not thread-safe, because i
348 // had random access violations on high load operations at this point.
349 // For now, i will serialize DriverManager access, until further
350 // investigation (maybe the problem is in the pool driver, as
351 // DriverManager should be thread-safe in essence.
352 FCriticalSectionDriverManager.Enter;
354 FConnections[I] := DriverManager.GetConnection(FURL);
356 FCriticalSectionDriverManager.Leave;
358 FConnections[I].Open;
362 FCriticalSection.Enter;
364 FSlotsInUse[I] := False;
365 FConnections[I] := nil;
367 FCriticalSection.Leave;
368 raise Exception.Create(ClassName + '.Acquire'+LineEnding+'Error while trying to acquire a new connection'+LineEnding+LineEnding+E.Message);
372 FDefaultAutoCommit := FConnections[I].GetAutoCommit;
373 FDefaultTransactIsolationLevel := FConnections[I].GetTransactionIsolation;
376 Result := IZConnection(FConnections[I]);
377 Result.SetAutoCommit(True);
378 Result.SetTransactionIsolation(tiReadCommitted);
381 procedure TConnectionPool.ReturnToPool(const Connection: IZConnection);
386 // Return the connection to the pool.
388 FCriticalSection.Enter;
390 for I := 0 to Length(FConnections) - 1 do
392 if FConnections[I] = Connection then
395 // If there is some problem with the connection, a RollBack will raise
396 // an exception, and the connection will be dropped.
399 FSlotsInUse[I] := False;
400 FConnectionsReturnTimes[I] := Now;
401 FConnections[I].Rollback;
404 FConnections[I] := nil;
412 FCriticalSection.Leave;
416 { TZDbcPooledConnection }
418 constructor TZDbcPooledConnection.Create(const ConnectionPool: TConnectionPool);
420 FConnectionPool := ConnectionPool;
421 {$IFDEF ZEOS_TEST_ONLY}
426 destructor TZDbcPooledConnection.Destroy;
428 if FConnection <> nil then
430 FConnectionPool.ReturnToPool(FConnection);
434 FConnectionPool := nil;
439 function TZDbcPooledConnection.GetConnection: IZConnection;
441 if FConnection = nil then
442 FConnection := FConnectionPool.Acquire;
443 Result := FConnection;
446 procedure TZDbcPooledConnection.ClearWarnings;
448 GetConnection.ClearWarnings;
451 function TZDbcPooledConnection.UseMetadata: boolean;
453 result := FUseMetadata;
456 procedure TZDbcPooledConnection.SetUseMetadata(Value: Boolean);
458 FUseMetadata := Value;
461 procedure TZDbcPooledConnection.Close;
463 if FConnection <> nil then
465 FConnectionPool.ReturnToPool(FConnection);
470 procedure TZDbcPooledConnection.Commit;
472 GetConnection.Commit;
475 procedure TZDbcPooledConnection.CommitPrepared(const transactionid: string);
477 GetConnection.CommitPrepared(transactionid);
480 function TZDbcPooledConnection.CreateNotification(const Event: string): IZNotification;
482 Result := GetConnection.CreateNotification(Event);
485 function TZDbcPooledConnection.CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence;
487 Result := GetConnection.CreateSequence(Sequence, BlockSize);
490 function TZDbcPooledConnection.CreateStatement: IZStatement;
492 Result := GetConnection.CreateStatement;
496 function TZDbcPooledConnection.CreateStatementWithParams(Info: TStrings): IZStatement;
498 Result := GetConnection.CreateStatementWithParams(Info);
501 function TZDbcPooledConnection.EscapeString(Value: RawByteString): RawByteString;
503 Result := GetConnection.EscapeString(Value);
506 function TZDbcPooledConnection.GetAutoCommit: Boolean;
508 Result := GetConnection.GetAutoCommit;
511 function TZDbcPooledConnection.GetCatalog: string;
513 Result := GetConnection.GetCatalog;
516 function TZDbcPooledConnection.GetClientVersion: Integer;
518 Result := GetConnection.GetClientVersion;
521 function TZDbcPooledConnection.GetDriver: IZDriver;
523 Result := GetConnection.GetDriver;
526 function TZDbcPooledConnection.GetIZPlainDriver: IZPlainDriver;
528 Result := GetConnection.GetIZPlainDriver;
531 function TZDbcPooledConnection.GetHostVersion: Integer;
533 Result := GetConnection.GetHostVersion;
536 function TZDbcPooledConnection.GetMetadata: IZDatabaseMetadata;
538 Result := GetConnection.GetMetadata;
541 function TZDbcPooledConnection.GetParameters: TStrings;
543 Result := GetConnection.GetParameters;
546 function TZDbcPooledConnection.GetTransactionIsolation: TZTransactIsolationLevel;
548 Result := GetConnection.GetTransactionIsolation;
551 function TZDbcPooledConnection.GetWarnings: EZSQLWarning;
553 Result := GetConnection.GetWarnings;
556 function TZDbcPooledConnection.IsClosed: Boolean;
558 Result := (FConnection = nil) or FConnection.IsClosed;
561 function TZDbcPooledConnection.IsReadOnly: Boolean;
563 Result := GetConnection.IsReadOnly;
566 function TZDbcPooledConnection.NativeSQL(const SQL: string): string;
568 Result := GetConnection.NativeSQL(SQL);
571 procedure TZDbcPooledConnection.Open;
576 function TZDbcPooledConnection.PingServer: Integer;
578 Result := GetConnection.PingServer;
581 function TZDbcPooledConnection.PrepareCall(const SQL: string): IZCallableStatement;
583 Result := GetConnection.PrepareCall(SQL);
586 function TZDbcPooledConnection.PrepareCallWithParams(const SQL: string; Info: TStrings): IZCallableStatement;
588 Result := GetConnection.PrepareCallWithParams(SQL, Info);
591 function TZDbcPooledConnection.PrepareStatement(const SQL: string): IZPreparedStatement;
593 Result := GetConnection.PrepareStatement(SQL);
596 function TZDbcPooledConnection.PrepareStatementWithParams(const SQL: string; Info: TStrings): IZPreparedStatement;
598 Result := GetConnection.PrepareStatementWithParams(SQL, Info);
601 procedure TZDbcPooledConnection.PrepareTransaction(const transactionid: string);
603 GetConnection.PrepareTransaction(transactionid);
606 procedure TZDbcPooledConnection.Rollback;
608 GetConnection.Rollback;
611 procedure TZDbcPooledConnection.RollbackPrepared(const transactionid: string);
613 GetConnection.RollbackPrepared(transactionid);
616 procedure TZDbcPooledConnection.SetAutoCommit(Value: Boolean);
618 GetConnection.SetAutoCommit(Value);
621 procedure TZDbcPooledConnection.SetCatalog(const Value: string);
623 GetConnection.SetCatalog(Value);
626 procedure TZDbcPooledConnection.SetReadOnly(Value: Boolean);
628 GetConnection.SetReadOnly(Value);
631 procedure TZDbcPooledConnection.SetTransactionIsolation(Value: TZTransactIsolationLevel);
633 GetConnection.SetTransactionIsolation(Value);
637 EgonHugeist: Check if the given Charset for Compiler/Database-Support!!
638 Not supported means if there is a pissible String-DataLoss.
639 So it raises an Exception if case of settings. This handling
640 is an improofment to inform Zeos-Users about the troubles the given
641 CharacterSet may have.
642 @param CharSet the CharacterSet which has to be proofed
643 @param DoArrange represents a switch to check and set a aternative ZAlias as
644 default. This means it ignores the choosen Client-CharacterSet and sets a
645 "more" Zeos-Compatible Client-CharacterSet if known.
647 procedure TZDbcPooledConnection.CheckCharEncoding(CharSet: String;
648 const DoArrange: Boolean = False);
650 Self.GetConSettings.ClientCodePage := GetIZPlainDriver.ValidateCharEncoding(CharSet, DoArrange);
651 FClientCodePage := ConSettings.ClientCodePage^.Name; //resets the developer choosen ClientCodePage
656 EgonHugeist: this is a compatibility-Option for exiting Applictions.
657 Zeos is now able to preprepare direct insered SQL-Statements.
658 Means do the UTF8-preparation if the CharacterSet was choosen.
659 So we do not need to do the SQLString + UTF8Encode(Edit1.Test) for example.
660 @result True if coAutoEncodeStrings was choosen in the TZAbstractConnection
662 function TZDbcPooledConnection.GetAutoEncodeStrings: Boolean;
664 Result := FAutoEncodeStrings;
667 procedure TZDbcPooledConnection.SetAutoEncodeStrings(const Value: Boolean);
669 FAutoEncodeStrings := Value;
674 Returns the BinaryString in a Tokenizer-detectable kind
675 If the Tokenizer don't need to predetect it Result = BinaryString
676 @param Value represents the Binary-String
677 @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3)
678 @result the detectable Binary String
680 function TZDbcPooledConnection.GetBinaryEscapeString(const Value: RawByteString): String;
682 Result := GetConnection.GetBinaryEscapeString(Value);
685 function TZDbcPooledConnection.GetBinaryEscapeString(const Value: TByteDynArray): String;
687 Result := GetConnection.GetBinaryEscapeString(Value);
690 function TZDbcPooledConnection.GetEscapeString(const Value: ZWideString): ZWideString;
692 Result := GetConnection.GetEscapeString(Value);
695 function TZDbcPooledConnection.GetEscapeString(const Value: RawByteString): RawByteString;
697 Result := GetConnection.GetEscapeString(Value);
700 function TZDbcPooledConnection.GetEncoding: TZCharEncoding;
702 Result := ConSettings.ClientCodePage^.Encoding;
705 function TZDbcPooledConnection.GetConSettings: PZConSettings;
707 Result := @ConSettings;
710 {$IFDEF ZEOS_TEST_ONLY}
711 function TZDbcPooledConnection.GetTestMode: Byte;
716 procedure TZDbcPooledConnection.SetTestMode(Mode: Byte);
723 Result 100% Compiler-Compatible
724 And sets it Result to ClientCodePage by calling the
725 PlainDriver.GetClientCodePageInformations function
727 @param ClientCharacterSet the CharacterSet which has to be checked
728 @result PZCodePage see ZCompatible.pas
730 function TZDbcPooledConnection.GetClientCodePageInformations: PZCodePage; //EgonHugeist
732 Result := ConSettings.ClientCodePage
735 { TZDbcPooledConnectionDriver }
737 constructor TZDbcPooledConnectionDriver.Create;
741 PoolList := TObjectList.Create(True);
742 URLList := TStringList.Create;
743 AddSupportedProtocol(PooledPrefix + '*');
746 destructor TZDbcPooledConnectionDriver.Destroy;
754 function TZDbcPooledConnectionDriver.AcceptsURL(const URL: string): Boolean;
756 Result := Copy(URL, 1, 5 + Length(PooledPrefix)) = 'zdbc:' + PooledPrefix;
759 function TZDbcPooledConnectionDriver.Connect(const URL: TZURL): IZConnection;
763 ConnectionPool: TConnectionPool;
764 ConnetionTimeout: Integer;
765 MaxConnections: Integer;
770 TempURL := TZURL.Create;
772 TempURL.URL := GetEmbeddedURL(URL.URL);
773 TempURL.Properties.Text := URL.Properties.Text;
775 ConnectionPool := nil;
778 - Read and process connection properties 'timeout', 'poolsize' and 'wait' }
781 // Search for an existing pool for the URL.
782 // There is room to improve the algorithm used to decide when a pool is
783 // compatible with a given URL. For now, i am just comparing the URL strings.
785 for I := 0 to PoolList.Count - 1 do
786 if URLList[I] = TempURL.URL then
788 ConnectionPool := TConnectionPool(PoolList[I]);
793 // Create a new pool if needed.
795 if ConnectionPool = nil then
797 ConnetionTimeout := StrToIntDef(TempURL.Properties.Values['ConnectionTimeout'], 0);
798 MaxConnections := StrToIntDef(TempURL.Properties.Values['MaxConnections'], 0);
799 Wait := StrToBoolDef(TempURL.Properties.Values['Wait'], True);
800 ConnectionPool := TConnectionPool.Create(TempURL.URL, ConnetionTimeout, MaxConnections, Wait);
801 PoolList.Add(ConnectionPool);
802 URLList.Add(TempURL.URL);
805 Result := TZDbcPooledConnection.Create(ConnectionPool);
811 function TZDbcPooledConnectionDriver.GetClientVersion(const URL: string): Integer;
813 Result := DriverManager.GetDriver(GetEmbeddedURL(URL)).GetClientVersion(GetEmbeddedURL(URL));
816 function TZDbcPooledConnectionDriver.GetMajorVersion: Integer;
821 function TZDbcPooledConnectionDriver.GetMinorVersion: Integer;
826 function TZDbcPooledConnectionDriver.GetPropertyInfo(const URL: string; Info: TStrings): TStrings;
828 Result := DriverManager.GetDriver(GetEmbeddedURL(URL)).GetPropertyInfo(GetEmbeddedURL(URL), Info);
830 Result := TStringList.Create;
831 Result.Values['ConnectionTimeout'] := '0';
832 Result.Values['MaxConnections'] := '0';
833 Result.Values['Wait'] := 'True';
836 function TZDbcPooledConnectionDriver.GetSubVersion: Integer;
841 {function TZDbcPooledConnectionDriver.GetSupportedProtocols: TStringDynArray;
843 SetLength(Result, 1);
844 Result[0] := PooledPrefix + '*';
847 function TZDbcPooledConnectionDriver.GetEmbeddedURL(const URL: String): String;
849 if Copy(URL, 1, 5 + Length(PooledPrefix)) = 'zdbc:' + PooledPrefix then
850 Result := 'zdbc:' + Copy(URL, 5 + Length(PooledPrefix) + 1, Length(URL))
852 raise Exception.Create('TZDbcPooledConnectionDriver.GetRealURL - URL must start with ''zdbc:' + PooledPrefix+ '''');
858 { TConnectionTimeoutThread }
860 constructor TConnectionTimeoutThread.Create(const ConnectionPool: TConnectionPool);
862 inherited Create(False);
864 FConnectionPool := ConnectionPool;
865 FreeOnTerminate := False;
868 procedure TConnectionTimeoutThread.Execute;
872 while not Terminated do
877 // Check if there are timed out connections and releases them
879 FConnectionPool.FCriticalSection.Enter;
881 for I := 0 to Length(FConnectionPool.FConnections) - 1 do
882 if (FConnectionPool.FConnections[I] <> nil) and
883 (not FConnectionPool.FSlotsInUse[I]) and
884 (FConnectionPool.FConnectionsReturnTimes[I] <> 0) and
885 (MilliSecondsBetween(FConnectionPool.FConnectionsReturnTimes[I], Now) > FConnectionPool.FConnectionTimeout * 1000) then
886 FConnectionPool.FConnections[I] := nil;
888 FConnectionPool.FCriticalSection.Leave;
894 _Driver := TZDbcPooledConnectionDriver.Create;
895 DriverManager.RegisterDriver(_Driver);
898 DriverManager.DeregisterDriver(_Driver);