ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBQuery.pas
Revision: 143
Committed: Fri Feb 23 12:11:21 2018 UTC (6 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 14532 byte(s)
Log Message:
Fixes Merged

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 tony 143 { Associates Ltd 2011 - 2018 }
31 tony 33 { }
32     {************************************************************************}
33    
34     unit IBQuery;
35    
36     interface
37    
38     {$Mode Delphi}
39    
40     uses
41     {$IFDEF WINDOWS }
42     Windows,
43     {$ELSE}
44     unix,
45     {$ENDIF}
46 tony 139 SysUtils, Classes, Db, IB, IBCustomDataSet, IBSQL;
47 tony 33
48     type
49    
50     { TIBQuery }
51    
52     TIBQuery = class(TIBParserDataSet)
53     private
54     FSQL: TStrings;
55     FPrepared: Boolean;
56     FParams: TParams;
57     FText: string;
58     FSQLUpdating: boolean;
59 tony 35 FInQueryChanged: boolean;
60 tony 33 function GetRowsAffected: Integer;
61     procedure PrepareSQL;
62     procedure QueryChanged(Sender: TObject);
63     procedure ReadParamData(Reader: TReader);
64     procedure SetQuery(Value: TStrings);
65     procedure SetParamsList(Value: TParams);
66     procedure SetParams;
67     procedure SetParamsFromCursor;
68     procedure SetPrepared(Value: Boolean);
69     procedure SetPrepare(Value: Boolean);
70     procedure WriteParamData(Writer: TWriter);
71 tony 45 function GetStmtHandle: IStatement;
72 tony 35 procedure UpdateSQL;
73 tony 33
74     protected
75     { IProviderSupport }
76     (* procedure PSExecute; override;
77     function PSGetParams: TParams; override;
78     function PSGetTableName: string; override;
79     procedure PSSetCommandText(const CommandText: string); override;
80     procedure PSSetParams(AParams: TParams); override; *)
81    
82     procedure DefineProperties(Filer: TFiler); override;
83     procedure InitFieldDefs; override;
84     procedure InternalOpen; override;
85     procedure Disconnect; override;
86     function GetParamsCount: Word;
87     function GenerateQueryForLiveUpdate : Boolean;
88     procedure SetFiltered(Value: Boolean); override;
89 tony 35 procedure SQLChanged(Sender: TObject); override;
90     procedure SQLChanging(Sender: TObject); override;
91 tony 33
92     public
93     constructor Create(AOwner: TComponent); override;
94     destructor Destroy; override;
95     procedure BatchInput(InputObject: TIBBatchInput);
96     procedure BatchOutput(OutputObject: TIBBatchOutput);
97     procedure ExecSQL;
98     procedure GetDetailLinkFields(MasterFields, DetailFields: TList);(* override;*)
99     function ParamByName(const Value: string): TParam;
100     procedure Prepare;
101     procedure UnPrepare;
102 tony 35 procedure ResetParser; override;
103 tony 33 property Prepared: Boolean read FPrepared write SetPrepare;
104     property ParamCount: Word read GetParamsCount;
105 tony 45 property StmtHandle: IStatement read GetStmtHandle;
106 tony 33 property StatementType;
107     property Text: string read FText;
108     property RowsAffected: Integer read GetRowsAffected;
109     // property Params: TParams read FParams write SetParamsList;
110     property BaseSQLSelect;
111    
112     published
113     property Active;
114     property AutoCommit;
115     property BufferChunks;
116     property CachedUpdates;
117     property DataSource read GetDataSource write SetDataSource;
118     property GenerateParamNames;
119     // property Constraints stored ConstraintsStored;
120     property GeneratorField;
121     property ParamCheck;
122     property SQL: TStrings read FSQL write SetQuery;
123     property Params: TParams read FParams write SetParamsList;
124     property UniDirectional default False;
125     property UpdateObject;
126     property Filtered;
127     property DataSetCloseAction;
128    
129     property BeforeDatabaseDisconnect;
130     property AfterDatabaseDisconnect;
131     property DatabaseFree;
132     property BeforeTransactionEnd;
133     property AfterTransactionEnd;
134     property TransactionFree;
135     property OnFilterRecord;
136     property OnValidatePost;
137 tony 118 property OnDeleteReturning;
138 tony 33 end;
139    
140     implementation
141    
142 tony 45 uses FBMessages;
143    
144 tony 33 { TIBQuery }
145    
146     constructor TIBQuery.Create(AOwner: TComponent);
147     begin
148     inherited Create(AOwner);
149     FSQL := TStringList.Create;
150     TStringList(SQL).OnChange := QueryChanged;
151     FParams := TParams.Create(Self);
152     ParamCheck := True;
153     end;
154    
155     destructor TIBQuery.Destroy;
156     begin
157     Destroying;
158     Disconnect;
159     SQL.Free;
160     FParams.Free;
161     inherited Destroy;
162     end;
163    
164     procedure TIBQuery.InitFieldDefs;
165     begin
166     inherited InitFieldDefs;
167     end;
168    
169     procedure TIBQuery.InternalOpen;
170     begin
171     ActivateConnection();
172     ActivateTransaction;
173     QSelect.GenerateParamNames := GenerateParamNames;
174     SetPrepared(True);
175     if DataSource <> nil then
176     SetParamsFromCursor;
177     SetParams;
178     inherited InternalOpen;
179     end;
180    
181     procedure TIBQuery.Disconnect;
182     begin
183     Close;
184     UnPrepare;
185     end;
186    
187     procedure TIBQuery.SetPrepare(Value: Boolean);
188     begin
189     if Value then
190     Prepare
191     else
192     UnPrepare;
193     end;
194    
195     procedure TIBQuery.Prepare;
196     begin
197     SetPrepared(True);
198     end;
199    
200     procedure TIBQuery.UnPrepare;
201     begin
202     SetPrepared(False);
203     end;
204    
205 tony 35 procedure TIBQuery.ResetParser;
206     begin
207     inherited ResetParser;
208     UpdateSQL;
209     end;
210    
211 tony 33 procedure TIBQuery.SetQuery(Value: TStrings);
212     begin
213     if SQL.Text <> Value.Text then
214     begin
215     Disconnect;
216     SQL.BeginUpdate;
217     try
218     SQL.Assign(Value);
219     finally
220     SQL.EndUpdate;
221     end;
222     end;
223     end;
224    
225     procedure TIBQuery.QueryChanged(Sender: TObject);
226     begin
227 tony 35 if FInQueryChanged then Exit;
228     FInQueryChanged := true;
229     try
230     if not (csReading in ComponentState) then
231 tony 33 begin
232 tony 35 Disconnect;
233     if csDesigning in ComponentState then
234     FText := FParams.ParseSQL(SQL.Text, true)
235     else
236     FText := SQL.Text;
237     DataEvent(dePropertyChange, 0);
238     end else
239     FText := FParams.ParseSQL(SQL.Text, true);
240    
241     if not FSQLUpdating then
242     begin
243     Prepared := false;
244     SelectSQL.Assign(SQL);
245 tony 33 end;
246 tony 35 finally
247     FInQueryChanged := false;
248     end;
249 tony 33 end;
250    
251     procedure TIBQuery.SetParamsList(Value: TParams);
252     begin
253     FParams.AssignValues(Value);
254     end;
255    
256     function TIBQuery.GetParamsCount: Word;
257     begin
258     Result := FParams.Count;
259     end;
260    
261     procedure TIBQuery.DefineProperties(Filer: TFiler);
262    
263     function WriteData: Boolean;
264     begin
265     {The following results in a stream read error with nested frames. Hence commented out until
266     someone fixes the LCL }
267     { if Filer.Ancestor <> nil then
268     Result := not FParams.IsEqual(TIBQuery(Filer.Ancestor).FParams) else}
269     Result := FParams.Count > 0;
270     end;
271    
272     begin
273     inherited DefineProperties(Filer);
274     Filer.DefineProperty('ParamData', ReadParamData, WriteParamData, WriteData); {do not localize}
275     end;
276    
277    
278     procedure TIBQuery.ReadParamData(Reader: TReader);
279     begin
280     FParams.Clear;
281     Reader.ReadValue;
282     Reader.ReadCollection(FParams);
283     end;
284    
285     procedure TIBQuery.WriteParamData(Writer: TWriter);
286     begin
287     Writer.WriteCollection(Params);
288     end;
289    
290     procedure TIBQuery.SetPrepared(Value: Boolean);
291     begin
292     CheckDatasetClosed;
293     if Value <> Prepared then
294     begin
295     if Value then
296     begin
297     if Length(Text) > 1 then PrepareSQL
298     else IBError(ibxeEmptySQLStatement, [nil]);
299     end
300     else
301     begin
302     InternalUnPrepare;
303 tony 35 FParams.Clear;
304 tony 33 end;
305     FPrepared := Value;
306     end;
307     end;
308    
309     procedure TIBQuery.SetParamsFromCursor;
310     var
311     I: Integer;
312     DataSet: TDataSet;
313     Field: TField;
314    
315     procedure CheckRequiredParams;
316     var
317     I: Integer;
318     begin
319     for I := 0 to FParams.Count - 1 do
320     with FParams[I] do
321     if not Bound then
322     IBError(ibxeRequiredParamNotSet, [FParams[I].Name]);
323     end;
324    
325     begin
326     if DataSource <> nil then
327     begin
328     DataSet := DataSource.DataSet;
329     if DataSet <> nil then
330     begin
331     DataSet.FieldDefs.Update;
332     for I := 0 to FParams.Count - 1 do
333     if not FParams[I].Bound then
334     begin
335     Field := DataSet.FindField(FParams[I].Name);
336     if assigned(Field) then
337     begin
338     FParams[I].AssignField(Field);
339     FParams[I].Bound := False;
340     end;
341     end;
342     end
343     else
344     CheckRequiredParams;
345     end
346     else
347     CheckRequiredParams;
348     end;
349    
350    
351     function TIBQuery.ParamByName(const Value: string): TParam;
352     begin
353 tony 35 if not Prepared then
354     Prepare;
355 tony 33 Result := FParams.ParamByName(Value);
356     end;
357    
358     procedure TIBQuery.BatchInput(InputObject: TIBBatchInput);
359     begin
360     InternalBatchInput(InputObject);
361     end;
362    
363     procedure TIBQuery.BatchOutput(OutputObject: TIBBatchOutput);
364     begin
365     InternalBatchOutput(OutputObject);
366     end;
367    
368     procedure TIBQuery.ExecSQL;
369     var
370     DidActivate: Boolean;
371     begin
372     CheckInActive;
373     if SQL.Count <= 0 then
374     IBError(ibxeEmptySQLStatement, [nil]);
375 tony 80
376 tony 33 ActivateConnection();
377     DidActivate := ActivateTransaction;
378     try
379     SetPrepared(True);
380     if DataSource <> nil then SetParamsFromCursor;
381     if FParams.Count > 0 then SetParams;
382     InternalExecQuery;
383     finally
384     if DidActivate then
385     DeactivateTransaction;
386     end;
387     end;
388    
389     procedure TIBQuery.SetParams;
390    
391     var
392     i : integer;
393     Buffer: Pointer;
394 tony 45 SQLParam: ISQLParam;
395 tony 33
396     begin
397     for I := 0 to FParams.Count - 1 do
398     begin
399     SQLParam := SQLParams.ByName(Params[i].Name);
400     if Params[i].IsNull then
401     SQLParam.IsNull := True
402     else begin
403     SQLParam.IsNull := False;
404     case Params[i].DataType of
405     ftBytes:
406     begin
407     GetMem(Buffer,Params[i].GetDataSize);
408     try
409     Params[i].GetData(Buffer);
410     SQLParam.AsPointer := Buffer;
411     finally
412     FreeMem(Buffer);
413     end;
414     end;
415     ftString:
416     SQLParam.AsString := Params[i].AsString;
417     ftBoolean:
418     SQLParam.AsBoolean := Params[i].AsBoolean;
419     ftSmallint, ftWord:
420     SQLParam.AsShort := Params[i].AsSmallInt;
421     ftInteger:
422     SQLParam.AsLong := Params[i].AsInteger;
423     ftLargeInt:
424     SQLParam.AsInt64 := Params[i].AsLargeInt;
425     ftFloat:
426     SQLParam.AsDouble := Params[i].AsFloat;
427     ftBCD, ftCurrency:
428     SQLParam.AsCurrency := Params[i].AsCurrency;
429     ftDate:
430     SQLParam.AsDate := Params[i].AsDateTime;
431     ftTime:
432     SQLParam.AsTime := Params[i].AsDateTime;
433     ftDateTime:
434     SQLParam.AsDateTime := Params[i].AsDateTime;
435     ftBlob, ftMemo:
436     SQLParam.AsString := Params[i].AsString;
437     else
438     IBError(ibxeNotSupported, [nil]);
439     end;
440     end;
441     end;
442     end;
443    
444     procedure TIBQuery.PrepareSQL;
445 tony 35 var List: TParams;
446 tony 33 begin
447     QSelect.GenerateParamNames := GenerateParamNames;
448     InternalPrepare;
449 tony 35 UpdateSQL;
450     if ParamCheck then
451     begin
452     List := TParams.Create(Self);
453     try
454     FText := List.ParseSQL(SQL.Text, True);
455     List.AssignValues(FParams);
456     FParams.Clear;
457     FParams.Assign(List);
458     finally
459     List.Free;
460     end;
461     end;
462 tony 33 end;
463    
464    
465     function TIBQuery.GetRowsAffected: Integer;
466     begin
467     Result := -1;
468     if Prepared then
469     Result := QSelect.RowsAffected
470     end;
471    
472    
473     procedure TIBQuery.GetDetailLinkFields(MasterFields, DetailFields: TList);
474    
475     function AddFieldToList(const FieldName: string; DataSet: TDataSet;
476     List: TList): Boolean;
477     var
478     Field: TField;
479     begin
480     Field := DataSet.FindField(FieldName);
481     if (Field <> nil) then
482     List.Add(Field);
483     Result := Field <> nil;
484     end;
485    
486     var
487     i: Integer;
488     begin
489     MasterFields.Clear;
490     DetailFields.Clear;
491     if (DataSource <> nil) and (DataSource.DataSet <> nil) then
492     for i := 0 to Params.Count - 1 do
493     if AddFieldToList(Params[i].Name, DataSource.DataSet, MasterFields) then
494     AddFieldToList(Params[i].Name, Self, DetailFields);
495     end;
496    
497 tony 45 function TIBQuery.GetStmtHandle: IStatement;
498 tony 33 begin
499     Result := SelectStmtHandle;
500     end;
501    
502 tony 35 procedure TIBQuery.UpdateSQL;
503 tony 33 begin
504 tony 39 if not FSQLUpdating and not FInQueryChanged and (SQL.Text <> SelectSQL.Text) then
505 tony 35 begin
506     FSQLUpdating := true;
507     try
508     SQL.Text := SelectSQL.Text;
509     finally
510     FSQLUpdating := false
511     end;
512     end;
513 tony 33 end;
514    
515     function TIBQuery.GenerateQueryForLiveUpdate : Boolean;
516     begin
517     Result := False;
518     end;
519    
520     procedure TIBQuery.SetFiltered(Value: Boolean);
521     begin
522     if(Filtered <> Value) then
523     begin
524     inherited SetFiltered(value);
525     if Active then
526     begin
527     Close;
528     Open;
529     end;
530     end
531     else
532     inherited SetFiltered(value);
533     end;
534    
535 tony 35 procedure TIBQuery.SQLChanged(Sender: TObject);
536     begin
537     inherited SQLChanged(Sender);
538     UpdateSQL;
539     end;
540    
541     procedure TIBQuery.SQLChanging(Sender: TObject);
542     begin
543     inherited SQLChanging(Sender);
544     Prepared := false;
545     end;
546    
547 tony 33 { TIBQuery IProviderSupport }
548     (*
549     function TIBQuery.PSGetParams: TParams;
550     begin
551     Result := Params;
552     end;
553    
554     procedure TIBQuery.PSSetParams(AParams: TParams);
555     begin
556     if AParams.Count <> 0 then
557     Params.Assign(AParams);
558     Close;
559     end;
560    
561     function TIBQuery.PSGetTableName: string;
562     begin
563     Result := inherited PSGetTableName;
564     end;
565    
566     procedure TIBQuery.PSExecute;
567     begin
568     ExecSQL;
569     end;
570    
571     procedure TIBQuery.PSSetCommandText(const CommandText: string);
572     begin
573     if CommandText <> '' then
574     SQL.Text := CommandText;
575     end;
576     *)
577     end.
578