1 {*********************************************************}
3 { Zeos Database Objects }
4 { Interbase Database Connectivity Classes }
6 { Originally written by Sergey Merkuriev }
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 ZCompatibility, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Contnrs, SysUtils,
60 ZDbcIntfs, ZDbcConnection, ZPlainASADriver, ZTokenizer, ZDbcGenericResolver,
61 ZURL, ZPlainDriver, ZGenericSqlAnalyser, ZPlainASAConstants;
64 {** Implements a ASA Database Driver. }
66 TZASADriver = class(TZAbstractDriver)
68 constructor Create; override;
69 function Connect(const Url: TZURL): IZConnection; override;
70 function GetMajorVersion: Integer; override;
71 function GetMinorVersion: Integer; override;
72 function GetTokenizer: IZTokenizer; override;
73 function GetStatementAnalyser: IZStatementAnalyser; override;
77 {** Represents a ASA specific connection interface. }
78 IZASAConnection = interface (IZConnection)
79 ['{FAAAFCE0-F550-4098-96C6-580145813EBF}']
80 function GetDBHandle: PZASASQLCA;
81 function GetPlainDriver: IZASAPlainDriver;
82 // procedure CreateNewDatabase(SQL: String);
85 {** Implements ASA Database Connection. }
86 TZASAConnection = class(TZAbstractConnection, IZASAConnection)
91 procedure StartTransaction; virtual;
92 function DetermineASACharSet: String;
94 procedure InternalCreate; override;
96 destructor Destroy; override;
98 function GetDBHandle: PZASASQLCA;
99 function GetPlainDriver: IZASAPlainDriver;
100 // procedure CreateNewDatabase(SQL: String);
102 function CreateRegularStatement(Info: TStrings): IZStatement; override;
103 function CreatePreparedStatement(const SQL: string; Info: TStrings):
104 IZPreparedStatement; override;
105 function CreateCallableStatement(const SQL: string; Info: TStrings):
106 IZCallableStatement; override;
108 procedure Commit; override;
109 procedure Rollback; override;
110 procedure SetOption(Temporary: Integer; User: PAnsiChar; const Option: string;
111 const Value: string);
113 procedure Open; override;
114 procedure Close; override;
117 {** Implements a specialized cached resolver for ASA. }
118 TZASACachedResolver = class(TZGenericCachedResolver)
120 function FormCalculateStatement(Columns: TObjectList): string; override;
125 {** The common driver manager object. }
131 ZDbcASAMetadata, ZDbcASAStatement, ZDbcASAUtils, ZSybaseToken,
132 ZSybaseAnalyser, ZDbcLogging{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF};
137 Attempts to make a database connection to the given URL.
138 The driver should return "null" if it realizes it is the wrong kind
139 of driver to connect to the given URL. This will be common, as when
140 the JDBC driver manager is asked to connect to a given URL it passes
141 the URL to each loaded driver in turn.
143 <P>The driver should raise a SQLException if it is the right
144 driver to connect to the given URL, but has trouble connecting to
147 <P>The java.util.Properties argument can be used to passed arbitrary
148 string tag/value pairs as connection arguments.
149 Normally at least "user" and "password" properties should be
150 included in the Properties.
152 @param url the URL of the database to which to connect
153 @param info a list of arbitrary string tag/value pairs as
154 connection arguments. Normally at least a "user" and
155 "password" property should be included.
156 @return a <code>Connection</code> object that represents a
157 connection to the URL
160 function TZASADriver.Connect(const Url: TZURL): IZConnection;
162 Result := TZASAConnection.Create(Url);
167 Constructs this object with default properties.
169 constructor TZASADriver.Create;
172 AddSupportedProtocol(AddPlainDriverToCache(TZASA7PlainDriver.Create));
173 AddSupportedProtocol(AddPlainDriverToCache(TZASA8PlainDriver.Create));
174 AddSupportedProtocol(AddPlainDriverToCache(TZASA9PlainDriver.Create));
175 AddSupportedProtocol(AddPlainDriverToCache(TZASA12PlainDriver.Create));
179 Gets the driver's major version number. Initially this should be 1.
180 @return this driver's major version number
182 function TZASADriver.GetMajorVersion: Integer;
188 Gets the driver's minor version number. Initially this should be 0.
189 @return this driver's minor version number
191 function TZASADriver.GetMinorVersion: Integer;
197 Gets a SQL syntax tokenizer.
198 @returns a SQL syntax tokenizer object.
200 function TZASADriver.GetTokenizer: IZTokenizer;
202 Result := TZSybaseTokenizer.Create; { thread save! Allways return a new Tokenizer! }
206 Creates a statement analyser object.
207 @returns a statement analyser object.
209 function TZASADriver.GetStatementAnalyser: IZStatementAnalyser;
211 Result := TZSybaseStatementAnalyser.Create; { thread save! Allways return a new Analyser! }
217 Releases a Connection's database and JDBC resources
218 immediately instead of waiting for
219 them to be automatically released.
221 <P><B>Note:</B> A Connection is automatically closed when it is
222 garbage collected. Certain fatal errors also result in a closed
225 procedure TZASAConnection.Close;
227 if Closed or (not Assigned(PlainDriver))then
235 GetPlainDriver.db_string_disconnect( FHandle, nil);
236 CheckASAError( GetPlainDriver, FHandle, lcDisconnect);
239 if GetPlainDriver.db_fini( @FSQLCA) = 0 then
241 DriverManager.LogError( lcConnect, PlainDriver.GetProtocol, 'Inititalizing SQLCA',
242 0, 'Error closing SQLCA');
243 raise EZSQLException.CreateWithCode( 0,
244 'Error closing SQLCA');
247 DriverManager.LogMessage(lcDisconnect, PlainDriver.GetProtocol,
248 Format('DISCONNECT FROM "%s"', [Database]));
254 Commit current transaction
256 procedure TZASAConnection.Commit;
258 if Closed or AutoCommit then
261 if FHandle <> nil then
263 GetPlainDriver.db_commit( FHandle, 0);
264 CheckASAError( GetPlainDriver, FHandle, lcTransaction);
265 DriverManager.LogMessage(lcTransaction,
266 PlainDriver.GetProtocol, 'TRANSACTION COMMIT');
271 Constructs this object and assignes the main properties.
273 procedure TZASAConnection.InternalCreate;
275 Self.FMetadata := TZASADatabaseMetadata.Create(Self, URL);
279 Creates a <code>CallableStatement</code> object for calling
280 database stored procedures.
281 The <code>CallableStatement</code> object provides
282 methods for setting up its IN and OUT parameters, and
283 methods for executing the call to a stored procedure.
285 <P><B>Note:</B> This method is optimized for handling stored
286 procedure call statements. Some drivers may send the call
287 statement to the database when the method <code>prepareCall</code>
289 may wait until the <code>CallableStatement</code> object
290 is executed. This has no
291 direct effect on users; however, it does affect which method
292 throws certain SQLExceptions.
294 Result sets created using the returned CallableStatement will have
295 forward-only type and read-only concurrency, by default.
297 @param sql a SQL statement that may contain one or more '?'
298 parameter placeholders. Typically this statement is a JDBC
299 function call escape string.
300 @param Info a statement parameters.
301 @return a new CallableStatement object containing the
302 pre-compiled SQL statement
304 function TZASAConnection.CreateCallableStatement(const SQL: string;
305 Info: TStrings): IZCallableStatement;
309 Result := TZASACallableStatement.Create(Self, SQL, Info);
313 Creates a <code>PreparedStatement</code> object for sending
314 parameterized SQL statements to the database.
316 A SQL statement with or without IN parameters can be
317 pre-compiled and stored in a PreparedStatement object. This
318 object can then be used to efficiently execute this statement
321 <P><B>Note:</B> This method is optimized for handling
322 parametric SQL statements that benefit from precompilation. If
323 the driver supports precompilation,
324 the method <code>prepareStatement</code> will send
325 the statement to the database for precompilation. Some drivers
326 may not support precompilation. In this case, the statement may
327 not be sent to the database until the <code>PreparedStatement</code> is
328 executed. This has no direct effect on users; however, it does
329 affect which method throws certain SQLExceptions.
331 Result sets created using the returned PreparedStatement will have
332 forward-only type and read-only concurrency, by default.
334 @param sql a SQL statement that may contain one or more '?' IN
335 parameter placeholders
336 @return a new PreparedStatement object containing the
337 pre-compiled statement
339 function TZASAConnection.CreatePreparedStatement(const SQL: string;
340 Info: TStrings): IZPreparedStatement;
344 Result := TZASAPreparedStatement.Create(Self, SQL, Info);
348 Creates a <code>Statement</code> object for sending
349 SQL statements to the database.
350 SQL statements without parameters are normally
351 executed using Statement objects. If the same SQL statement
352 is executed many times, it is more efficient to use a
353 <code>PreparedStatement</code> object.
355 Result sets created using the returned <code>Statement</code>
356 object will by default have forward-only type and read-only concurrency.
358 @param Info a statement parameters.
359 @return a new Statement object
361 function TZASAConnection.CreateRegularStatement(
362 Info: TStrings): IZStatement;
366 Result := TZASAStatement.Create(Self, Info);
370 Destroys this object and cleanups the memory.
372 destructor TZASAConnection.Destroy;
381 Get database connection handle.
382 @return database handle
384 function TZASAConnection.GetDBHandle: PZASASQLCA;
390 Return native interbase plain driver
393 function TZASAConnection.GetPlainDriver: IZASAPlainDriver;
395 Result := PlainDriver as IZASAPlainDriver;
399 Opens a connection to database server with specified parameters.
401 procedure TZASAConnection.Open;
403 ConnectionString, Links: string;
409 ConnectionString := '';
411 if GetPlainDriver.db_init( @FSQLCA) = 0 then
413 DriverManager.LogError( lcConnect, PlainDriver.GetProtocol, 'Inititalizing SQLCA',
414 0, 'Error initializing SQLCA');
415 raise EZSQLException.CreateWithCode( 0,
416 'Error initializing SQLCA');
420 if HostName <> '' then
421 ConnectionString := ConnectionString + 'ENG="' + HostName + '"; ';
423 ConnectionString := ConnectionString + 'UID="' + User + '"; ';
424 if Password <> '' then
425 ConnectionString := ConnectionString + 'PWD="' + Password + '"; ';
426 if Database <> '' then
428 if CompareText( ExtractFileExt( Database), '.db') = 0 then
429 ConnectionString := ConnectionString + 'DBF="' + Database + '"; '
431 ConnectionString := ConnectionString + 'DBN="' + Database + '"; ';
435 if Info.Values['CommLinks'] <> ''
436 then Links := 'CommLinks=' + Info.Values['CommLinks'];
437 if Info.Values['LINKS'] <> ''
438 then Links := 'LINKS=' + Info.Values['LINKS'];
439 if (Links = '') and (Port <> 0)
440 then Links := 'LINKS=tcpip(PORT=' + IntToStr(Port) + ')';
442 then ConnectionString := ConnectionString + Links + '; ';
444 GetPlainDriver.db_string_connect(FHandle, PAnsiChar(AnsiString(ConnectionString)));
445 CheckASAError( GetPlainDriver, FHandle, lcConnect);
447 DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol,
448 Format('CONNECT TO "%s" AS USER "%s"', [Database, User]));
450 if ( FClientCodePage <> '' ) then
451 if ( GetPlainDriver.db_change_char_charset(FHandle, PAnsiChar(AnsiString(FClientCodePage))) = 0 ) or
452 ( GetPlainDriver.db_change_nchar_charset(FHandle, PAnsiChar(AnsiString(FClientCodePage))) = 0 ) then
453 CheckASAError( GetPlainDriver, FHandle, lcOther, 'Set client CharacterSet failed.');
457 //SetConnOptions RowCount;
462 if Assigned( FHandle) then
463 GetPlainDriver.db_fini( FHandle);
471 if FClientCodePage = '' then
472 CheckCharEncoding(DetermineASACharSet);
476 Drops all changes made since the previous
477 commit/rollback and releases any database locks currently held
478 by this Connection. This method should be used only when auto-
479 commit has been disabled.
482 procedure TZASAConnection.Rollback;
484 if Closed or AutoCommit then
487 if Assigned( FHandle) then
489 GetPlainDriver.db_rollback( FHandle, 0);
490 CheckASAError( GetPlainDriver, FHandle, lcTransaction);
491 DriverManager.LogMessage(lcTransaction,
492 PlainDriver.GetProtocol, 'TRANSACTION ROLLBACK');
496 procedure TZASAConnection.SetOption(Temporary: Integer; User: PAnsiChar;
497 const Option: string; const Value: string);
503 if Assigned( FHandle) then
505 Sz := SizeOf( TASASQLDA) - 32767 * SizeOf( TZASASQLVAR);
506 SQLDA := AllocMem( Sz);
508 {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( SQLDA.sqldaid, 'SQLDA ', 8);
512 SQLDA.sqlVar[0].sqlType := DT_STRING;
513 SQLDA.sqlVar[0].sqlLen := Length( Value)+1;
514 SQLDA.sqlVar[0].sqlData := PAnsiChar(AnsiString(Value));
515 GetPlainDriver.db_setoption(FHandle, Temporary, User, PAnsiChar(AnsiString(Option)), SQLDA);
517 CheckASAError( GetPlainDriver, FHandle, lcOther);
519 DriverManager.LogMessage( lcOther, PlainDriver.GetProtocol,
520 Format( 'SET OPTION %s.%s = %s', [ S, Option, Value]));
530 procedure TZASAConnection.StartTransaction;
535 SetOption( 1, nil, 'CHAINED', 'OFF')
537 SetOption( 1, nil, 'CHAINED', 'ON');
538 ASATL := Ord( TransactIsolationLevel);
541 SetOption( 1, nil, 'ISOLATION_LEVEL', IntToStr( ASATL));
544 function TZASAConnection.DetermineASACharSet: String;
549 Stmt := Self.CreateRegularStatement(Info);
550 RS := Stmt.ExecuteQuery('SELECT DB_PROPERTY( ''CharSet'')');
552 Result := RS.GetString(1)
560 { TZASACachedResolver }
563 Forms a where clause for SELECT statements to calculate default values.
564 @param Columns a collection of key columns.
565 @param OldRowAccessor an accessor object to old column values.
567 function TZASACachedResolver.FormCalculateStatement(
568 Columns: TObjectList): string;
571 Current: TZResolverParameter;
574 if Columns.Count = 0 then
577 for I := 0 to Columns.Count - 1 do
579 Current := TZResolverParameter(Columns[I]);
581 Result := Result + ',';
582 if Current.DefaultValue <> '' then
583 Result := Result + Current.DefaultValue
585 Result := Result + 'NULL';
587 Result := 'SELECT ' + Result;
591 ASADriver := TZASADriver.Create;
592 DriverManager.RegisterDriver(ASADriver);
595 if Assigned(DriverManager) then
596 DriverManager.DeregisterDriver(ASADriver);