zeoslib  UNKNOWN
 All Files
ZDbcOracle.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Oracle Database Connectivity Classes }
5 { }
6 { Originally written by Sergey Seroukhov }
7 { }
8 {*********************************************************}
9 
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
12 { }
13 { License Agreement: }
14 { }
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. }
20 { }
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. }
39 { }
40 { }
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) }
45 { }
46 { http://www.sourceforge.net/projects/zeoslib. }
47 { }
48 { }
49 { Zeos Development Group. }
50 {********************************************************@}
51 
52 unit ZDbcOracle;
53 
54 interface
55 
56 {$I ZDbc.inc}
57 
58 uses
59  Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs,
60  ZCompatibility, ZDbcIntfs, ZDbcConnection, ZPlainOracleDriver, ZDbcLogging,
61  ZTokenizer, ZDbcGenericResolver, ZURL, ZGenericSqlAnalyser,
62  ZPlainOracleConstants;
63 
64 type
65 
66  {** Implements Oracle Database Driver. }
67  {$WARNINGS OFF}
68  TZOracleDriver = class(TZAbstractDriver)
69  public
70  constructor Create; override;
71  function Connect(const Url: TZURL): IZConnection; override;
72  function GetMajorVersion: Integer; override;
73  function GetMinorVersion: Integer; override;
74 
75  function GetTokenizer: IZTokenizer; override;
76  function GetStatementAnalyser: IZStatementAnalyser; override;
77  end;
78  {$WARNINGS ON}
79 
80  {** Represents a Oracle specific connection interface. }
81  IZOracleConnection = interface (IZConnection)
82  ['{C7F36FDF-8A64-477B-A0EB-3E8AB7C09F8D}']
83 
84  function GetPlainDriver: IZOraclePlainDriver;
85  function GetConnectionHandle: POCIEnv;
86  function GetContextHandle: POCISvcCtx;
87  function GetErrorHandle: POCIError;
88  function GetServerHandle: POCIServer;
89  function GetSessionHandle: POCISession;
90  function GetTransactionHandle: POCITrans;
91  function GetDescribeHandle: POCIDescribe;
92  end;
93 
94  {** Implements Oracle Database Connection. }
95  TZOracleConnection = class(TZAbstractConnection, IZOracleConnection)
96  private
97  FCatalog: string;
98  FHandle: POCIEnv;
99  FContextHandle: POCISvcCtx;
100  FErrorHandle: POCIError;
101  FServerHandle: POCIServer;
102  FSessionHandle: POCISession;
103  FTransHandle: POCITrans;
104  FDescibeHandle: POCIDescribe;
105  protected
106  procedure InternalCreate; override;
107  procedure StartTransactionSupport;
108 
109  public
110  destructor Destroy; override;
111 
112  function CreateRegularStatement(Info: TStrings): IZStatement; override;
113  function CreatePreparedStatement(const SQL: string; Info: TStrings):
114  IZPreparedStatement; override;
115 
116  function CreateCallableStatement(const SQL: string; Info: TStrings):
117  IZCallableStatement; override;
118 
119  procedure Commit; override;
120  procedure Rollback; override;
121 
122  function PingServer: Integer; override;
123 
124  procedure Open; override;
125  procedure Close; override;
126 
127  procedure SetCatalog(const Catalog: string); override;
128  function GetCatalog: string; override;
129 
130  procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override;
131  function CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; override;
132 
133  function GetPlainDriver: IZOraclePlainDriver;
134  function GetConnectionHandle: POCIEnv;
135  function GetContextHandle: POCISvcCtx;
136  function GetErrorHandle: POCIError;
137  function GetServerHandle: POCIServer;
138  function GetSessionHandle: POCISession;
139  function GetTransactionHandle: POCITrans;
140  function GetDescribeHandle: POCIDescribe;
141  function GetClientVersion: Integer; override;
142  function GetHostVersion: Integer; override;
143  function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; override;
144  function GetBinaryEscapeString(const Value: RawByteString): String; overload; override;
145  end;
146 
147  TZOracleSequence = class(TZAbstractSequence)
148  public
149  function GetCurrentValue: Int64; override;
150  function GetCurrentValueSQL: String; override;
151  function GetNextValue: Int64; override;
152  function GetNextValueSQL: String; override;
153  end;
154 
155  {** Implements a specialized cached resolver for Oracle. }
156  TZOracleCachedResolver = class(TZGenericCachedResolver)
157  public
158  function FormCalculateStatement(Columns: TObjectList): string; override;
159  end;
160 
161 var
162  {** The common driver manager object. }
163  OracleDriver: IZDriver;
164 
165 implementation
166 
167 uses
168  ZMessages, ZGenericSqlToken, ZDbcOracleStatement, ZSysUtils, ZDbcUtils,
169  ZDbcOracleUtils, ZDbcOracleMetadata, ZOracleToken, ZOracleAnalyser;
170 
171 { TZOracleDriver }
172 
173 {**
174  Constructs this object with default properties.
175 }
176 constructor TZOracleDriver.Create;
177 begin
178  inherited Create;
179  AddSupportedProtocol(AddPlainDriverToCache(TZOracle9iPlainDriver.Create, 'oracle'));
180  AddSupportedProtocol(AddPlainDriverToCache(TZOracle9iPlainDriver.Create));
181 end;
182 
183 {**
184  Attempts to make a database connection to the given URL.
185  The driver should return "null" if it realizes it is the wrong kind
186  of driver to connect to the given URL. This will be common, as when
187  the JDBC driver manager is asked to connect to a given URL it passes
188  the URL to each loaded driver in turn.
189 
190  <P>The driver should raise a SQLException if it is the right
191  driver to connect to the given URL, but has trouble connecting to
192  the database.
193 
194  <P>The java.util.Properties argument can be used to passed arbitrary
195  string tag/value pairs as connection arguments.
196  Normally at least "user" and "password" properties should be
197  included in the Properties.
198 
199  @param url the URL of the database to which to connect
200  @param info a list of arbitrary string tag/value pairs as
201  connection arguments. Normally at least a "user" and
202  "password" property should be included.
203  @return a <code>Connection</code> object that represents a
204  connection to the URL
205 }
206 {$WARNINGS OFF}
207 function TZOracleDriver.Connect(const Url: TZURL): IZConnection;
208 begin
209  Result := TZOracleConnection.Create(Url);
210 end;
211 {$WARNINGS ON}
212 
213 {**
214  Gets the driver's major version number. Initially this should be 1.
215  @return this driver's major version number
216 }
217 function TZOracleDriver.GetMajorVersion: Integer;
218 begin
219  Result := 1;
220 end;
221 
222 {**
223  Gets the driver's minor version number. Initially this should be 0.
224  @return this driver's minor version number
225 }
226 function TZOracleDriver.GetMinorVersion: Integer;
227 begin
228  Result := 0;
229 end;
230 
231 {**
232  Gets a SQL syntax tokenizer.
233  @returns a SQL syntax tokenizer object.
234 }
235 function TZOracleDriver.GetTokenizer: IZTokenizer;
236 begin
237  Result := TZOracleTokenizer.Create; { thread save! Allways return a new Tokenizer! }
238 end;
239 
240 {**
241  Creates a statement analyser object.
242  @returns a statement analyser object.
243 }
244 function TZOracleDriver.GetStatementAnalyser: IZStatementAnalyser;
245 begin
246  Result := TZOracleStatementAnalyser.Create; { thread save! Allways return a new Analyser! }
247 end;
248 
249 { TZOracleConnection }
250 
251 {**
252  Constructs this object and assignes the main properties.
253 }
254 procedure TZOracleConnection.InternalCreate;
255 begin
256  FMetaData := TZOracleDatabaseMetadata.Create(Self, URL);
257  FHandle := nil;
258 
259  { Sets a default properties }
260  if Self.Port = 0 then
261  Self.Port := 1521;
262  AutoCommit := True;
263  TransactIsolationLevel := tiNone;
264  Open;
265 end;
266 
267 function TZOracleConnection.CreateCallableStatement(const SQL: string;
268  Info: TStrings): IZCallableStatement;
269 begin
270  if IsClosed then
271  Open;
272  Result := TZOracleCallableStatement.Create(Self, SQL, Info);
273  Result.ClearParameters;
274 end;
275 
276 {**
277  Destroys this object and cleanups the memory.
278 }
279 destructor TZOracleConnection.Destroy;
280 begin
281  if not IsClosed then
282  Close;
283 
284  if FHandle <> nil then
285  begin
286  GetPlainDriver.HandleFree(FHandle, OCI_HTYPE_ENV);
287  FHandle := nil;
288  end;
289 
290  inherited Destroy;
291 end;
292 
293 {**
294  Opens a connection to database server with specified parameters.
295 }
296 procedure TZOracleConnection.Open;
297 var
298  Status: Integer;
299  LogMessage: string;
300  OCI_CLIENT_CHARSET_ID, OCI_CLIENT_NCHARSET_ID: ub2;
301 
302  procedure CleanupOnFail;
303  begin
304  GetPlainDriver.HandleFree(FDescibeHandle, OCI_HTYPE_DESCRIBE);
305  FDescibeHandle := nil;
306  GetPlainDriver.HandleFree(FContextHandle, OCI_HTYPE_SVCCTX);
307  FContextHandle := nil;
308  GetPlainDriver.HandleFree(FErrorHandle, OCI_HTYPE_ERROR);
309  FErrorHandle := nil;
310  GetPlainDriver.HandleFree(FServerHandle, OCI_HTYPE_SERVER);
311  FServerHandle := nil;
312  end;
313 
314 begin
315  if not Closed then
316  Exit;
317 
318  LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]);
319 
320  { Sets a default port number. }
321  if Port = 0 then
322  Port := 1521;
323 
324  { Sets a client codepage. }
325  OCI_CLIENT_CHARSET_ID := ConSettings.ClientCodePage^.ID;
326  { Connect to Oracle database. }
327  if ( FHandle = nil ) then
328  try
329  FErrorHandle := nil;
330  Status := GetPlainDriver.EnvNlsCreate(FHandle, OCI_OBJECT, nil, nil, nil, nil, 0, nil,
331  OCI_CLIENT_CHARSET_ID, OCI_CLIENT_CHARSET_ID);
332  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcOther, 'EnvNlsCreate failed.');
333  except
334  raise;
335  end;
336  FErrorHandle := nil;
337  GetPlainDriver.HandleAlloc(FHandle, FErrorHandle, OCI_HTYPE_ERROR, 0, nil);
338  FServerHandle := nil;
339  GetPlainDriver.HandleAlloc(FHandle, FServerHandle, OCI_HTYPE_SERVER, 0, nil);
340  FContextHandle := nil;
341  GetPlainDriver.HandleAlloc(FHandle, FContextHandle, OCI_HTYPE_SVCCTX, 0, nil);
342  FDescibeHandle := nil;
343  GetPlainDriver.HandleAlloc(FHandle, FDescibeHandle, OCI_HTYPE_DESCRIBE, 0, nil);
344 
345  Status := GetPlainDriver.ServerAttach(FServerHandle, FErrorHandle,
346  PAnsiChar(ansistring(Database)), Length(AnsiString(Database)), 0);
347  try
348  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcConnect, LogMessage);
349  except
350  CleanupOnFail;
351  raise;
352  end;
353 
354  if OCI_CLIENT_CHARSET_ID = 0 then
355  begin
356  OCI_CLIENT_NCHARSET_ID := High(ub2);
357  GetPlainDriver.AttrGet(FHandle, OCI_HTYPE_ENV, @OCI_CLIENT_CHARSET_ID,
358  nil, OCI_ATTR_ENV_CHARSET_ID, FErrorHandle); //Get Server default CodePage
359  CheckCharEncoding(GetPlainDriver.ValidateCharEncoding(OCI_CLIENT_CHARSET_ID)^.Name);
360  if OCI_CLIENT_CHARSET_ID <> OCI_CLIENT_NCHARSET_ID then
361  begin
362  CleanupOnFail;
363  Open;
364  Exit;
365  end;
366  end;
367  if GetPlainDriver.GetEnvCharsetByteWidth(FHandle, FErrorHandle, ConSettings.ClientCodePage^.CharWidth) <> OCI_SUCCESS then
368  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcConnect, LogMessage);
369 
370  GetPlainDriver.AttrSet(FContextHandle, OCI_HTYPE_SVCCTX, FServerHandle, 0,
371  OCI_ATTR_SERVER, FErrorHandle);
372  GetPlainDriver.HandleAlloc(FHandle, FSessionHandle, OCI_HTYPE_SESSION, 0, nil);
373  GetPlainDriver.AttrSet(FSessionHandle, OCI_HTYPE_SESSION, PAnsiChar(AnsiString(User)),
374  Length(User), OCI_ATTR_USERNAME, FErrorHandle);
375  GetPlainDriver.AttrSet(FSessionHandle, OCI_HTYPE_SESSION, PAnsiChar(AnsiString(Password)),
376  Length(Password), OCI_ATTR_PASSWORD, FErrorHandle);
377  Status := GetPlainDriver.SessionBegin(FContextHandle, FErrorHandle,
378  FSessionHandle, OCI_CRED_RDBMS, OCI_DEFAULT);
379  try
380  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcConnect, LogMessage);
381  except
382  CleanupOnFail;
383  raise;
384  end;
385  GetPlainDriver.AttrSet(FContextHandle, OCI_HTYPE_SVCCTX, FSessionHandle, 0,
386  OCI_ATTR_SESSION, FErrorHandle);
387  DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage);
388 
389  StartTransactionSupport;
390 
391  inherited Open;
392 end;
393 
394 {**
395  Starts a transaction support.
396 }
397 procedure TZOracleConnection.StartTransactionSupport;
398 var
399  SQL: PChar;
400  Status: Integer;
401  Isolation: Integer;
402 begin
403  if TransactIsolationLevel = tiNone then
404  begin
405  SQL := 'SET TRANSACTION ISOLATION LEVEL DEFAULT';
406  Isolation := OCI_DEFAULT;
407  end
408  else if TransactIsolationLevel = tiReadCommitted then
409  begin
410 // Behaviour changed by mdaems 31/05/2006 : Read Committed is the default
411 // isolation level used by oracle. This property should not be abused to add
412 // the non-standard isolation level 'read only' thats invented by oracle.
413 // SQL := 'SET TRANSACTION ISOLATION LEVEL READONLY';
414 // Isolation := OCI_TRANS_READONLY;
415  SQL := 'SET TRANSACTION ISOLATION LEVEL DEFAULT';
416  Isolation := OCI_DEFAULT;
417  end
418  else if TransactIsolationLevel = tiRepeatableRead then
419  begin
420  SQL := 'SET TRANSACTION ISOLATION LEVEL READWRITE';
421  Isolation := OCI_TRANS_READWRITE;
422  end
423  else if TransactIsolationLevel = tiSerializable then
424  begin
425  SQL := 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE';
426  Isolation := OCI_TRANS_SERIALIZABLE;
427  end
428  else
429  raise EZSQLException.Create(SIsolationIsNotSupported);
430 
431  FTransHandle := nil;
432  GetPlainDriver.HandleAlloc(FHandle, FTransHandle, OCI_HTYPE_TRANS, 0, nil);
433  GetPlainDriver.AttrSet(FContextHandle, OCI_HTYPE_SVCCTX, FTransHandle, 0,
434  OCI_ATTR_TRANS, FErrorHandle);
435 
436  Status := GetPlainDriver.TransStart(FContextHandle, FErrorHandle, 0, Isolation);
437  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcExecute, SQL);
438 
439  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL);
440 end;
441 
442 {**
443  Creates a <code>Statement</code> object for sending
444  SQL statements to the database.
445  SQL statements without parameters are normally
446  executed using Statement objects. If the same SQL statement
447  is executed many times, it is more efficient to use a
448  <code>PreparedStatement</code> object.
449  <P>
450  Result sets created using the returned <code>Statement</code>
451  object will by default have forward-only type and read-only concurrency.
452 
453  @param Info a statement parameters.
454  @return a new Statement object
455 }
456 function TZOracleConnection.CreateRegularStatement(Info: TStrings):
457  IZStatement;
458 begin
459  if IsClosed then
460  Open;
461  Result := TZOracleStatement.Create(GetPlainDriver, Self, Info);
462 end;
463 
464 {**
465  Creates a <code>PreparedStatement</code> object for sending
466  parameterized SQL statements to the database.
467 
468  A SQL statement with or without IN parameters can be
469  pre-compiled and stored in a PreparedStatement object. This
470  object can then be used to efficiently execute this statement
471  multiple times.
472 
473  <P><B>Note:</B> This method is optimized for handling
474  parametric SQL statements that benefit from precompilation. If
475  the driver supports precompilation,
476  the method <code>prepareStatement</code> will send
477  the statement to the database for precompilation. Some drivers
478  may not support precompilation. In this case, the statement may
479  not be sent to the database until the <code>PreparedStatement</code> is
480  executed. This has no direct effect on users; however, it does
481  affect which method throws certain SQLExceptions.
482 
483  Result sets created using the returned PreparedStatement will have
484  forward-only type and read-only concurrency, by default.
485 
486  @param sql a SQL statement that may contain one or more '?' IN
487  parameter placeholders
488  @param Info a statement parameters.
489  @return a new PreparedStatement object containing the
490  pre-compiled statement
491 }
492 function TZOracleConnection.CreatePreparedStatement(const SQL: string;
493  Info: TStrings): IZPreparedStatement;
494 begin
495  if IsClosed then
496  Open;
497  Result := TZOraclePreparedStatement.Create(GetPlainDriver, Self, SQL, Info);
498 end;
499 
500 {**
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.
505  @see #setAutoCommit
506 }
507 procedure TZOracleConnection.Commit;
508 var
509  Status: Integer;
510  SQL: PChar;
511 begin
512  if not Closed then
513  begin
514  SQL := 'COMMIT';
515 
516  Status := GetPlainDriver.TransCommit(FContextHandle, FErrorHandle,
517  OCI_DEFAULT);
518  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcExecute, SQL);
519 
520  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL);
521  end;
522 end;
523 
524 {**
525  Drops all changes made since the previous
526  commit/rollback and releases any database locks currently held
527  by this Connection. This method should be used only when auto-
528  commit has been disabled.
529  @see #setAutoCommit
530 }
531 procedure TZOracleConnection.Rollback;
532 var
533  Status: Integer;
534  SQL: PChar;
535 begin
536  if not Closed then
537  begin
538  SQL := 'ROLLBACK';
539 
540  Status := GetPlainDriver.TransRollback(FContextHandle, FErrorHandle,
541  OCI_DEFAULT);
542  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcExecute, SQL);
543 
544  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL);
545  end;
546 end;
547 
548 {**
549  Ping Current Connection's server, if client was disconnected,
550  the connection is resumed.
551  @return 0 if succesfull or error code if any error occurs
552 }
553 function TZOracleConnection.PingServer: Integer;
554 begin
555  Result := GetPlainDriver.Ping(FContextHandle, FErrorHandle);
556  CheckOracleError(GetPlainDriver, FErrorHandle, Result, lcExecute, 'Ping Server');
557  Result := 0; //only possible if CheckOracleError dosn't raise an exception
558 end;
559 
560 {**
561  Releases a Connection's database and JDBC resources
562  immediately instead of waiting for
563  them to be automatically released.
564 
565  <P><B>Note:</B> A Connection is automatically closed when it is
566  garbage collected. Certain fatal errors also result in a closed
567  Connection.
568 }
569 procedure TZOracleConnection.Close;
570 var
571  Status: Integer;
572  LogMessage: string;
573 begin
574  if not Closed then
575  begin
576  LogMessage := Format('DISCONNECT FROM "%s"', [Database]);
577 
578  { Closes started transaction }
579  Status := GetPlainDriver.TransRollback(FContextHandle, FErrorHandle,
580  OCI_DEFAULT);
581  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcDisconnect,
582  LogMessage);
583  GetPlainDriver.HandleFree(FTransHandle, OCI_HTYPE_TRANS);
584  FTransHandle := nil;
585 
586  { Closes the session }
587  Status := GetPlainDriver.SessionEnd(FContextHandle, FErrorHandle,
588  FSessionHandle, OCI_DEFAULT);
589  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcDisconnect,
590  LogMessage);
591 
592  { Detaches from the server }
593  Status := GetPlainDriver.ServerDetach(FServerHandle, FErrorHandle,
594  OCI_DEFAULT);
595  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcDisconnect,
596  LogMessage);
597 
598  { Frees all handlers }
599  GetPlainDriver.HandleFree(FDescibeHandle, OCI_HTYPE_DESCRIBE);
600  FDescibeHandle := nil;
601  GetPlainDriver.HandleFree(FSessionHandle, OCI_HTYPE_SESSION);
602  FSessionHandle := nil;
603  GetPlainDriver.HandleFree(FContextHandle, OCI_HTYPE_SVCCTX);
604  FContextHandle := nil;
605  GetPlainDriver.HandleFree(FServerHandle, OCI_HTYPE_SERVER);
606  FServerHandle := nil;
607  GetPlainDriver.HandleFree(FErrorHandle, OCI_HTYPE_ERROR);
608  FErrorHandle := nil;
609 
610  DriverManager.LogMessage(lcDisconnect, PlainDriver.GetProtocol, LogMessage);
611  end;
612  inherited Close;
613 end;
614 
615 {**
616  Gets a selected catalog name.
617  @return a selected catalog name.
618 }
619 function TZOracleConnection.GetCatalog: string;
620 begin
621  Result := FCatalog;
622 end;
623 
624 {**
625  Sets a new selected catalog name.
626  @param Catalog a selected catalog name.
627 }
628 procedure TZOracleConnection.SetCatalog(const Catalog: string);
629 begin
630  FCatalog := Catalog;
631 end;
632 
633 {**
634  Sets a new transact isolation level.
635  @param Level a new transact isolation level.
636 }
637 procedure TZOracleConnection.SetTransactionIsolation(
638  Level: TZTransactIsolationLevel);
639 var
640  Status: Integer;
641  SQL: PChar;
642 begin
643  if TransactIsolationLevel <> Level then
644  begin
645  inherited SetTransactionIsolation(Level);
646 
647  if not Closed then
648  begin
649  SQL := 'END TRANSACTION';
650  Status := GetPlainDriver.TransRollback(FContextHandle, FErrorHandle,
651  OCI_DEFAULT);
652  CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcExecute, SQL);
653  GetPlainDriver.HandleFree(FTransHandle, OCI_HTYPE_TRANS);
654  FTransHandle := nil;
655  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL);
656 
657  StartTransactionSupport;
658  end;
659  end;
660 end;
661 
662 {**
663  Creates a sequence generator object.
664  @param Sequence a name of the sequence generator.
665  @param BlockSize a number of unique keys requested in one trip to SQL server.
666  @returns a created sequence object.
667 }
668 function TZOracleConnection.CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence;
669 begin
670  Result := TZOracleSequence.Create(Self, Sequence, BlockSize);
671 end;
672 {**
673  Gets a Oracle plain driver interface.
674  @return a Oracle plain driver interface.
675 }
676 function TZOracleConnection.GetPlainDriver: IZOraclePlainDriver;
677 begin
678  Result := PlainDriver as IZOraclePlainDriver;
679 end;
680 
681 {**
682  Gets a reference to Oracle connection handle.
683  @return a reference to Oracle connection handle.
684 }
685 function TZOracleConnection.GetConnectionHandle: POCIEnv;
686 begin
687  Result := FHandle;
688 end;
689 
690 {**
691  Gets a reference to Oracle context handle.
692  @return a reference to Oracle context handle.
693 }
694 function TZOracleConnection.GetContextHandle: POCISvcCtx;
695 begin
696  Result := FContextHandle;
697 end;
698 
699 {**
700  Gets a reference to Oracle error handle.
701  @return a reference to Oracle error handle.
702 }
703 function TZOracleConnection.GetErrorHandle: POCIError;
704 begin
705  Result := FErrorHandle;
706 end;
707 
708 {**
709  Gets a reference to Oracle server handle.
710  @return a reference to Oracle server handle.
711 }
712 function TZOracleConnection.GetServerHandle: POCIServer;
713 begin
714  Result := FServerHandle;
715 end;
716 
717 {**
718  Gets a reference to Oracle session handle.
719  @return a reference to Oracle session handle.
720 }
721 function TZOracleConnection.GetSessionHandle: POCISession;
722 begin
723  Result := FSessionHandle;
724 end;
725 
726 {**
727  Gets a reference to Oracle transaction handle.
728  @return a reference to Oracle transacton handle.
729 }
730 function TZOracleConnection.GetTransactionHandle: POCITrans;
731 begin
732  Result := FTransHandle;
733 end;
734 
735 {**
736  Gets a reference to Oracle describe handle.
737  @return a reference to Oracle describe handle.
738 }
739 function TZOracleConnection.GetDescribeHandle: POCIDescribe;
740 begin
741  Result := FDescibeHandle;
742 end;
743 
744 function TZOracleConnection.GetClientVersion: Integer;
745 var
746  major_version, minor_version, update_num,
747  patch_num, port_update_num: sword;
748 begin
749  GetPlainDriver.ClientVersion(@major_version, @minor_version, @update_num,
750  @patch_num, @port_update_num);
751  Result := EncodeSQLVersioning(major_version,minor_version,update_num);
752 end;
753 
754 function TZOracleConnection.GetHostVersion: Integer;
755 var
756  buf:text;
757  version:ub4;
758 begin
759  result:=0;
760  getmem(buf,1024);
761  if GetPlainDriver.ServerRelease(FServerHandle,FErrorHandle,buf,1024,OCI_HTYPE_SERVER,@version)=OCI_SUCCESS then
762  Result := EncodeSQLVersioning((version shr 24) and $ff,(version shr 20) and $f,(version shr 12) and $ff);
763  freemem(buf);
764 end;
765 
766 function TZOracleConnection.GetBinaryEscapeString(const Value: TByteDynArray): String;
767 var
768  tmp: RawByteString;
769  L: Integer;
770 begin
771  L := Length(Value);
772  SetLength(tmp, L*2);
773  BinToHex(PAnsiChar(Value), PAnsiChar(tmp), L);
774  Result := #39+String(tmp)+#39;
775  if GetAutoEncodeStrings then
776  Result := GetDriver.GetTokenizer.GetEscapeString(Result)
777 end;
778 
779 function TZOracleConnection.GetBinaryEscapeString(const Value: RawByteString): String;
780 var
781  tmp: RawByteString;
782  L: Integer;
783 begin
784  L := Length(Value);
785  SetLength(tmp, L*2);
786  BinToHex(PAnsiChar(Value), PAnsiChar(tmp), L);
787  if GetAutoEncodeStrings then
788  Result := GetDriver.GetTokenizer.GetEscapeString(Result)
789 end;
790 
791 { TZOracleSequence }
792 
793 {**
794  Gets the current unique key generated by this sequence.
795  @param the last generated unique key.
796 }
797 function TZOracleSequence.GetCurrentValue: Int64;
798 var
799  Statement: IZStatement;
800  ResultSet: IZResultSet;
801 begin
802  Statement := Connection.CreateStatement;
803  ResultSet := Statement.ExecuteQuery(
804  Format('SELECT %s.CURRVAL FROM DUAL', [Name]));
805  if ResultSet.Next then
806  Result := ResultSet.GetLong(1)
807  else
808  Result := inherited GetCurrentValue;
809  ResultSet.Close;
810  Statement.Close;
811 end;
812 
813 function TZOracleSequence.GetCurrentValueSQL: String;
814 begin
815  result:=Format('SELECT %s.CURRVAL FROM DUAL', [Name]);
816 end;
817 
818 {**
819  Gets the next unique key generated by this sequence.
820  @param the next generated unique key.
821 }
822 function TZOracleSequence.GetNextValue: Int64;
823 var
824  Statement: IZStatement;
825  ResultSet: IZResultSet;
826 begin
827  Statement := Connection.CreateStatement;
828  ResultSet := Statement.ExecuteQuery(
829  Format('SELECT %s.NEXTVAL FROM DUAL', [Name]));
830  if ResultSet.Next then
831  Result := ResultSet.GetLong(1)
832  else
833  Result := inherited GetNextValue;
834  ResultSet.Close;
835  Statement.Close;
836 end;
837 
838 
839 function TZOracleSequence.GetNextValueSQL: String;
840 begin
841  result:=Format('SELECT %s.NEXTVAL FROM DUAL', [Name]);
842 end;
843 
844 { TZOracleCachedResolver }
845 
846 {**
847  Forms a where clause for SELECT statements to calculate default values.
848  @param Columns a collection of key columns.
849  @param OldRowAccessor an accessor object to old column values.
850 }
851 function TZOracleCachedResolver.FormCalculateStatement(
852  Columns: TObjectList): string;
853 var
854  iPos: Integer;
855 begin
856  Result := inherited FormCalculateStatement(Columns);
857  if Result <> '' then
858  begin
859  iPos := pos('FROM', uppercase(Result));
860  if iPos > 0 then
861  begin
862  Result := copy(Result, 1, iPos+3) + ' DUAL';
863  end
864  else
865  begin
866  Result := Result + ' FROM DUAL';
867  end;
868  end;
869 end;
870 
871 initialization
872  OracleDriver := TZOracleDriver.Create;
873  DriverManager.RegisterDriver(OracleDriver);
874 finalization
875  if DriverManager <> nil then
876  DriverManager.DeregisterDriver(OracleDriver);
877  OracleDriver := nil;
878 end.
879