ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBStoredProc.pas
(Generate patch)

Comparing ibx/trunk/runtime/IBStoredProc.pas (file contents):
Revision 27 by tony, Tue Apr 14 13:10:23 2015 UTC vs.
Revision 45 by tony, Tue Dec 6 10:33:46 2016 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines