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 (9 years, 9 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

# 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 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 if FProcName = '' then
239 IBError(ibxeNoStoredProcName,[nil]);
240 ActivateConnection;
241 Database.InternalTransaction.StartTransaction;
242 Params := TStringList.Create;
243 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 FormatParameter(Database.SQLDialect, Query.Current.ByName('RDB$PARAMETER_NAME').AsString) else {do not localize}
260 input := ':' +
261 FormatParameter(Database.SQLDialect, Query.Current.ByName('RDB$PARAMETER_NAME').AsString); {do not localize}
262 end
263 end;
264 SelectSQL.Text := 'Execute Procedure ' + {do not localize}
265 FormatParameter(Database.SQLDialect, FProcName) + ' ' + input;
266 { writeln(SelectSQL.Text);}
267 finally
268 Query.Free;
269 Params.Free;
270 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 ftLargeInt:
475 SQLParams[i].AsInt64 := Params[j].AsLargeInt;
476 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 end.