1 {*********************************************************}
3 { Zeos Database Objects }
4 { Abstract StoredProc component }
6 { Originally written by Sergey Seroukhov }
7 { & Janos Fegyverneki }
9 {*********************************************************}
11 {@********************************************************}
12 { Copyright (c) 1999-2012 Zeos Development Group }
14 { License Agreement: }
16 { This library is distributed in the hope that it will be }
17 { useful, but WITHOUT ANY WARRANTY; without even the }
18 { implied warranty of MERCHANTABILITY or FITNESS FOR }
19 { A PARTICULAR PURPOSE. See the GNU Lesser General }
20 { Public License for more details. }
22 { The source code of the ZEOS Libraries and packages are }
23 { distributed under the Library GNU General Public }
24 { License (see the file COPYING / COPYING.ZEOS) }
25 { with the following modification: }
26 { As a special exception, the copyright holders of this }
27 { library give you permission to link this library with }
28 { independent modules to produce an executable, }
29 { regardless of the license terms of these independent }
30 { modules, and to copy and distribute the resulting }
31 { executable under terms of your choice, provided that }
32 { you also meet, for each linked independent module, }
33 { the terms and conditions of the license of that module. }
34 { An independent module is a module which is not derived }
35 { from or based on this library. If you modify this }
36 { library, you may extend this exception to your version }
37 { of the library, but you are not obligated to do so. }
38 { If you do not wish to do so, delete this exception }
39 { statement from your version. }
42 { The project web site is located on: }
43 { http://zeos.firmos.at (FORUM) }
44 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
45 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
47 { http://www.sourceforge.net/projects/zeoslib. }
50 { Zeos Development Group. }
51 {********************************************************@}
53 unit ZStoredProcedure;
60 Types, SysUtils, Classes, {$IFDEF MSEgui}mclasses, mdb{$ELSE}DB{$ENDIF},
61 ZDbcIntfs, ZAbstractDataset, ZCompatibility;
66 Abstract dataset to access to stored procedures.
68 TZStoredProc = class(TZAbstractDataset)
70 FMetaResultSet: IZResultset;
71 procedure RetrieveParamValues;
72 function GetStoredProcName: string;
73 procedure SetStoredProcName(const Value: string);
74 function GetParamType(const Value: TZProcedureColumnType): TParamType;
76 function CreateStatement(const SQL: string; Properties: TStrings):
77 IZPreparedStatement; override;
78 procedure SetStatementParams(Statement: IZPreparedStatement;
79 ParamNames: TStringDynArray; Params: TParams;
80 DataLink: TDataLink); override;
81 procedure InternalOpen; override;
82 procedure InternalClose; override;
85 {$IFDEF WITH_IPROVIDER}
86 function PSIsSQLBased: Boolean; override;
87 procedure PSExecute; override;
88 {$IFDEF WITH_IPROVIDERWIDE}
89 function PSGetTableNameW: WideString; override;
91 function PSGetTableName: string; override;
93 procedure PSSetCommandText(const ACommandText: string); override;
97 procedure ExecProc; virtual;
99 procedure FirstResultSet;
100 procedure PreviousResultSet;
101 procedure NextResultSet;
102 procedure LastResultSet;
103 procedure SetResultSet(const Index: Integer);
104 function ResultSetCount: Integer;
105 function BOR: Boolean;
106 function EOR: Boolean;
111 property ShowRecordTypes;
113 property StoredProcName: string read GetStoredProcName
114 write SetStoredProcName;
120 ZAbstractRODataset, ZMessages, ZDatasetUtils
121 {$IFDEF WITH_ASBYTES}, ZSysUtils{$ENDIF}
122 {$IFDEF WITH_INLINE_ANSICOMPARETEXT}, Windows{$ENDIF};
127 Creates a DBC statement for the query.
128 @param SQL an SQL query.
129 @param Properties a statement specific properties.
130 @returns a created DBC statement.
135 function TZStoredProc.CreateStatement(const SQL: string; Properties: TStrings):
139 CallableStatement: IZCallableStatement;
140 Catalog, Schema, ObjectName: string;
142 CallableStatement := Connection.DbcConnection.PrepareCallWithParams(
143 Trim(SQL), Properties);
145 CallableStatement.ClearParameters;
147 if Supports(CallableStatement, IZParamNamedCallableStatement) then
148 if Assigned(FMetaResultSet) then
149 FMetaResultSet.BeforeFirst
151 begin //i need allways all types to cast and there names
152 SplitQualifiedObjectName(Trim(SQL), Catalog, Schema, ObjectName);
153 ObjectName := Connection.DbcConnection.GetMetadata.AddEscapeCharToWildcards(ObjectName);
154 FMetaResultSet := Connection.DbcConnection.GetMetadata.GetProcedureColumns(Catalog, Schema, ObjectName, '');
157 for I := 0 to Params.Count - 1 do
159 CallableStatement.RegisterParamType( I+1, ord(Params[I].ParamType));
161 if Params[I].ParamType in [ptResult, ptOutput, ptInputOutput] then
162 CallableStatement.RegisterOutParameter(I + 1,
163 Ord(ConvertDatasetToDbcType(Params[I].DataType)));
165 if Supports(CallableStatement, IZParamNamedCallableStatement) and
166 Assigned(FMetaResultSet) then
167 if FMetaResultSet.Next then
168 (CallableStatement as IZParamNamedCallableStatement).RegisterParamTypeAndName(
169 I, FMetaResultSet.GetString(7), Params[i].Name, FMetaResultSet.GetInt(8),
170 FMetaResultSet.GetInt(9));
172 Result := CallableStatement;
179 Fill prepared statement with parameters.
180 @param Statement a prepared SQL statement.
181 @param ParamNames an array of parameter names.
182 @param Params a collection of SQL parameters.
183 @param DataLink a datalink to get parameters.
188 procedure TZStoredProc.SetStatementParams(Statement: IZPreparedStatement;
189 ParamNames: TStringDynArray; Params: TParams; DataLink: TDataLink);
194 for I := 0 to Params.Count - 1 do
198 if Params[I].ParamType in [ptResult, ptOutput] then
201 SetStatementParam(I+1, Statement, Param);
209 Retrieves parameter values from callable statement.
211 procedure TZStoredProc.RetrieveParamValues;
215 FCallableStatement: IZCallableStatement;
218 if Assigned(Statement) then
219 Statement.QueryInterface(IZCallableStatement, FCallableStatement);
220 if not Assigned(FCallableStatement) then
223 for I := 0 to Params.Count - 1 do
227 if not (Param.ParamType in [ptResult, ptOutput, ptInputOutput]) then
230 if FCallableStatement.IsNull(I + 1) then
233 case Param.DataType of
235 Param.AsBoolean := FCallableStatement.GetBoolean(I + 1);
237 Param.AsSmallInt := FCallableStatement.GetShort(I + 1);
238 ftInteger, ftAutoInc:
239 Param.AsInteger := FCallableStatement.GetInt(I + 1);
241 Param.AsFloat := FCallableStatement.GetDouble(I + 1);
243 Param.Value := FCallableStatement.GetLong(I + 1);
246 Param.AsString := FCallableStatement.GetString(I + 1);
247 {$IFDEF UNICODE}Param.DataType := ftString;{$ENDIF} //Hack: D12_UP sets ftWideString on assigning a UnicodeString
250 {$IFDEF WITH_FTWIDESTRING}Param.AsWideString{$ELSE}Param.Value{$ENDIF} := FCallableStatement.GetUnicodeString(I + 1);
253 Param.AsMemo := FCallableStatement.GetString(I + 1);
254 {$IFDEF UNICODE}Param.DataType := ftMemo;{$ENDIF} //Hack: D12_UP sets ftWideMemo on assigning a UnicodeString
256 {$IFDEF WITH_WIDEMEMO}
259 Param.AsWideString := FCallableStatement.GetUnicodeString(I + 1);
260 Param.DataType := ftWideMemo;
264 Param.Value := FCallableStatement.GetBytes(I + 1);
266 Param.AsDate := FCallableStatement.GetDate(I + 1);
268 Param.AsTime := FCallableStatement.GetTime(I + 1);
270 Param.AsDateTime := FCallableStatement.GetTimestamp(I + 1);
273 TempBlob := FCallableStatement.GetValue(I +1).VInterface as IZBlob;
274 if not TempBlob.IsEmpty then
275 Param.SetBlobData({$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ENDIF}(TempBlob.GetBuffer), TempBlob.Length);
279 raise EZDatabaseError.Create(SUnKnownParamDataType);
285 Performs internal query opening.
287 procedure TZStoredProc.InternalOpen;
289 inherited InternalOpen;
295 Performs internal query closing.
297 procedure TZStoredProc.InternalClose;
299 inherited InternalClose;
302 function TZStoredProc.GetStoredProcName: string;
304 Result := Trim(SQL.Text);
310 procedure TZStoredProc.SetStoredProcName(const Value: string);
313 Catalog, Schema, ObjectName: string;
316 if AnsiCompareText(Trim(SQL.Text), Trim(Value)) <> 0 then
319 if ParamCheck and (Value <> '') and not (csLoading in ComponentState) and Assigned(Connection) then
322 Connection.ShowSQLHourGlass;
324 SplitQualifiedObjectName(Value,
325 Connection.DbcConnection.GetMetadata.GetDatabaseInfo.SupportsCatalogsInProcedureCalls,
326 Connection.DbcConnection.GetMetadata.GetDatabaseInfo.SupportsSchemasInProcedureCalls,
327 Catalog, Schema, ObjectName);
328 ObjectName := Connection.DbcConnection.GetMetadata.AddEscapeCharToWildcards(ObjectName);
329 FMetaResultSet := Connection.DbcConnection.GetMetadata.GetProcedureColumns(Catalog, Schema, ObjectName, '');
330 OldParams := TParams.Create;
332 OldParams.Assign(Params);
334 while FMetaResultSet.Next do
336 ColumnType := FMetaResultSet.GetIntByName('COLUMN_TYPE');
337 if ColumnType >= 0 then //-1 is result column
338 Params.CreateParam(ConvertDbcToDatasetType(TZSqlType(FMetaResultSet.GetIntByName('DATA_TYPE'))),
339 FMetaResultSet.GetStringByName('COLUMN_NAME'),
340 GetParamType(TZProcedureColumnType(ColumnType)));
342 Params.AssignValues(OldParams);
347 Connection.HideSQLHourGlass;
356 procedure TZStoredProc.ExecProc;
358 Connection.ShowSQLHourGlass;
365 Connection.HideSQLHourGlass;
370 Procedure the First retrieved resultset if the givens
372 procedure TZStoredProc.FirstResultSet;
374 if Assigned(Statement) then
375 if (Statement as IZCallableStatement).HasMoreResultSets then
376 SetAnotherResultset((Statement as IZCallableStatement).GetFirstResultSet);
380 Procedure the Previous retrieved resultset if the givens
382 procedure TZStoredProc.PreviousResultSet;
384 if Assigned(Statement) then
385 if (Statement as IZCallableStatement).HasMoreResultSets then
386 SetAnotherResultset((Statement as IZCallableStatement).GetPreviousResultSet);
390 Procedure the Next retrieved resultset if the givens
392 procedure TZStoredProc.NextResultSet;
394 if Assigned(Statement) then
395 if (Statement as IZCallableStatement).HasMoreResultSets then
396 SetAnotherResultset((Statement as IZCallableStatement).GetNextResultSet);
400 Procedure the Last retrieved resultset if the givens
402 procedure TZStoredProc.LastResultSet;
404 if Assigned(Statement) then
405 if (Statement as IZCallableStatement).HasMoreResultSets then
406 SetAnotherResultset((Statement as IZCallableStatement).GetLastResultSet);
410 Retrieves a ResultSet by his index.
411 @param Integer the index of the Resultset
412 @result <code>IZResultSet</code> of the Index or nil.
414 procedure TZStoredProc.SetResultSet(const Index: Integer);
416 if Assigned(Statement) then
417 if ( Index < 0 ) or ( Index > (Statement as IZCallableStatement).GetResultSetCount -1 ) then
418 raise Exception.Create(Format(SListIndexError, [Index]))
420 SetAnotherResultset((Statement as IZCallableStatement).GetResultSetByIndex(Index));
424 Returns the Count of retrived ResultSets.
425 @result <code>Integer</code> Count
427 function TZStoredProc.ResultSetCount: Integer;
430 if Assigned(Statement) then
431 if (Statement as IZCallableStatement).HasMoreResultSets then
432 Result := (Statement as IZCallableStatement).GetResultSetCount;
437 @result <code>True</code> if first ResultSet
439 function TZStoredProc.BOR: Boolean;
442 if Assigned(Statement) then
443 if (Statement as IZCallableStatement).HasMoreResultSets then
444 Result := (Statement as IZCallableStatement).BOR;
449 @result <code>True</code> if Last ResultSet
451 function TZStoredProc.EOR: Boolean;
454 if Assigned(Statement) then
455 if (Statement as IZCallableStatement).HasMoreResultSets then
456 Result := (Statement as IZCallableStatement).EOR;
460 Converts procedure column type to dataset param type.
461 @param Value a initial procedure column type.
462 @return a corresponding param type.
464 function TZStoredProc.GetParamType(const Value: TZProcedureColumnType): TParamType;
470 Result := ptInputOutput;
482 {$IFDEF WITH_IPROVIDER}
484 Checks if dataset can execute SQL queries?
485 @returns <code>True</code> if the query can execute SQL.
487 function TZStoredProc.PSIsSQLBased: Boolean;
493 Gets the name of the stored procedure.
494 @returns the name of this stored procedure.
496 {$IFDEF WITH_IPROVIDERWIDE}
497 function TZStoredProc.PSGetTableNameW: WideString;
499 function TZStoredProc.PSGetTableName: string;
502 Result := StoredProcName;
506 Executes this stored procedure.
508 procedure TZStoredProc.PSExecute;
514 Assignes a new name for this stored procedure.
515 @param ACommandText a new name for this stored procedure.
517 procedure TZStoredProc.PSSetCommandText(const ACommandText: string);
519 StoredProcName := ACommandText;