ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBStoredProc.pas
Revision: 39
Committed: Tue May 17 08:14:52 2016 UTC (7 years, 11 months ago) by tony
Content type: text/x-pascal
File size: 16310 byte(s)
Log Message:
Committing updates for Release R1-4-1

File Contents

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