ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/IBQuery.pas
Revision: 308
Committed: Sat Jul 18 10:26:30 2020 UTC (3 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 15787 byte(s)
Log Message:
Fixes Merged

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