1 {*********************************************************}
3 { Zeos Database Objects }
4 { ADO Connectivity Classes }
6 { Originally written by Janos Fegyverneki }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
59 Types, Classes, ZDbcConnection, ZDbcIntfs, ZCompatibility, ZPlainDriver,
60 ZPlainAdoDriver, ZPlainAdo, ZURL, ZTokenizer;
63 {** Implements Ado Database Driver. }
65 TZAdoDriver = class(TZAbstractDriver)
67 constructor Create; override;
68 function Connect(const Url: TZURL): IZConnection; override;
69 function GetMajorVersion: Integer; override;
70 function GetMinorVersion: Integer; override;
71 function GetTokenizer: IZTokenizer; override;
75 {** Represents an Ado specific connection interface. }
76 IZAdoConnection = interface (IZConnection)
77 ['{50D1AF76-0174-41CD-B90B-4FB770EFB14F}']
78 function GetAdoConnection: ZPlainAdo.Connection;
79 procedure InternalExecuteStatement(const SQL: string);
80 procedure CheckAdoError;
83 {** Implements a generic Ado Connection. }
84 TZAdoConnection = class(TZAbstractConnection, IZAdoConnection)
86 procedure ReStartTransactionSupport;
88 FAdoConnection: ZPlainAdo.Connection;
89 function GetAdoConnection: ZPlainAdo.Connection;
90 procedure InternalExecuteStatement(const SQL: string);
91 procedure CheckAdoError;
92 procedure StartTransaction;
93 procedure InternalCreate; override;
95 destructor Destroy; override;
97 function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; override;
98 function GetBinaryEscapeString(const Value: RawByteString): String; overload; override;
99 function CreateRegularStatement(Info: TStrings): IZStatement; override;
100 function CreatePreparedStatement(const SQL: string; Info: TStrings):
101 IZPreparedStatement; override;
102 function CreateCallableStatement(const SQL: string; Info: TStrings):
103 IZCallableStatement; override;
105 function NativeSQL(const SQL: string): string; override;
107 procedure SetAutoCommit(Value: Boolean); override;
108 procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override;
110 procedure Commit; override;
111 procedure Rollback; override;
113 procedure Open; override;
114 procedure Close; override;
116 procedure SetReadOnly(ReadOnly: Boolean); override;
118 procedure SetCatalog(const Catalog: string); override;
119 function GetCatalog: string; override;
121 function GetWarnings: EZSQLWarning; override;
122 procedure ClearWarnings; override;
126 {** The common driver manager object. }
133 SysUtils, ActiveX, ZDbcUtils, ZDbcLogging, ZAdoToken, ZSysUtils,
134 ZDbcAdoStatement, ZDbcAdoMetaData;
136 const //adXactUnspecified
137 IL: array[TZTransactIsolationLevel] of TOleEnum = (adXactChaos, adXactReadUncommitted, adXactReadCommitted, adXactRepeatableRead, adXactSerializable);
142 Constructs this object with default properties.
144 constructor TZAdoDriver.Create;
147 AddSupportedProtocol(AddPlainDriverToCache(TZAdoPlainDriver.Create));
151 Attempts to make a database connection to the given URL.
154 function TZAdoDriver.Connect(const Url: TZURL): IZConnection;
156 Result := TZAdoConnection.Create(Url);
161 Gets the driver's major version number. Initially this should be 1.
162 @return this driver's major version number
164 function TZAdoDriver.GetMajorVersion: Integer;
170 Gets the driver's minor version number. Initially this should be 0.
171 @return this driver's minor version number
173 function TZAdoDriver.GetMinorVersion: Integer;
178 function TZAdoDriver.GetTokenizer: IZTokenizer;
180 Result := TZAdoSQLTokenizer.Create; { thread save! Allways return a new Tokenizer! }
184 AdoCoInitialized: integer;
188 inc(AdoCoInitialized);
189 if AdoCoInitialized=1 then
195 assert(AdoCoInitialized>0);
196 dec(AdoCoInitialized);
197 if AdoCoInitialized=0 then
202 procedure TZAdoConnection.InternalCreate;
205 FAdoConnection := CoConnection.Create;
206 Self.FMetadata := TZAdoDatabaseMetadata.Create(Self, URL);
211 Destroys this object and cleanups the memory.
213 destructor TZAdoConnection.Destroy;
216 FAdoConnection := nil;
222 Just return the Ado Connection
224 function TZAdoConnection.GetAdoConnection: ZPlainAdo.Connection;
226 Result := FAdoConnection;
230 Executes simple statements internally.
232 procedure TZAdoConnection.InternalExecuteStatement(const SQL: string);
234 RowsAffected: OleVariant;
237 FAdoConnection.Execute(SQL, RowsAffected, adExecuteNoRecords);
238 DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL);
242 DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, SQL, 0, E.Message);
248 procedure TZAdoConnection.CheckAdoError;
253 Starts a transaction support.
255 procedure TZAdoConnection.ReStartTransactionSupport;
259 if not (AutoCommit or (GetTransactionIsolation = tiNone)) then
264 Opens a connection to database server with specified parameters.
266 procedure TZAdoConnection.Open;
270 if not Closed then Exit;
272 LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]);
275 FAdoConnection.Set_Mode(adModeRead)
277 FAdoConnection.Set_Mode(adModeUnknown);
278 FAdoConnection.Open(Database, User, Password, -1{adConnectUnspecified});
279 FAdoConnection.Set_CursorLocation(adUseClient);
280 DriverManager.LogMessage(lcConnect, PLainDriver.GetProtocol, LogMessage);
281 if FClientCodePage <> 'CP_ADO' then CheckCharEncoding('CP_ADO', True)
285 DriverManager.LogError(lcConnect, PlainDriver.GetProtocol, LogMessage, 0, E.Message);
292 FAdoConnection.IsolationLevel := IL[GetTransactionIsolation];
293 ReStartTransactionSupport;
296 function TZAdoConnection.GetBinaryEscapeString(const Value: TByteDynArray): String;
298 Result := GetSQLHexString(PAnsiChar(Value), Length(Value), True);
299 if GetAutoEncodeStrings then
300 Result := GetDriver.GetTokenizer.GetEscapeString(Result)
303 function TZAdoConnection.GetBinaryEscapeString(const Value: RawByteString): String;
305 Result := GetSQLHexString(PAnsiChar(Value), Length(Value), True);
306 if GetAutoEncodeStrings then
307 Result := GetDriver.GetTokenizer.GetEscapeString(Result)
311 Creates a <code>Statement</code> object for sending
312 SQL statements to the database.
313 SQL statements without parameters are normally
314 executed using Statement objects. If the same SQL statement
315 is executed many times, it is more efficient to use a
316 <code>PreparedStatement</code> object.
318 Result sets created using the returned <code>Statement</code>
319 object will by default have forward-only type and read-only concurrency.
321 @param Info a statement parameters.
322 @return a new Statement object
324 function TZAdoConnection.CreateRegularStatement(Info: TStrings): IZStatement;
326 if IsClosed then Open;
327 Result := TZAdoStatement.Create(Self, Info);
331 Creates a <code>PreparedStatement</code> object for sending
332 parameterized SQL statements to the database.
334 A SQL statement with or without IN parameters can be
335 pre-compiled and stored in a PreparedStatement object. This
336 object can then be used to efficiently execute this statement
339 <P><B>Note:</B> This method is optimized for handling
340 parametric SQL statements that benefit from precompilation. If
341 the driver supports precompilation,
342 the method <code>prepareStatement</code> will send
343 the statement to the database for precompilation. Some drivers
344 may not support precompilation. In this case, the statement may
345 not be sent to the database until the <code>PreparedStatement</code> is
346 executed. This has no direct effect on users; however, it does
347 affect which method throws certain SQLExceptions.
349 Result sets created using the returned PreparedStatement will have
350 forward-only type and read-only concurrency, by default.
352 @param sql a SQL statement that may contain one or more '?' IN
353 parameter placeholders
354 @param Info a statement parameters.
355 @return a new PreparedStatement object containing the
356 pre-compiled statement
358 function TZAdoConnection.CreatePreparedStatement(
359 const SQL: string; Info: TStrings): IZPreparedStatement;
361 if IsClosed then Open;
362 Result := TZAdoPreparedStatement.Create(Self, SQL, Info);
366 Creates a <code>CallableStatement</code> object for calling
367 database stored procedures.
368 The <code>CallableStatement</code> object provides
369 methods for setting up its IN and OUT parameters, and
370 methods for executing the call to a stored procedure.
372 <P><B>Note:</B> This method is optimized for handling stored
373 procedure call statements. Some drivers may send the call
374 statement to the database when the method <code>prepareCall</code>
376 may wait until the <code>CallableStatement</code> object
377 is executed. This has no
378 direct effect on users; however, it does affect which method
379 throws certain SQLExceptions.
381 Result sets created using the returned CallableStatement will have
382 forward-only type and read-only concurrency, by default.
384 @param sql a SQL statement that may contain one or more '?'
385 parameter placeholders. Typically this statement is a JDBC
386 function call escape string.
387 @param Info a statement parameters.
388 @return a new CallableStatement object containing the
389 pre-compiled SQL statement
391 function TZAdoConnection.CreateCallableStatement(const SQL: string; Info: TStrings):
394 if IsClosed then Open;
395 Result := TZAdoCallableStatement.Create(Self, SQL, Info);
399 Converts the given SQL statement into the system's native SQL grammar.
400 A driver may convert the JDBC sql grammar into its system's
401 native SQL grammar prior to sending it; this method returns the
402 native form of the statement that the driver would have sent.
404 @param sql a SQL statement that may contain one or more '?'
405 parameter placeholders
406 @return the native form of this statement
408 function TZAdoConnection.NativeSQL(const SQL: string): string;
414 Sets this connection's auto-commit mode.
415 If a connection is in auto-commit mode, then all its SQL
416 statements will be executed and committed as individual
417 transactions. Otherwise, its SQL statements are grouped into
418 transactions that are terminated by a call to either
419 the method <code>commit</code> or the method <code>rollback</code>.
420 By default, new connections are in auto-commit mode.
422 The commit occurs when the statement completes or the next
423 execute occurs, whichever comes first. In the case of
424 statements returning a ResultSet, the statement completes when
425 the last row of the ResultSet has been retrieved or the
426 ResultSet has been closed. In advanced cases, a single
427 statement may return multiple results as well as output
428 parameter values. In these cases the commit occurs when all results and
429 output parameter values have been retrieved.
431 @param autoCommit true enables auto-commit; false disables auto-commit.
433 procedure TZAdoConnection.SetAutoCommit(Value: Boolean);
435 if AutoCommit = Value then Exit;
436 if not Closed and Value then
438 if (FAdoConnection.State = adStateOpen) and
439 (GetTransactionIsolation <> tiNone) then
441 FAdoConnection.CommitTrans;
442 DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'COMMIT');
446 ReStartTransactionSupport;
450 Attempts to change the transaction isolation level to the one given.
451 The constants defined in the interface <code>Connection</code>
452 are the possible transaction isolation levels.
454 <P><B>Note:</B> This method cannot be called while
455 in the middle of a transaction.
457 @param level one of the TRANSACTION_* isolation values with the
458 exception of TRANSACTION_NONE; some databases may not support other values
459 @see DatabaseMetaData#supportsTransactionIsolationLevel
461 procedure TZAdoConnection.SetTransactionIsolation(
462 Level: TZTransactIsolationLevel);
464 if GetTransactionIsolation = Level then Exit;
466 if not Closed and not AutoCommit and (GetTransactionIsolation <> tiNone) then
468 FAdoConnection.CommitTrans;
469 DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'COMMIT');
475 FAdoConnection.IsolationLevel := IL[Level];
477 RestartTransactionSupport;
481 Starts a new transaction. Used internally.
483 procedure TZAdoConnection.StartTransaction;
487 LogMessage := 'BEGIN TRANSACTION';
489 FAdoConnection.BeginTrans;
490 DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage);
494 DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message);
501 Makes all changes made since the previous
502 commit/rollback permanent and releases any database locks
503 currently held by the Connection. This method should be
504 used only when auto-commit mode has been disabled.
507 procedure TZAdoConnection.Commit;
511 LogMessage := 'COMMIT';
512 if not (AutoCommit or (GetTransactionIsolation = tiNone)) then
514 FAdoConnection.CommitTrans;
515 DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage);
520 DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message);
527 Drops all changes made since the previous
528 commit/rollback and releases any database locks currently held
529 by this Connection. This method should be used only when auto-
530 commit has been disabled.
533 procedure TZAdoConnection.Rollback;
537 LogMessage := 'ROLLBACK';
538 if not (AutoCommit or (GetTransactionIsolation = tiNone)) then
540 FAdoConnection.RollbackTrans;
541 DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage);
546 DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message);
553 Releases a Connection's database and JDBC resources
554 immediately instead of waiting for
555 them to be automatically released.
557 <P><B>Note:</B> A Connection is automatically closed when it is
558 garbage collected. Certain fatal errors also result in a closed
561 procedure TZAdoConnection.Close;
565 if Closed or (not Assigned(PlainDriver)) then
570 LogMessage := Format('CLOSE CONNECTION TO "%s"', [Database]);
572 if FAdoConnection.State = adStateOpen then
573 FAdoConnection.Close;
574 DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage);
578 DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message);
587 Puts this connection in read-only mode as a hint to enable
588 database optimizations.
590 <P><B>Note:</B> This method cannot be called while in the
591 middle of a transaction.
593 @param readOnly true enables read-only mode; false disables
596 procedure TZAdoConnection.SetReadOnly(ReadOnly: Boolean);
602 Sets a catalog name in order to select
603 a subspace of this Connection's database in which to work.
604 If the driver does not support catalogs, it will
605 silently ignore this request.
607 procedure TZAdoConnection.SetCatalog(const Catalog: string);
613 LogMessage := Format('SET CATALOG %s', [Catalog]);
615 FAdoConnection.DefaultDatabase := Catalog;
616 DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage);
620 DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message);
627 Returns the Connection's current catalog name.
628 @return the current catalog name or null
630 function TZAdoConnection.GetCatalog: string;
632 Result := FAdoConnection.DefaultDatabase;
636 Returns the first warning reported by calls on this Connection.
637 <P><B>Note:</B> Subsequent warnings will be chained to this
639 @return the first SQLWarning or null
641 function TZAdoConnection.GetWarnings: EZSQLWarning;
647 Clears all warnings reported for this <code>Connection</code> object.
648 After a call to this method, the method <code>getWarnings</code>
649 returns null until a new warning is reported for this Connection.
651 procedure TZAdoConnection.ClearWarnings;
656 AdoCoInitialized := 0;
657 AdoDriver := TZAdoDriver.Create;
658 DriverManager.RegisterDriver(AdoDriver);
660 if Assigned(DriverManager) then
661 DriverManager.DeregisterDriver(AdoDriver);