ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBQuery.pas
Revision: 80
Committed: Mon Jan 1 11:31:07 2018 UTC (6 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 14523 byte(s)
Log Message:
Fixes merged into public release

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 IBQuery;
35
36 interface
37
38 {$Mode Delphi}
39
40 uses
41 {$IFDEF WINDOWS }
42 Windows,
43 {$ELSE}
44 unix,
45 {$ENDIF}
46 SysUtils, Classes, Db,
47 IBHeader, IB, IBCustomDataSet, IBSQL, IBSQLParser;
48
49 type
50
51 { TIBQuery }
52
53 TIBQuery = class(TIBParserDataSet)
54 private
55 FSQL: TStrings;
56 FPrepared: Boolean;
57 FParams: TParams;
58 FText: string;
59 FSQLUpdating: boolean;
60 FInQueryChanged: boolean;
61 function GetRowsAffected: Integer;
62 procedure PrepareSQL;
63 procedure QueryChanged(Sender: TObject);
64 procedure ReadParamData(Reader: TReader);
65 procedure SetQuery(Value: TStrings);
66 procedure SetParamsList(Value: TParams);
67 procedure SetParams;
68 procedure SetParamsFromCursor;
69 procedure SetPrepared(Value: Boolean);
70 procedure SetPrepare(Value: Boolean);
71 procedure WriteParamData(Writer: TWriter);
72 function GetStmtHandle: IStatement;
73 procedure UpdateSQL;
74
75 protected
76 { IProviderSupport }
77 (* procedure PSExecute; override;
78 function PSGetParams: TParams; override;
79 function PSGetTableName: string; override;
80 procedure PSSetCommandText(const CommandText: string); override;
81 procedure PSSetParams(AParams: TParams); override; *)
82
83 procedure DefineProperties(Filer: TFiler); override;
84 procedure InitFieldDefs; override;
85 procedure InternalOpen; override;
86 procedure Disconnect; override;
87 function GetParamsCount: Word;
88 function GenerateQueryForLiveUpdate : Boolean;
89 procedure SetFiltered(Value: Boolean); override;
90 procedure SQLChanged(Sender: TObject); override;
91 procedure SQLChanging(Sender: TObject); override;
92
93 public
94 constructor Create(AOwner: TComponent); override;
95 destructor Destroy; override;
96 procedure BatchInput(InputObject: TIBBatchInput);
97 procedure BatchOutput(OutputObject: TIBBatchOutput);
98 procedure ExecSQL;
99 procedure GetDetailLinkFields(MasterFields, DetailFields: TList);(* override;*)
100 function ParamByName(const Value: string): TParam;
101 procedure Prepare;
102 procedure UnPrepare;
103 procedure ResetParser; override;
104 property Prepared: Boolean read FPrepared write SetPrepare;
105 property ParamCount: Word read GetParamsCount;
106 property StmtHandle: IStatement read GetStmtHandle;
107 property StatementType;
108 property Text: string read FText;
109 property RowsAffected: Integer read GetRowsAffected;
110 // property Params: TParams read FParams write SetParamsList;
111 property BaseSQLSelect;
112
113 published
114 property Active;
115 property AutoCommit;
116 property BufferChunks;
117 property CachedUpdates;
118 property DataSource read GetDataSource write SetDataSource;
119 property GenerateParamNames;
120 // property Constraints stored ConstraintsStored;
121 property GeneratorField;
122 property ParamCheck;
123 property SQL: TStrings read FSQL write SetQuery;
124 property Params: TParams read FParams write SetParamsList;
125 property UniDirectional default False;
126 property UpdateObject;
127 property Filtered;
128 property DataSetCloseAction;
129
130 property BeforeDatabaseDisconnect;
131 property AfterDatabaseDisconnect;
132 property DatabaseFree;
133 property BeforeTransactionEnd;
134 property AfterTransactionEnd;
135 property TransactionFree;
136 property OnFilterRecord;
137 property OnValidatePost;
138 end;
139
140 implementation
141
142 uses FBMessages;
143
144 { 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 procedure TIBQuery.ResetParser;
206 begin
207 inherited ResetParser;
208 UpdateSQL;
209 end;
210
211 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 if FInQueryChanged then Exit;
228 FInQueryChanged := true;
229 try
230 if not (csReading in ComponentState) then
231 begin
232 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 end;
246 finally
247 FInQueryChanged := false;
248 end;
249 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 FParams.Clear;
304 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 if not Prepared then
354 Prepare;
355 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
376 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 SQLParam: ISQLParam;
395
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 var List: TParams;
446 begin
447 QSelect.GenerateParamNames := GenerateParamNames;
448 InternalPrepare;
449 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 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 function TIBQuery.GetStmtHandle: IStatement;
498 begin
499 Result := SelectStmtHandle;
500 end;
501
502 procedure TIBQuery.UpdateSQL;
503 begin
504 if not FSQLUpdating and not FInQueryChanged and (SQL.Text <> SelectSQL.Text) then
505 begin
506 FSQLUpdating := true;
507 try
508 SQL.Text := SelectSQL.Text;
509 finally
510 FSQLUpdating := false
511 end;
512 end;
513 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 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 { 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