ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBStoredProc.pas
Revision: 33
Committed: Sat Jul 18 12:30:52 2015 UTC (8 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 16251 byte(s)
Log Message:
Committing updates for Release R1-3-1

File Contents

# User Rev Content
1 tony 33 {************************************************************************}
2     { }
3     { Borland Delphi Visual Component Library }
4     { InterBase Express core components }
5     { }
6     { Copyright (c) 1998-2000 Inprise Corporation }
7     { }
8     { InterBase Express is based in part on the product }
9     { Free IB Components, written by Gregory H. Deatz for }
10     { Hoagland, Longo, Moran, Dunst & Doukas Company. }
11     { Free IB Components is used under license. }
12     { }
13     { The contents of this file are subject to the InterBase }
14     { Public License Version 1.0 (the "License"); you may not }
15     { use this file except in compliance with the License. You }
16     { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
17     { Software distributed under the License is distributed on }
18     { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
19     { express or implied. See the License for the specific language }
20     { governing rights and limitations under the License. }
21     { The Original Code was created by InterBase Software Corporation }
22     { and its successors. }
23     { Portions created by Inprise Corporation are Copyright (C) Inprise }
24     { Corporation. All Rights Reserved. }
25     { Contributor(s): Jeff Overcash }
26     { }
27     { IBX For Lazarus (Firebird Express) }
28     { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
29     { Portions created by MWA Software are copyright McCallum Whyman }
30     { Associates Ltd 2011 }
31     { }
32     {************************************************************************}
33    
34     unit IBStoredProc;
35    
36     {$Mode Delphi}
37    
38     interface
39    
40     uses SysUtils, Classes, DB, IB, IBDatabase, IBCustomDataSet,
41     IBHeader, IBSQL, IBUtils;
42    
43     { TIBStoredProc }
44     type
45    
46     TIBStoredProc = class(TIBCustomDataSet)
47     private
48     FIBLoaded: Boolean;
49     FStmtHandle: TISC_STMT_HANDLE;
50     FProcName: string;
51     FParams: TParams;
52     FPrepared: Boolean;
53     FNameList: TStrings;
54     procedure SetParamsList(Value: TParams);
55     procedure FreeStatement;
56     function GetStoredProcedureNames: TStrings;
57     procedure GetStoredProcedureNamesFromServer;
58     procedure CreateParamDesc;
59     procedure SetParams;
60     procedure SetParamsFromCursor;
61     procedure GenerateSQL;
62     procedure FetchDataIntoOutputParams;
63     procedure ReadParamData(Reader: TReader);
64     procedure WriteParamData(Writer: TWriter);
65    
66     protected
67    
68     procedure DefineProperties(Filer: TFiler); override;
69     procedure SetFiltered(Value: Boolean); override;
70     procedure InitFieldDefs; override;
71     function GetParamsCount: Word;
72     procedure SetPrepared(Value: Boolean);
73     procedure SetPrepare(Value: Boolean);
74     procedure SetProcName(Value: string);
75     procedure Disconnect; override;
76     procedure InternalOpen; override;
77    
78     public
79     constructor Create(AOwner: TComponent); override;
80     destructor Destroy; override;
81     procedure CopyParams(Value: TParams);
82     procedure ExecProc;
83     function ParamByName(const Value: string): TParam;
84     procedure Prepare;
85     procedure UnPrepare;
86     property ParamCount: Word read GetParamsCount;
87     property StmtHandle: TISC_STMT_HANDLE read FStmtHandle;
88     property Prepared: Boolean read FPrepared write SetPrepare;
89     property StoredProcedureNames: TStrings read GetStoredProcedureNames;
90    
91     published
92     property StoredProcName: string read FProcName write SetProcName;
93     property Params: TParams read FParams write SetParamsList;
94     property Filtered;
95    
96     property BeforeDatabaseDisconnect;
97     property AfterDatabaseDisconnect;
98     property DatabaseFree;
99     property BeforeTransactionEnd;
100     property AfterTransactionEnd;
101     property TransactionFree;
102     property OnFilterRecord;
103     end;
104    
105     implementation
106    
107     uses
108     IBIntf;
109    
110     { TIBStoredProc }
111    
112     constructor TIBStoredProc.Create(AOwner: TComponent);
113     begin
114     inherited Create(AOwner);
115     FIBLoaded := False;
116     CheckIBLoaded;
117     FIBLoaded := True;
118     FParams := TParams.Create (self);
119     FNameList := TStringList.Create;
120     end;
121    
122     destructor TIBStoredProc.Destroy;
123     begin
124     if FIBLoaded then
125     begin
126     Destroying;
127     Disconnect;
128     FParams.Free;
129     FNameList.Destroy;
130     end;
131     inherited Destroy;
132     end;
133    
134     procedure TIBStoredProc.Disconnect;
135     begin
136     Close;
137     UnPrepare;
138     end;
139    
140     procedure TIBStoredProc.ExecProc;
141     var
142     DidActivate: Boolean;
143     begin
144     CheckInActive;
145     if StoredProcName = '' then
146     IBError(ibxeNoStoredProcName, [nil]);
147     ActivateConnection;
148     DidActivate := ActivateTransaction;
149     try
150     SetPrepared(True);
151     if DataSource <> nil then SetParamsFromCursor;
152     if FParams.Count > 0 then SetParams;
153     InternalExecQuery;
154     FetchDataIntoOutputParams;
155     finally
156     if DidActivate then
157     DeactivateTransaction;
158     end;
159     end;
160    
161     procedure TIBStoredProc.SetProcName(Value: string);
162     begin
163     if not (csReading in ComponentState) then
164     begin
165     CheckInactive;
166     if Value <> FProcName then
167     begin
168     FProcName := Value;
169     FreeStatement;
170     FParams.Clear;
171     if (Value <> '') and
172     (Database <> nil) then
173     GenerateSQL;
174     end;
175     end else begin
176     FProcName := Value;
177     if (Value <> '') and
178     (Database <> nil) then
179     GenerateSQL;
180     end;
181     end;
182    
183     function TIBStoredProc.GetParamsCount: Word;
184     begin
185     Result := FParams.Count;
186     end;
187    
188     procedure TIBStoredProc.SetFiltered(Value: Boolean);
189     begin
190     if(Filtered <> Value) then
191     begin
192     inherited SetFiltered(value);
193     if Active then
194     begin
195     Close;
196     Open;
197     end;
198     end
199     else
200     inherited SetFiltered(value);
201     end;
202    
203     procedure TIBStoredProc.InitFieldDefs;
204     begin
205     if SelectSQL.Text = '' then
206     GenerateSQL;
207     inherited InitFieldDefs;
208     end;
209    
210     procedure TIBStoredProc.GenerateSQL;
211    
212     var Params: TStringList;
213    
214     function FormatParameter(Dialect: Integer; Value: String): String;
215     var j: integer;
216     begin
217     Value := Trim(Value);
218     if Dialect = 1 then
219     Result := AnsiUpperCase(Value)
220     else
221     begin
222     j := 1;
223     Value := Space2Underscore(AnsiUpperCase(Value));
224     Result := Value;
225     while Params.IndexOf(Result) <> -1 do
226     begin
227     Result := Value + IntToStr(j);
228     Inc(j)
229     end;
230     Params.Add(Result)
231     end;
232     end;
233    
234     var
235     Query : TIBSQL;
236     input : string;
237     begin
238     input := '';
239     if FProcName = '' then
240     IBError(ibxeNoStoredProcName,[nil]);
241     ActivateConnection;
242     Database.InternalTransaction.StartTransaction;
243     Params := TStringList.Create;
244     Query := TIBSQL.Create(self);
245     try
246     Query.Database := DataBase;
247     Query.Transaction := Database.InternalTransaction;
248     Query.SQL.Text := 'SELECT RDB$PARAMETER_NAME, RDB$PARAMETER_TYPE ' + {do not localize}
249     'FROM RDB$PROCEDURE_PARAMETERS ' + {do not localize}
250     'WHERE RDB$PROCEDURE_NAME = ' + {do not localize}
251     '''' + FormatIdentifierValue(Database.SQLDialect, FProcName) + '''' +
252     ' ORDER BY RDB$PARAMETER_NUMBER'; {do not localize}
253     Query.Prepare;
254     Query.GoToFirstRecordOnExecute := False;
255     Query.ExecQuery;
256     while (not Query.EOF) and (Query.Next <> nil) do begin
257     if (Query.Current.ByName('RDB$PARAMETER_TYPE').AsInteger = 0) then begin {do not localize}
258     if (input <> '') then
259     input := input + ', :' +
260     FormatParameter(Database.SQLDialect, Query.Current.ByName('RDB$PARAMETER_NAME').AsString) else {do not localize}
261     input := ':' +
262     FormatParameter(Database.SQLDialect, Query.Current.ByName('RDB$PARAMETER_NAME').AsString); {do not localize}
263     end
264     end;
265     SelectSQL.Text := 'Execute Procedure ' + {do not localize}
266     FormatParameter(Database.SQLDialect, FProcName) + ' ' + input;
267     { writeln(SelectSQL.Text);}
268     finally
269     Query.Free;
270     Params.Free;
271     Database.InternalTransaction.Commit;
272     end;
273     end;
274    
275     procedure TIBStoredProc.CreateParamDesc;
276     var
277     i : integer;
278     DataType : TFieldType;
279     begin
280     DataType := ftUnknown;
281     for i := 0 to QSelect.Current.Count - 1 do begin
282     case QSelect.Fields[i].SQLtype of
283     SQL_TYPE_DATE: DataType := ftDate;
284     SQL_TYPE_TIME: DataType := ftTime;
285     SQL_TIMESTAMP: DataType := ftDateTime;
286     SQL_SHORT:
287     if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale = 0) then
288     DataType := ftSmallInt
289     else
290     DataType := ftBCD;
291     SQL_LONG:
292     if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale = 0) then
293     DataType := ftInteger
294     else if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale >= (-4)) then
295     DataType := ftBCD
296     else
297     DataType := ftFloat;
298     SQL_INT64:
299     if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale = 0) then
300     DataType := ftLargeInt
301     else if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale >= (-4)) then
302     DataType := ftBCD
303     else
304     DataType := ftFloat;
305     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: DataType := ftFloat;
306     SQL_BOOLEAN:
307     DataType := ftBoolean;
308     SQL_TEXT: DataType := ftString;
309     SQL_VARYING:
310     if ((QSelect.Fields[i].AsXSQLVar)^.sqllen < 1024) then
311     DataType := ftString
312     else DataType := ftBlob;
313     SQL_BLOB, SQL_ARRAY, SQL_QUAD: DataType := ftBlob;
314     end;
315     FParams.CreateParam(DataType, Trim(QSelect.Fields[i].Name), ptOutput);
316     end;
317    
318     DataType := ftUnknown;
319     for i := 0 to QSelect.Params.Count - 1 do begin
320     case QSelect.Params[i].SQLtype of
321     SQL_TYPE_DATE: DataType := ftDate;
322     SQL_TYPE_TIME: DataType := ftTime;
323     SQL_TIMESTAMP: DataType := ftDateTime;
324     SQL_SHORT:
325     if ((QSelect.Params[i].AsXSQLVar)^.sqlscale = 0) then
326     DataType := ftSmallInt
327     else
328     DataType := ftBCD;
329     SQL_LONG:
330     if ((QSelect.Params[i].AsXSQLVar)^.sqlscale = 0) then
331     DataType := ftInteger
332     else if ((QSelect.Params[i].AsXSQLVar)^.sqlscale >= (-4)) then
333     DataType := ftBCD
334     else DataType := ftFloat;
335     SQL_INT64:
336     if ((QSelect.Params[i].AsXSQLVar)^.sqlscale = 0) then
337     DataType := ftLargeInt
338     else if ((QSelect.Params[i].AsXSQLVar)^.sqlscale >= (-4)) then
339     DataType := ftBCD
340     else DataType := ftFloat;
341     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: DataType := ftFloat;
342     SQL_BOOLEAN:
343     DataType := ftBoolean;
344     SQL_TEXT: DataType := ftString;
345     SQL_VARYING:
346     if ((QSelect.Params[i].AsXSQLVar)^.sqllen < 1024) then
347     DataType := ftString
348     else DataType := ftBlob;
349     SQL_BLOB, SQL_ARRAY, SQL_QUAD: DataType := ftBlob;
350     end;
351     FParams.CreateParam(DataType, Trim(QSelect.Params[i].Name), ptInput);
352     end;
353     end;
354    
355     procedure TIBStoredProc.SetPrepared(Value: Boolean);
356     begin
357     if Prepared <> Value then
358     begin
359     if Value then
360     try
361     if SelectSQL.Text = '' then GenerateSQL;
362     InternalPrepare;
363     if FParams.Count = 0 then CreateParamDesc;
364     FPrepared := True;
365     except
366     FreeStatement;
367     raise;
368     end
369     else FreeStatement;
370     end;
371    
372     end;
373    
374     procedure TIBStoredProc.Prepare;
375     begin
376     SetPrepared(True);
377     end;
378    
379     procedure TIBStoredProc.UnPrepare;
380     begin
381     SetPrepared(False);
382     end;
383    
384     procedure TIBStoredProc.FreeStatement;
385     begin
386     InternalUnPrepare;
387     FPrepared := False;
388     end;
389    
390     procedure TIBStoredProc.SetPrepare(Value: Boolean);
391     begin
392     if Value then Prepare
393     else UnPrepare;
394     end;
395    
396     procedure TIBStoredProc.CopyParams(Value: TParams);
397     begin
398     if not Prepared and (FParams.Count = 0) then
399     try
400     Prepare;
401     Value.Assign(FParams);
402     finally
403     UnPrepare;
404     end else
405     Value.Assign(FParams);
406     end;
407    
408     procedure TIBStoredProc.SetParamsList(Value: TParams);
409     begin
410     CheckInactive;
411     if Prepared then
412     begin
413     SetPrepared(False);
414     FParams.Assign(Value);
415     SetPrepared(True);
416     end else
417     FParams.Assign(Value);
418     end;
419    
420     function TIBStoredProc.ParamByName(const Value: string): TParam;
421     begin
422     Prepare;
423     Result := FParams.ParamByName(Value);
424     end;
425    
426     function TIBStoredProc.GetStoredProcedureNames: TStrings;
427     begin
428     FNameList.clear;
429     GetStoredProcedureNamesFromServer;
430     Result := FNameList;
431     end;
432    
433     procedure TIBStoredProc.GetStoredProcedureNamesFromServer;
434     var
435     Query : TIBSQL;
436     begin
437     if not (csReading in ComponentState) then begin
438     ActivateConnection;
439     Database.InternalTransaction.StartTransaction;
440     Query := TIBSQL.Create(self);
441     try
442     Query.GoToFirstRecordOnExecute := False;
443     Query.Database := DataBase;
444     Query.Transaction := Database.InternalTransaction;
445     Query.SQL.Text := 'Select RDB$PROCEDURE_NAME from RDB$PROCEDURES'; {do not localize}
446     Query.Prepare;
447     Query.ExecQuery;
448     while (not Query.EOF) and (Query.Next <> nil) do
449     FNameList.Add(TrimRight(Query.Current.ByName('RDB$PROCEDURE_NAME').AsString)); {do not localize}
450     finally
451     Query.Free;
452     Database.InternalTransaction.Commit;
453     end;
454     end;
455     end;
456    
457     procedure TIBStoredProc.SetParams;
458     var
459     i : integer;
460     j: integer;
461     begin
462     i := 0;
463     for j := 0 to FParams.Count - 1 do
464     begin
465     if (Params[j].ParamType <> ptInput) then
466     continue;
467     if not Params[j].Bound then
468     IBError(ibxeRequiredParamNotSet, [Params[j].Name]);
469     if Params[j].IsNull then
470     SQLParams[i].IsNull := True
471     else begin
472     SQLParams[i].IsNull := False;
473     case Params[j].DataType of
474     ftString:
475     SQLParams[i].AsString := Params[j].AsString;
476     ftSmallint, ftWord:
477     SQLParams[i].AsShort := Params[j].AsSmallInt;
478     ftBoolean:
479     SQLParams[i].AsBoolean := Params[j].AsBoolean;
480     ftInteger:
481     SQLParams[i].AsLong := Params[j].AsInteger;
482     ftLargeInt:
483     SQLParams[i].AsInt64 := Params[j].AsLargeInt;
484     ftFloat, ftCurrency:
485     SQLParams[i].AsDouble := Params[j].AsFloat;
486     ftBCD:
487     SQLParams[i].AsCurrency := Params[j].AsCurrency;
488     ftDate:
489     SQLParams[i].AsDate := Params[j].AsDateTime;
490     ftTime:
491     SQLParams[i].AsTime := Params[j].AsDateTime;
492     ftDateTime:
493     SQLParams[i].AsDateTime := Params[j].AsDateTime;
494     ftBlob, ftMemo:
495     SQLParams[i].AsString := Params[j].AsString;
496     else
497     IBError(ibxeNotSupported, [nil]);
498     end;
499     end;
500     Inc(i);
501     end;
502     end;
503    
504     procedure TIBStoredProc.SetParamsFromCursor;
505     var
506     I: Integer;
507     DataSet: TDataSet;
508     begin
509     if DataSource <> nil then
510     begin
511     DataSet := DataSource.DataSet;
512     if DataSet <> nil then
513     begin
514     DataSet.FieldDefs.Update;
515     for I := 0 to FParams.Count - 1 do
516     with FParams[I] do
517     if (not Bound) and
518     ((ParamType = ptInput) or (ParamType = ptInputOutput)) then
519     AssignField(DataSet.FieldByName(Name));
520     end;
521     end;
522     end;
523    
524     procedure TIBStoredProc.FetchDataIntoOutputParams;
525     var
526     i,j : Integer;
527     begin
528     j := 0;
529     for i := 0 to FParams.Count - 1 do
530     with Params[I] do
531     if ParamType = ptOutput then begin
532     Value := QSelect.Fields[j].Value;
533     Inc(j);
534     end;
535     end;
536    
537     procedure TIBStoredProc.InternalOpen;
538     begin
539     IBError(ibxeIsAExecuteProcedure,[nil]);
540     end;
541    
542     procedure TIBStoredProc.DefineProperties(Filer: TFiler);
543    
544     function WriteData: Boolean;
545     begin
546     if Filer.Ancestor <> nil then
547     Result := not FParams.IsEqual(TIBStoredProc(Filer.Ancestor).FParams) else
548     Result := FParams.Count > 0;
549     end;
550    
551     begin
552     inherited DefineProperties(Filer);
553     Filer.DefineProperty('ParamData', ReadParamData, WriteParamData, WriteData); {do not localize}
554     end;
555    
556     procedure TIBStoredProc.WriteParamData(Writer: TWriter);
557     begin
558     Writer.WriteCollection(Params);
559     end;
560    
561     procedure TIBStoredProc.ReadParamData(Reader: TReader);
562     begin
563     Reader.ReadValue;
564     Reader.ReadCollection(Params);
565     end;
566    
567     end.