1 {*********************************************************}
3 { Zeos Database Objects }
4 { Oracle Database Connectivity Classes }
6 { Originally written by Sergey Seroukhov }
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 {********************************************************@}
52 unit ZDbcOracleStatement;
59 Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Types,
60 ZSysUtils, ZDbcIntfs, ZDbcStatement, ZDbcLogging, ZPlainOracleDriver,
61 ZCompatibility, ZVariant, ZDbcOracleUtils, ZPlainOracleConstants;
65 {** Defines a Oracle specific statement. }
66 IZOracleStatement = interface(IZStatement)
67 ['{8644E5B6-1E0F-493F-B6AC-40D70CCEA13A}']
69 function GetStatementHandle: POCIStmt;
72 {** Implements Generic Oracle Statement. }
73 TZOracleStatement = class(TZAbstractStatement, IZOracleStatement)
75 FPlainDriver: IZOraclePlainDriver;
78 constructor Create(PlainDriver: IZOraclePlainDriver;
79 Connection: IZConnection; Info: TStrings);
80 destructor Destroy; override;
82 function ExecuteQuery(const SQL: RawByteString): IZResultSet; override;
83 function ExecuteUpdate(const SQL: RawByteString): Integer; override;
84 function Execute(const SQL: RawByteString): Boolean; override;
86 function GetStatementHandle: POCIStmt;
89 {** Implements Prepared SQL Statement. }
90 TZOraclePreparedStatement = class(TZAbstractPreparedStatement)
94 FErrorHandle: POCIError;
95 FPlainDriver: IZOraclePlainDriver;
96 FExecStatement: IZStatement;
97 FLastStatement: IZStatement;
100 procedure SetLastStatement(LastStatement: IZStatement);
101 function GetExecStatement: IZStatement;
102 function ConvertToOracleSQLQuery(SQL: string): RawByteString;
105 property Prepared: Boolean read FPrepared write FPrepared;
106 property Handle: POCIStmt read FHandle write FHandle;
107 property ErrorHandle: POCIError read FErrorHandle write FErrorHandle;
108 property ExecStatement: IZStatement read FExecStatement write FExecStatement;
109 property LastStatement: IZStatement read FLastStatement write SetLastStatement;
110 property InVars: PZSQLVars read FInVars write FInVars;
112 constructor Create(PlainDriver: IZOraclePlainDriver;
113 Connection: IZConnection; const SQL: string; Info: TStrings);
114 destructor Destroy; override;
116 procedure Close; override;
117 procedure Prepare; override;
118 function ExecuteQuery(const SQL: RawByteString): IZResultSet; override;
119 function ExecuteUpdate(const SQL: RawByteString): Integer; override;
120 function Execute(const SQL: RawByteString): Boolean; override;
122 function ExecuteQueryPrepared: IZResultSet; override;
123 function ExecuteUpdatePrepared: Integer; override;
124 function ExecutePrepared: Boolean; override;
126 function GetStatementHandle: POCIStmt;
129 TZOracleCallableStatement = class(TZAbstractCallableStatement,
130 IZParamNamedCallableStatement)
132 FOutParamCount: Integer;
133 FErrorHandle: POCIError;
135 FPlainDriver:IZOraclePlainDriver;
138 FOracleParams: TZOracleParams;
139 FOracleParamsCount: Integer;
140 FParamNames: TStringDynArray;
141 PackageIncludedList: TStrings;
142 procedure ArrangeInParams;
143 procedure FetchOutParamsFromOracleVars;
145 function GetProcedureSql(SelectProc: boolean): RawByteString;
146 procedure SetInParam(ParameterIndex: Integer; SQLType: TZSQLType;
147 const Value: TZVariant); override;
148 procedure RegisterParamTypeAndName(const ParameterIndex:integer;
149 const ParamTypeName, ParamName: String; Const ColumnSize, Precision: Integer);
151 procedure RegisterOutParameter(ParameterIndex: Integer; SQLType: Integer); override;
152 procedure RegisterParamType(ParameterIndex: integer; ParamType: Integer); override;
153 procedure Prepare; override;
154 function IsNull(ParameterIndex: Integer): Boolean;override;
156 Function ExecuteUpdatePrepared: Integer; override;
157 function ExecuteQueryPrepared: IZResultSet; override;
158 constructor Create(Connection: IZConnection; const pProcName: string; Info: TStrings);
159 destructor Destroy; override;
160 procedure ClearParameters; override;
166 ZTokenizer, ZDbcOracle, ZDbcOracleResultSet
167 {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF};
169 { TZOracleStatement }
172 Constructs this object and assignes the main properties.
173 @param PlainDriver a Oracle plain driver.
174 @param Connection a database connection object.
175 @param Info a statement parameters.
176 @param Handle a connection handle pointer.
178 constructor TZOracleStatement.Create(PlainDriver: IZOraclePlainDriver;
179 Connection: IZConnection; Info: TStrings);
181 inherited Create(Connection, Info);
182 FPlainDriver := PlainDriver;
183 ResultSetType := rtForwardOnly;
187 Destroys this object and cleanups the memory.
189 destructor TZOracleStatement.Destroy;
195 Executes an SQL statement that returns a single <code>ResultSet</code> object.
196 @param sql typically this is a static SQL <code>SELECT</code> statement
197 @return a <code>ResultSet</code> object that contains the data produced by the
198 given query; never <code>null</code>
200 function TZOracleStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet;
203 ErrorHandle: POCIError;
205 AllocateOracleStatementHandles(FPlainDriver, Connection, Handle, ErrorHandle);
208 PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, Handle, ErrorHandle,
209 StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings);
210 Result := CreateOracleResultSet(FPlainDriver, Self, LogSQL,
211 Handle, ErrorHandle);
213 FreeOracleStatementHandles(FPlainDriver, Handle, ErrorHandle);
217 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
221 Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
222 <code>DELETE</code> statement. In addition,
223 SQL statements that return nothing, such as SQL DDL statements,
226 @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
227 <code>DELETE</code> statement or an SQL statement that returns nothing
228 @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
229 or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
231 function TZOracleStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
234 ErrorHandle: POCIError;
236 AllocateOracleStatementHandles(FPlainDriver, Connection, Handle, ErrorHandle);
239 PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, Handle, ErrorHandle,
240 StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings);
241 ExecuteOracleStatement(FPlainDriver, Connection, LogSQL, Handle, ErrorHandle);
242 Result := GetOracleUpdateCount(FPlainDriver, Handle, ErrorHandle);
244 FreeOracleStatementHandles(FPlainDriver, Handle, ErrorHandle);
247 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
249 { Autocommit statement. }
250 if Connection.GetAutoCommit then
255 Executes an SQL statement that may return multiple results.
256 Under some (uncommon) situations a single SQL statement may return
257 multiple result sets and/or update counts. Normally you can ignore
258 this unless you are (1) executing a stored procedure that you know may
259 return multiple results or (2) you are dynamically executing an
260 unknown SQL string. The methods <code>execute</code>,
261 <code>getMoreResults</code>, <code>getResultSet</code>,
262 and <code>getUpdateCount</code> let you navigate through multiple results.
264 The <code>execute</code> method executes an SQL statement and indicates the
265 form of the first result. You can then use the methods
266 <code>getResultSet</code> or <code>getUpdateCount</code>
267 to retrieve the result, and <code>getMoreResults</code> to
268 move to any subsequent result(s).
270 @param sql any SQL statement
271 @return <code>true</code> if the next result is a <code>ResultSet</code> object;
272 <code>false</code> if it is an update count or there are no more results
274 function TZOracleStatement.Execute(const SQL: RawByteString): Boolean;
277 ErrorHandle: POCIError;
281 AllocateOracleStatementHandles(FPlainDriver, Connection, Handle, ErrorHandle);
284 PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, Handle, ErrorHandle,
285 StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings);
288 FPlainDriver.AttrGet(Handle, OCI_HTYPE_STMT, @StatementType, nil,
289 OCI_ATTR_STMT_TYPE, ErrorHandle);
291 if StatementType = OCI_STMT_SELECT then
293 LastResultSet := CreateOracleResultSet(FPlainDriver, Self,
294 LogSQL, Handle, ErrorHandle);
295 Result := LastResultSet <> nil;
299 ExecuteOracleStatement(FPlainDriver, Connection, LogSQL,
300 Handle, ErrorHandle);
301 LastUpdateCount := GetOracleUpdateCount(FPlainDriver, Handle, ErrorHandle);
305 FreeOracleStatementHandles(FPlainDriver, Handle, ErrorHandle);
308 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
310 { Autocommit statement. }
311 if not Result and Connection.GetAutoCommit then
316 Gets statement handle.
317 @return statement handle.
319 function TZOracleStatement.GetStatementHandle: POCIStmt;
324 { TZOraclePreparedStatement }
327 Constructs this object and assignes the main properties.
328 @param PlainDriver a Oracle plain driver.
329 @param Connection a database connection object.
330 @param Info a statement parameters.
331 @param Handle a connection handle pointer.
333 constructor TZOraclePreparedStatement.Create(
334 PlainDriver: IZOraclePlainDriver; Connection: IZConnection;
335 const SQL: string; Info: TStrings);
337 inherited Create(Connection, SQL, Info);
338 FPlainDriver := PlainDriver;
339 ResultSetType := rtForwardOnly;
340 ASQL := ConvertToOracleSQLQuery(SQL);
345 Destroys this object and cleanups the memory.
347 destructor TZOraclePreparedStatement.Destroy;
353 Sets a reference to the last statement.
354 @param LastStatement the last statement interface.
356 procedure TZOraclePreparedStatement.SetLastStatement(
357 LastStatement: IZStatement);
359 if FLastStatement <> nil then
360 FLastStatement.Close;
361 FLastStatement := LastStatement;
365 Creates a temporary statement which executes queries.
366 @param Info a statement parameters.
367 @return a created statement object.
369 function TZOraclePreparedStatement.GetExecStatement: IZStatement;
371 if ExecStatement = nil then
373 ExecStatement := TZOracleStatement.Create(FPlainDriver, Connection, Info);
375 ExecStatement.SetMaxFieldSize(GetMaxFieldSize);
376 ExecStatement.SetMaxRows(GetMaxRows);
377 ExecStatement.SetEscapeProcessing(EscapeProcessing);
378 ExecStatement.SetQueryTimeout(GetQueryTimeout);
379 ExecStatement.SetCursorName(CursorName);
381 ExecStatement.SetFetchDirection(GetFetchDirection);
382 ExecStatement.SetFetchSize(GetFetchSize);
383 ExecStatement.SetResultSetConcurrency(GetResultSetConcurrency);
384 ExecStatement.SetResultSetType(GetResultSetType);
386 Result := ExecStatement;
390 Converts an SQL query into Oracle format.
391 @param SQL a query with parameters defined with '?'
392 @returns a query with parameters in Oracle format ':pN'.
394 function TZOraclePreparedStatement.ConvertToOracleSQLQuery(SQL: string): RawByteString;
399 if Pos('?', SQL) > 0 then
401 Tokens := Connection.GetDriver.GetTokenizer.
402 TokenizeBufferToList(SQL, [toUnifyWhitespaces]);
406 for I := 0 to Tokens.Count - 1 do
407 if Tokens[I] = '?' then
410 Result := Result + ':P' + RawByteString(IntToStr(N));
412 Result := Result + ZPlainString(Tokens[I]);
417 Result := GetEncodedSQL(SQL);
421 Closes this statement and frees all resources.
423 procedure TZOraclePreparedStatement.Close;
426 if LastStatement <> nil then
428 FLastStatement.Close;
429 FLastStatement := nil;
431 FreeOracleStatementHandles(FPlainDriver, FHandle, FErrorHandle);
432 FreeOracleSQLVars(FPlainDriver, FInVars, (Connection as IZOracleConnection).GetConnectionHandle, FErrorHandle, ConSettings);
436 Executes an SQL statement that may return multiple results.
437 Under some (uncommon) situations a single SQL statement may return
438 multiple result sets and/or update counts. Normally you can ignore
439 this unless you are (1) executing a stored procedure that you know may
440 return multiple results or (2) you are dynamically executing an
441 unknown SQL string. The methods <code>execute</code>,
442 <code>getMoreResults</code>, <code>getResultSet</code>,
443 and <code>getUpdateCount</code> let you navigate through multiple results.
445 The <code>execute</code> method executes an SQL statement and indicates the
446 form of the first result. You can then use the methods
447 <code>getResultSet</code> or <code>getUpdateCount</code>
448 to retrieve the result, and <code>getMoreResults</code> to
449 move to any subsequent result(s).
451 @param sql any SQL statement
452 @return <code>true</code> if the next result is a <code>ResultSet</code> object;
453 <code>false</code> if it is an update count or there are no more results
455 function TZOraclePreparedStatement.Execute(const SQL: RawByteString): Boolean;
457 LastStatement := GetExecStatement;
458 Result := LastStatement.Execute(SQL);
460 LastResultSet := LastStatement.GetResultSet
462 LastUpdateCount := LastStatement.GetUpdateCount;
466 Executes an SQL statement that returns a single <code>ResultSet</code> object.
467 @param sql typically this is a static SQL <code>SELECT</code> statement
468 @return a <code>ResultSet</code> object that contains the data produced by the
469 given query; never <code>null</code>
471 function TZOraclePreparedStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet;
473 Result := GetExecStatement.ExecuteQuery(SQL);
477 Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
478 <code>DELETE</code> statement. In addition,
479 SQL statements that return nothing, such as SQL DDL statements,
482 @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
483 <code>DELETE</code> statement or an SQL statement that returns nothing
484 @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
485 or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
487 function TZOraclePreparedStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
489 Result := GetExecStatement.ExecuteUpdate(SQL);
490 LastUpdateCount := Result;
494 Prepares an SQL statement
496 procedure TZOraclePreparedStatement.Prepare;
501 CurrentVar: PZSQLVar;
505 { Allocates statement handles. }
506 if (FHandle = nil) or (FErrorHandle = nil) then
508 AllocateOracleStatementHandles(FPlainDriver, Connection,
509 FHandle, FErrorHandle);
512 PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, Handle, ErrorHandle,
513 StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings);
515 AllocateOracleSQLVars(FInVars, InParamCount);
516 InVars^.ActualNum := InParamCount;
518 for I := 0 to InParamCount - 1 do
520 CurrentVar := @FInVars.Variables[I + 1];
521 CurrentVar.Handle := nil;
523 { Artificially define Oracle internal type. }
524 if InParamTypes[I] in [stBytes, stBinaryStream] then
525 TypeCode := SQLT_BLOB
526 else if InParamTypes[I] = stAsciiStream then
527 TypeCode := SQLT_CLOB
528 else if InParamTypes[I] = stUnicodeStream then
529 TypeCode := SQLT_CLOB
530 else TypeCode := SQLT_STR;
532 InitializeOracleVar(FPlainDriver, Connection, CurrentVar,
533 InParamTypes[I], TypeCode, 1024);
535 Status := FPlainDriver.BindByPos(FHandle, CurrentVar.BindHandle,
536 FErrorHandle, I + 1, CurrentVar.Data, CurrentVar.Length,
537 CurrentVar.TypeCode, @CurrentVar.Indicator, nil, nil, 0, nil,
539 CheckOracleError(FPlainDriver, FErrorHandle, Status, lcExecute, LogSQL);
542 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
548 Executes the SQL query in this <code>PreparedStatement</code> object
549 and returns the result set generated by the query.
551 @return a <code>ResultSet</code> object that contains the data produced by the
552 query; never <code>null</code>
554 function TZOraclePreparedStatement.ExecutePrepared: Boolean;
560 { Prepares a statement. }
564 { Loads binded variables with values. }
565 LoadOracleVars(FPlainDriver, Connection, ErrorHandle,
566 FInVars, InParamValues, ChunkSize);
569 FPlainDriver.AttrGet(Handle, OCI_HTYPE_STMT, @StatementType, nil,
570 OCI_ATTR_STMT_TYPE, ErrorHandle);
572 if StatementType = OCI_STMT_SELECT then
574 { Executes the statement and gets a resultset. }
575 LastResultSet := CreateOracleResultSet(FPlainDriver, Self,
576 SQL, Handle, ErrorHandle);
577 Result := LastResultSet <> nil;
581 { Executes the statement and gets a result. }
582 ExecuteOracleStatement(FPlainDriver, Connection, LogSQL,
583 Handle, ErrorHandle);
584 LastUpdateCount := GetOracleUpdateCount(FPlainDriver, Handle, ErrorHandle);
587 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
589 { Unloads binded variables with values. }
590 UnloadOracleVars(FInVars);
592 { Autocommit statement. }
593 if not Result and Connection.GetAutoCommit then
598 Executes the SQL query in this <code>PreparedStatement</code> object
599 and returns the result set generated by the query.
601 @return a <code>ResultSet</code> object that contains the data produced by the
602 query; never <code>null</code>
604 function TZOraclePreparedStatement.ExecuteQueryPrepared: IZResultSet;
606 { Prepares a statement. }
610 { Loads binded variables with values. }
611 LoadOracleVars(FPlainDriver, Connection, ErrorHandle,
612 FInVars, InParamValues,ChunkSize);
614 { Executes the statement and gets a resultset. }
615 Result := CreateOracleResultSet(FPlainDriver, Self, SQL,
616 Handle, ErrorHandle);
618 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SQL);
620 { Unloads binded variables with values. }
621 UnloadOracleVars(FInVars);
625 Executes the SQL INSERT, UPDATE or DELETE statement
626 in this <code>PreparedStatement</code> object.
628 SQL statements that return nothing, such as SQL DDL statements,
631 @return either the row count for INSERT, UPDATE or DELETE statements;
632 or 0 for SQL statements that return nothing
634 function TZOraclePreparedStatement.ExecuteUpdatePrepared: Integer;
637 ResultSet: IZResultSet;
639 { Prepares a statement. }
643 { Loads binded variables with values. }
644 LoadOracleVars(FPlainDriver, Connection, ErrorHandle,
645 FInVars, InParamValues, ChunkSize);
649 FPlainDriver.AttrGet(Handle, OCI_HTYPE_STMT, @StatementType, nil,
650 OCI_ATTR_STMT_TYPE, ErrorHandle);
652 if StatementType = OCI_STMT_SELECT then
654 { Executes the statement and gets a resultset. }
655 ResultSet := CreateOracleResultSet(FPlainDriver, Self,
656 SQL, Handle, ErrorHandle);
658 while ResultSet.Next do;
659 LastUpdateCount := ResultSet.GetRow;
666 { Executes the statement and gets a result. }
667 ExecuteOracleStatement(FPlainDriver, Connection, LogSQL,
668 Handle, ErrorHandle);
669 LastUpdateCount := GetOracleUpdateCount(FPlainDriver, Handle, ErrorHandle);
671 Result := LastUpdateCount;
673 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
675 { Unloads binded variables with values. }
676 UnloadOracleVars(FInVars);
679 { Autocommit statement. }
680 if Connection.GetAutoCommit then
685 Gets statement handle.
686 @return statement handle.
688 function TZOraclePreparedStatement.GetStatementHandle: POCIStmt;
693 procedure TZOracleCallableStatement.Prepare;
698 CurrentVar: PZSQLVar;
701 if not FPrepared then
703 ArrangeInParams; //need to sort ReturnValues for functions
704 ASQL := GetProcedureSql(False);
705 SetLength(FParamNames, FOracleParamsCount);
706 for i := 0 to FOracleParamsCount -1 do
707 FParamNames[I] := Self.FOracleParams[I].pName;
709 { Allocates statement handles. }
710 if (FHandle = nil) or (FErrorHandle = nil) then
712 AllocateOracleStatementHandles(FPlainDriver, Connection,
713 FHandle, FErrorHandle);
716 PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, FHandle, FErrorHandle,
717 StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings);
718 //make sure eventual old buffers are cleaned
719 FreeOracleSQLVars(FPlainDriver, FInVars, (Connection as IZOracleConnection).GetConnectionHandle, FErrorHandle, ConSettings);
720 AllocateOracleSQLVars(FInVars, FOracleParamsCount);
721 FInVars^.ActualNum := FOracleParamsCount;
723 for I := 0 to FOracleParamsCount - 1 do
725 CurrentVar := @FInVars.Variables[I + 1];
726 CurrentVar.Handle := nil;
727 SQLType := TZSQLType(FOracleParams[I].pSQLType);
729 { Artificially define Oracle internal type. }
730 if SQLType = stBinaryStream then
731 TypeCode := SQLT_BLOB
732 else if SQLType in [stAsciiStream, stUnicodeStream] then
733 TypeCode := SQLT_CLOB
734 else TypeCode := SQLT_STR;
736 InitializeOracleVar(FPlainDriver, Connection, CurrentVar,
737 SQLType, TypeCode, 1024);
739 Status := FPlainDriver.BindByPos(FHandle, CurrentVar.BindHandle,
740 FErrorHandle, I + 1, CurrentVar.Data, CurrentVar.Length,
741 CurrentVar.TypeCode, @CurrentVar.Indicator, nil, nil, 0, nil,
743 CheckOracleError(FPlainDriver, FErrorHandle, Status, lcExecute, LogSQL);
745 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
750 procedure TZOracleCallableStatement.RegisterOutParameter(ParameterIndex,
753 inherited RegisterOutParameter(ParameterIndex,SQLType);
754 with FOracleParams[ParameterIndex-1] do
756 if not GetConnection.UseMetadata then
757 pName := 'pOut'+IntToStr(ParameterIndex);
762 procedure TZOracleCallableStatement.RegisterParamType(ParameterIndex: integer;
765 inherited RegisterParamType(ParameterIndex, ParamType);
766 if ParameterIndex > High(FOracleParams) then
767 SetLength(FOracleParams, ParameterIndex);
768 if ParameterIndex > FOracleParamsCount then
769 FOracleParamsCount := ParameterIndex;
770 FOracleParams[ParameterIndex-1].pType := ParamType;
771 FOracleParams[ParameterIndex-1].pParamIndex := ParameterIndex;
772 if ParamType in [2,3,4] then //ptInOut, ptOut, ptResult
775 FOracleParams[ParameterIndex-1].pOutIndex := FOutParamCount;
779 procedure TZOracleCallableStatement.SetInParam(ParameterIndex: Integer;
780 SQLType: TZSQLType; const Value: TZVariant);
782 AConnection: IZConnection;
784 function GetOracleParamIndexOfParameterIndex: Integer;
788 for i := 0 to high(FOracleParams) do
789 if ParameterIndex = FOracleParams[i].pParamIndex then
797 inherited SetInParam(ParameterIndex, SQLType, Value);
798 with FOracleParams[GetOracleParamIndexOfParameterIndex] do
800 AConnection := GetConnection;
801 if Assigned(AConnection) and ( not AConnection.UseMetadata ) then
802 pName := 'p'+IntToStr(ParameterIndex);
803 pSQLType := ord(SQLType);
808 procedure TZOracleCallableStatement.RegisterParamTypeAndName(const ParameterIndex: integer;
809 const ParamTypeName, ParamName: String; Const ColumnSize, Precision: Integer);
814 FOracleParams[ParameterIndex].pName := ParamName;
815 FOracleParams[ParameterIndex].pTypeName := ParamTypeName;
816 iPos := Pos('.', ParamName);
819 ProcName := Copy(ParamName, 1, iPos-1); //extract function or Procedure names
820 FOracleParams[ParameterIndex].pProcIndex := PackageIncludedList.IndexOf(ProcName); //check index
821 if FOracleParams[ParameterIndex].pProcIndex = -1 then //if not exists
822 FOracleParams[ParameterIndex].pProcIndex := PackageIncludedList.Add(ProcName); //Add to List
825 FOracleParams[ParameterIndex].pProcIndex := 0;
828 procedure TZOracleCallableStatement.ArrangeInParams;
830 I, J, NewProcIndex, StartProcIndex: Integer;
831 TempVars: TZVariantDynArray;
832 TempOraVar: TZOracleParam;
838 for i := 0 to high(FOracleParams) do
840 if not ( FOracleParams[i].pProcIndex = NewProcIndex ) then
842 NewProcIndex := FOracleParams[i].pProcIndex;
845 if ( FOracleParams[i].pType = 4 ) then
847 DefVarManager.SetNull(FOracleParams[i].pValue);
848 if not (i = StartProcIndex) then
850 TempOraVar := FOracleParams[I];
851 for J := I downto StartProcIndex+1 do
852 FOracleParams[j] := FOracleParams[j-1];
853 FOracleParams[StartProcIndex] := TempOraVar;
857 SetLength(TempVars, Length(FOracleParams));
858 for i := 0 to high(FOracleParams) do
859 TempVars[i] := FOracleParams[i].pValue;
860 InParamValues := TempVars;
864 procedure TZOracleCallableStatement.FetchOutParamsFromOracleVars;
866 CurrentVar: PZSQLVar;
867 LobLocator: POCILobLocator;
871 procedure SetOutParam(CurrentVar: PZSQLVar; Index: Integer);
873 OracleConnection :IZOracleConnection;
875 Month, Day:Byte; Hour, Min, Sec:ub1; MSec: ub4;
879 case CurrentVar.TypeCode of
880 SQLT_INT: DefVarManager.SetAsInteger( outParamValues[Index], PLongInt(CurrentVar.Data)^ );
881 SQLT_FLT: DefVarManager.SetAsFloat( outParamValues[Index], PDouble(CurrentVar.Data)^ );
886 {$IFDEF WITH_STRLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrLCopy( ps, (CurrentVar.Data), 1024);
887 DefVarManager.SetAsString( OutParamValues[Index], ZDbcString(ps) );
894 OracleConnection := Connection as IZOracleConnection;
895 FPlainDriver.DateTimeGetDate(
896 OracleConnection.GetConnectionHandle ,
897 FErrorHandle, PPOCIDescriptor(CurrentVar.Data)^,
899 FPlainDriver.DateTimeGetTime(
900 OracleConnection.GetConnectionHandle ,
901 FErrorHandle, PPOCIDescriptor(CurrentVar.Data)^,
902 Hour, Min, Sec,MSec);
903 dTmp := EncodeDate(year,month,day )+EncodeTime(Hour,min,sec,msec) ;
904 DefVarManager.SetAsDateTime( outParamValues[Index], dTmp );
906 SQLT_BLOB, SQLT_CLOB, SQLT_BFILEE, SQLT_CFILEE:
908 if CurrentVar.Indicator >= 0 then
909 LobLocator := PPOCIDescriptor(CurrentVar.Data)^
913 OracleConnection := Connection as IZOracleConnection;
914 TempBlob := TZOracleBlob.Create(FPlainDriver, nil, 0, OracleConnection,
915 LobLocator, CurrentVar.ColType, GetChunkSize);
916 (TempBlob as IZOracleBlob).ReadBlob;
917 DefVarManager.SetAsInterface(outParamValues[Index], TempBlob);
921 DefVarManager.SetAsInterface(outParamValues[Index],
922 TZOracleBlob.CreateWithStream(nil, GetConnection));
926 for I := 0 to FOracleParamsCount -1 do
927 if FOracleParams[i].pType in [2,3,4] then
929 CurrentVar:= @FInVars.Variables[I+1];
930 CurrentVar.Data := CurrentVar.DupData;
931 SetOutParam(CurrentVar, FOracleParams[i].pParamIndex-1);
935 function TZOracleCallableStatement.GetProcedureSql(SelectProc: boolean): RawByteString;
938 I, IncludeCount, LastIndex: Integer;
939 PackageBody: TStrings;
942 function GenerateParamsStr(Count: integer): string;
946 for I := 0 to Count - 1 do
948 if ( FDBParamTypes[I] = 4 ) then //ptResult
950 sFunc := ' :'+FOracleParams[0].pName+' := ';
954 Result := Result + ',';
956 Result := Result + ':'+FOracleParams[I+1].pName
958 Result := Result + ':'+FOracleParams[I].pName;
960 Result := '('+Result+')'
967 if PackageIncludedList.Count > 0 then
969 PackageBody := TStringList.Create;
970 PackageBody.Add('BEGIN');
972 for IncludeCount := 0 to PackageIncludedList.Count -1 do
976 for i := LastIndex to high(FOracleParams) do
977 if IncludeCount = FOracleParams[i].pProcIndex then
978 if ( FOracleParams[I].pType = 4 ) then //ptResult
979 sFunc := ' :'+StringReplace(FOracleParams[I].pName, '.', '', [rfReplaceAll])+' := '
981 if InParams <> '' then
982 InParams := InParams +', :'+StringReplace(FOracleParams[I].pName, '.', '', [rfReplaceAll])
984 InParams := InParams +':'+StringReplace(FOracleParams[I].pName, '.', '', [rfReplaceAll])
990 PackageBody.Add('BEGIN '+sFunc+SQL+
991 '.'+GetConnection.GetMetadata.GetIdentifierConvertor.Quote(PackageIncludedList[IncludeCount])+'('+InParams+'); END;');
993 PackageBody.Add('END;');
994 TempResult := TrimRight(PackageBody.Text);
995 FreeAndNil(PackageBody);
999 InParams := GenerateParamsStr( FOracleParamsCount );
1000 TempResult := 'BEGIN ' + sFunc +SQL + InParams+'; END;';
1002 Result := ZPlainString(TempResult);
1005 function TZOracleCallableStatement.IsNull(ParameterIndex: Integer): Boolean;
1007 result := inherited IsNull(ParameterIndex);
1010 procedure TZOracleCallableStatement.ClearParameters;
1013 FOracleParamsCount := 0;
1014 SetLength(FOracleParams, 0);
1017 constructor TZOracleCallableStatement.Create(Connection: IZConnection;
1018 const pProcName: string; Info: TStrings);
1021 inherited Create(Connection, pProcName, Info);
1023 FOracleParamsCount := 0;
1024 FPlainDriver := Connection.GetIZPlainDriver as IZOraclePlainDriver;
1025 ResultSetType := rtForwardOnly;
1027 PackageIncludedList := TStringList.Create;
1028 FOutParamCount := 0;
1031 destructor TZOracleCallableStatement.Destroy;
1033 FreeOracleSQLVars(FPlainDriver, FInVars, (Connection as IZOracleConnection).GetConnectionHandle, FErrorHandle, ConSettings);
1034 PackageIncludedList.Free;
1038 function TZOracleCallableStatement.ExecuteUpdatePrepared: Integer;
1040 { Prepares a statement. }
1041 if not Prepared then
1044 { Loads binded variables with values. }
1045 LoadOracleVars(FPlainDriver , Connection, FErrorHandle,
1046 FInVars, InParamValues, ChunkSize);
1049 ExecuteOracleStatement(FPlainDriver, Connection, LogSQL,
1050 FHandle, FErrorHandle);
1051 LastUpdateCount := GetOracleUpdateCount(FPlainDriver, FHandle, FErrorHandle);
1052 FetchOutParamsFromOracleVars;
1053 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
1055 { Unloads binded variables with values. }
1056 UnloadOracleVars(FInVars);
1059 { Autocommit statement. }
1060 if Connection.GetAutoCommit then
1063 Result := LastUpdateCount;
1066 function TZOracleCallableStatement.ExecuteQueryPrepared: IZResultSet;
1068 { Prepares a statement. }
1069 if not Prepared then
1072 { Loads binded variables with values. }
1073 LoadOracleVars(FPlainDriver , Connection, FErrorHandle,
1074 FInVars, InParamValues, ChunkSize);
1077 ExecuteOracleStatement(FPlainDriver, Connection, LogSQL,
1078 FHandle, FErrorHandle);
1079 FetchOutParamsFromOracleVars;
1080 LastResultSet := CreateOracleResultSet(FPlainDriver, Self, LogSQL,
1081 FHandle, FErrorHandle, FInVars, FOracleParams);
1082 Result := LastResultSet;
1083 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
1085 { Unloads binded variables with values. }
1086 UnloadOracleVars(FInVars);