ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBStoredProc.pas
Revision: 19
Committed: Mon Jul 7 13:00:15 2014 UTC (10 years, 4 months ago) by tony
Content type: text/x-pascal
File size: 16614 byte(s)
Log Message:
Committing updates for Release R1-1-0

File Contents

# User Rev Content
1 tony 17 {************************************************************************}
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 tony 19 procedure InitFieldDefs; override;
71 tony 17 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 tony 19 procedure TIBStoredProc.InitFieldDefs;
204     begin
205     if SelectSQL.Text = '' then
206     GenerateSQL;
207     inherited InitFieldDefs;
208     end;
209    
210 tony 17 procedure TIBStoredProc.GenerateSQL;
211 tony 19
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 tony 17 var
235     Query : TIBSQL;
236     input : string;
237     begin
238 tony 19 if FProcName = '' then
239     IBError(ibxeNoStoredProcName,[nil]);
240 tony 17 ActivateConnection;
241     Database.InternalTransaction.StartTransaction;
242 tony 19 Params := TStringList.Create;
243 tony 17 Query := TIBSQL.Create(self);
244     try
245     Query.Database := DataBase;
246     Query.Transaction := Database.InternalTransaction;
247     Query.SQL.Text := 'SELECT RDB$PARAMETER_NAME, RDB$PARAMETER_TYPE ' + {do not localize}
248     'FROM RDB$PROCEDURE_PARAMETERS ' + {do not localize}
249     'WHERE RDB$PROCEDURE_NAME = ' + {do not localize}
250     '''' + FormatIdentifierValue(Database.SQLDialect, FProcName) + '''' +
251     ' ORDER BY RDB$PARAMETER_NUMBER'; {do not localize}
252     Query.Prepare;
253     Query.GoToFirstRecordOnExecute := False;
254     Query.ExecQuery;
255     while (not Query.EOF) and (Query.Next <> nil) do begin
256     if (Query.Current.ByName('RDB$PARAMETER_TYPE').AsInteger = 0) then begin {do not localize}
257     if (input <> '') then
258     input := input + ', :' +
259 tony 19 FormatParameter(Database.SQLDialect, Query.Current.ByName('RDB$PARAMETER_NAME').AsString) else {do not localize}
260 tony 17 input := ':' +
261 tony 19 FormatParameter(Database.SQLDialect, Query.Current.ByName('RDB$PARAMETER_NAME').AsString); {do not localize}
262 tony 17 end
263     end;
264     SelectSQL.Text := 'Execute Procedure ' + {do not localize}
265 tony 19 FormatParameter(Database.SQLDialect, FProcName) + ' ' + input;
266     { writeln(SelectSQL.Text);}
267 tony 17 finally
268     Query.Free;
269 tony 19 Params.Free;
270 tony 17 Database.InternalTransaction.Commit;
271     end;
272     end;
273    
274     procedure TIBStoredProc.CreateParamDesc;
275     var
276     i : integer;
277     DataType : TFieldType;
278     begin
279     DataType := ftUnknown;
280     for i := 0 to QSelect.Current.Count - 1 do begin
281     case QSelect.Fields[i].SQLtype of
282     SQL_TYPE_DATE: DataType := ftDate;
283     SQL_TYPE_TIME: DataType := ftTime;
284     SQL_TIMESTAMP: DataType := ftDateTime;
285     SQL_SHORT:
286     if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale = 0) then
287     DataType := ftSmallInt
288     else
289     DataType := ftBCD;
290     SQL_LONG:
291     if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale = 0) then
292     DataType := ftInteger
293     else if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale >= (-4)) then
294     DataType := ftBCD
295     else
296     DataType := ftFloat;
297     SQL_INT64:
298     if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale = 0) then
299     DataType := ftLargeInt
300     else if ((QSelect.Fields[i].AsXSQLVar)^.sqlscale >= (-4)) then
301     DataType := ftBCD
302     else
303     DataType := ftFloat;
304     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: DataType := ftFloat;
305     SQL_TEXT: DataType := ftString;
306     SQL_VARYING:
307     if ((QSelect.Fields[i].AsXSQLVar)^.sqllen < 1024) then
308     DataType := ftString
309     else DataType := ftBlob;
310     SQL_BLOB, SQL_ARRAY, SQL_QUAD: DataType := ftBlob;
311     end;
312     FParams.CreateParam(DataType, Trim(QSelect.Fields[i].Name), ptOutput);
313     end;
314    
315     DataType := ftUnknown;
316     for i := 0 to QSelect.Params.Count - 1 do begin
317     case QSelect.Params[i].SQLtype of
318     SQL_TYPE_DATE: DataType := ftDate;
319     SQL_TYPE_TIME: DataType := ftTime;
320     SQL_TIMESTAMP: DataType := ftDateTime;
321     SQL_SHORT:
322     if ((QSelect.Params[i].AsXSQLVar)^.sqlscale = 0) then
323     DataType := ftSmallInt
324     else
325     DataType := ftBCD;
326     SQL_LONG:
327     if ((QSelect.Params[i].AsXSQLVar)^.sqlscale = 0) then
328     DataType := ftInteger
329     else if ((QSelect.Params[i].AsXSQLVar)^.sqlscale >= (-4)) then
330     DataType := ftBCD
331     else DataType := ftFloat;
332     SQL_INT64:
333     if ((QSelect.Params[i].AsXSQLVar)^.sqlscale = 0) then
334     DataType := ftLargeInt
335     else if ((QSelect.Params[i].AsXSQLVar)^.sqlscale >= (-4)) then
336     DataType := ftBCD
337     else DataType := ftFloat;
338     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: DataType := ftFloat;
339     SQL_TEXT: DataType := ftString;
340     SQL_VARYING:
341     if ((QSelect.Params[i].AsXSQLVar)^.sqllen < 1024) then
342     DataType := ftString
343     else DataType := ftBlob;
344     SQL_BLOB, SQL_ARRAY, SQL_QUAD: DataType := ftBlob;
345     end;
346     FParams.CreateParam(DataType, Trim(QSelect.Params[i].Name), ptInput);
347     end;
348     end;
349    
350     procedure TIBStoredProc.SetPrepared(Value: Boolean);
351     begin
352     if Prepared <> Value then
353     begin
354     if Value then
355     try
356     if SelectSQL.Text = '' then GenerateSQL;
357     InternalPrepare;
358     if FParams.Count = 0 then CreateParamDesc;
359     FPrepared := True;
360     except
361     FreeStatement;
362     raise;
363     end
364     else FreeStatement;
365     end;
366    
367     end;
368    
369     procedure TIBStoredProc.Prepare;
370     begin
371     SetPrepared(True);
372     end;
373    
374     procedure TIBStoredProc.UnPrepare;
375     begin
376     SetPrepared(False);
377     end;
378    
379     procedure TIBStoredProc.FreeStatement;
380     begin
381     InternalUnPrepare;
382     FPrepared := False;
383     end;
384    
385     procedure TIBStoredProc.SetPrepare(Value: Boolean);
386     begin
387     if Value then Prepare
388     else UnPrepare;
389     end;
390    
391     procedure TIBStoredProc.CopyParams(Value: TParams);
392     begin
393     if not Prepared and (FParams.Count = 0) then
394     try
395     Prepare;
396     Value.Assign(FParams);
397     finally
398     UnPrepare;
399     end else
400     Value.Assign(FParams);
401     end;
402    
403     procedure TIBStoredProc.SetParamsList(Value: TParams);
404     begin
405     CheckInactive;
406     if Prepared then
407     begin
408     SetPrepared(False);
409     FParams.Assign(Value);
410     SetPrepared(True);
411     end else
412     FParams.Assign(Value);
413     end;
414    
415     function TIBStoredProc.ParamByName(const Value: string): TParam;
416     begin
417     Result := FParams.ParamByName(Value);
418     end;
419    
420     function TIBStoredProc.GetStoredProcedureNames: TStrings;
421     begin
422     FNameList.clear;
423     GetStoredProcedureNamesFromServer;
424     Result := FNameList;
425     end;
426    
427     procedure TIBStoredProc.GetStoredProcedureNamesFromServer;
428     var
429     Query : TIBSQL;
430     begin
431     if not (csReading in ComponentState) then begin
432     ActivateConnection;
433     Database.InternalTransaction.StartTransaction;
434     Query := TIBSQL.Create(self);
435     try
436     Query.GoToFirstRecordOnExecute := False;
437     Query.Database := DataBase;
438     Query.Transaction := Database.InternalTransaction;
439     Query.SQL.Text := 'Select RDB$PROCEDURE_NAME from RDB$PROCEDURES'; {do not localize}
440     Query.Prepare;
441     Query.ExecQuery;
442     while (not Query.EOF) and (Query.Next <> nil) do
443     FNameList.Add(TrimRight(Query.Current.ByName('RDB$PROCEDURE_NAME').AsString)); {do not localize}
444     finally
445     Query.Free;
446     Database.InternalTransaction.Commit;
447     end;
448     end;
449     end;
450    
451     procedure TIBStoredProc.SetParams;
452     var
453     i : integer;
454     j: integer;
455     begin
456     i := 0;
457     for j := 0 to FParams.Count - 1 do
458     begin
459     if (Params[j].ParamType <> ptInput) then
460     continue;
461     if not Params[j].Bound then
462     IBError(ibxeRequiredParamNotSet, [nil]);
463     if Params[j].IsNull then
464     SQLParams[i].IsNull := True
465     else begin
466     SQLParams[i].IsNull := False;
467     case Params[j].DataType of
468     ftString:
469     SQLParams[i].AsString := Params[j].AsString;
470     ftBoolean, ftSmallint, ftWord:
471     SQLParams[i].AsShort := Params[j].AsSmallInt;
472     ftInteger:
473     SQLParams[i].AsLong := Params[j].AsInteger;
474 tony 19 ftLargeInt:
475     SQLParams[i].AsInt64 := Params[j].AsLargeInt;
476 tony 17 ftFloat, ftCurrency:
477     SQLParams[i].AsDouble := Params[j].AsFloat;
478     ftBCD:
479     SQLParams[i].AsCurrency := Params[j].AsCurrency;
480     ftDate:
481     SQLParams[i].AsDate := Params[j].AsDateTime;
482     ftTime:
483     SQLParams[i].AsTime := Params[j].AsDateTime;
484     ftDateTime:
485     SQLParams[i].AsDateTime := Params[j].AsDateTime;
486     ftBlob, ftMemo:
487     SQLParams[i].AsString := Params[j].AsString;
488     else
489     IBError(ibxeNotSupported, [nil]);
490     end;
491     end;
492     Inc(i);
493     end;
494     end;
495    
496     procedure TIBStoredProc.SetParamsFromCursor;
497     var
498     I: Integer;
499     DataSet: TDataSet;
500     begin
501     if DataSource <> nil then
502     begin
503     DataSet := DataSource.DataSet;
504     if DataSet <> nil then
505     begin
506     DataSet.FieldDefs.Update;
507     for I := 0 to FParams.Count - 1 do
508     with FParams[I] do
509     if (not Bound) and
510     ((ParamType = ptInput) or (ParamType = ptInputOutput)) then
511     AssignField(DataSet.FieldByName(Name));
512     end;
513     end;
514     end;
515    
516     procedure TIBStoredProc.FetchDataIntoOutputParams;
517     var
518     i,j : Integer;
519     begin
520     j := 0;
521     for i := 0 to FParams.Count - 1 do
522     with Params[I] do
523     if ParamType = ptOutput then begin
524     Value := QSelect.Fields[j].Value;
525     Inc(j);
526     end;
527     end;
528    
529     procedure TIBStoredProc.InternalOpen;
530     begin
531     IBError(ibxeIsAExecuteProcedure,[nil]);
532     end;
533    
534     procedure TIBStoredProc.DefineProperties(Filer: TFiler);
535    
536     function WriteData: Boolean;
537     begin
538     if Filer.Ancestor <> nil then
539     Result := not FParams.IsEqual(TIBStoredProc(Filer.Ancestor).FParams) else
540     Result := FParams.Count > 0;
541     end;
542    
543     begin
544     inherited DefineProperties(Filer);
545     Filer.DefineProperty('ParamData', ReadParamData, WriteParamData, WriteData); {do not localize}
546     end;
547    
548     procedure TIBStoredProc.WriteParamData(Writer: TWriter);
549     begin
550     Writer.WriteCollection(Params);
551     end;
552    
553     procedure TIBStoredProc.ReadParamData(Reader: TReader);
554     begin
555     Reader.ReadValue;
556     Reader.ReadCollection(Params);
557     end;
558    
559 tony 19 end.