ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBSQL.pas
Revision: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 11 months ago) by tony
Content type: text/x-pascal
File size: 24587 byte(s)
Log Message:
Committing updates for Release R2-0-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 - 2014 }
31 { }
32 {************************************************************************}
33
34 unit IBSQL;
35
36 {$Mode Delphi}
37
38 {$codepage UTF8}
39
40 interface
41
42 uses
43 {$IFDEF WINDOWS }
44 Windows,
45 {$ELSE}
46 baseunix, unix,
47 {$ENDIF}
48 SysUtils, Classes, IBExternals, IB, IBDatabase, IBUtils;
49
50 type
51 { TIBBatch }
52
53 TIBBatch = class(TObject)
54 protected
55 FFilename: String;
56 FColumns: IResults;
57 FParams: ISQLParams;
58 public
59 procedure ReadyFile; virtual; abstract;
60 property Columns: IResults read FColumns;
61 property Filename: String read FFilename write FFilename;
62 property Params: ISQLParams read FParams;
63 end;
64
65 TIBBatchInput = class(TIBBatch)
66 public
67 function ReadParameters: Boolean; virtual; abstract;
68 end;
69
70 TIBBatchOutput = class(TIBBatch)
71 public
72 function WriteColumns: Boolean; virtual; abstract;
73 end;
74
75
76 { TIBOutputDelimitedFile }
77 TIBOutputDelimitedFile = class(TIBBatchOutput)
78 protected
79 {$IFDEF UNIX}
80 FHandle: cint;
81 {$ELSE}
82 FHandle: THandle;
83 {$ENDIF}
84 FOutputTitles: Boolean;
85 FColDelimiter,
86 FRowDelimiter: string;
87 public
88 destructor Destroy; override;
89 procedure ReadyFile; override;
90 function WriteColumns: Boolean; override;
91 property ColDelimiter: string read FColDelimiter write FColDelimiter;
92 property OutputTitles: Boolean read FOutputTitles
93 write FOutputTitles;
94 property RowDelimiter: string read FRowDelimiter write FRowDelimiter;
95 end;
96
97 { TIBInputDelimitedFile }
98 TIBInputDelimitedFile = class(TIBBatchInput)
99 protected
100 FColDelimiter,
101 FRowDelimiter: string;
102 FEOF: Boolean;
103 FFile: TFileStream;
104 FLookAhead: Char;
105 FReadBlanksAsNull: Boolean;
106 FSkipTitles: Boolean;
107 public
108 destructor Destroy; override;
109 function GetColumn(var Col: string): Integer;
110 function ReadParameters: Boolean; override;
111 procedure ReadyFile; override;
112 property ColDelimiter: string read FColDelimiter write FColDelimiter;
113 property ReadBlanksAsNull: Boolean read FReadBlanksAsNull
114 write FReadBlanksAsNull;
115 property RowDelimiter: string read FRowDelimiter write FRowDelimiter;
116 property SkipTitles: Boolean read FSkipTitles write FSkipTitles;
117 end;
118
119 { TIBOutputRawFile }
120 TIBOutputRawFile = class(TIBBatchOutput)
121 protected
122 {$IFDEF UNIX}
123 FHandle: cint;
124 {$ELSE}
125 FHandle: THandle;
126 {$ENDIF}
127 public
128 destructor Destroy; override;
129 procedure ReadyFile; override;
130 function WriteColumns: Boolean; override;
131 end;
132
133 { TIBInputRawFile }
134 TIBInputRawFile = class(TIBBatchInput)
135 protected
136 {$IFDEF UNIX}
137 FHandle: cint;
138 {$ELSE}
139 FHandle: THandle;
140 {$ENDIF}
141 public
142 destructor Destroy; override;
143 function ReadParameters: Boolean; override;
144 procedure ReadyFile; override;
145 end;
146
147 { TIBSQL }
148
149 TIBSQL = class(TComponent)
150 private
151 FMetaData: IMetaData;
152 FSQLParams: ISQLParams;
153 FStatement: IStatement;
154 FOnSQLChanged: TNotifyEvent;
155 FUniqueParamNames: Boolean;
156 FBOF: boolean;
157 FEOF: boolean;
158 function GetFieldCount: integer;
159 function GetOpen: Boolean;
160 function GetPrepared: Boolean;
161 function GetSQLStatementType: TIBSQLStatementTypes;
162 procedure SetUniqueParamNames(AValue: Boolean);
163 protected
164 FBase: TIBBase;
165 FGoToFirstRecordOnExecute: boolean; { Automatically position record on first record after executing }
166 FRecordCount: Integer; { How many records have been read so far? }
167 FOnSQLChanging: TNotifyEvent; { Call this when the SQL is changing }
168 FSQL: TStrings; { SQL Query (by user) }
169 FParamCheck: Boolean; { Check for parameters? (just like TQuery) }
170 FResults: IResults; {Single row results from exec}
171 FResultSet: IResultSet; {Multi-row results from open cursor}
172 FGenerateParamNames: Boolean; { Auto generate param names ?}
173 procedure DoBeforeDatabaseDisconnect(Sender: TObject);
174 function GetDatabase: TIBDatabase;
175 function GetEOF: Boolean;
176 function GetFields(const Idx: Integer): ISQLData;
177 function GetFieldIndex(FieldName: String): Integer;
178 function GetPlan: String;
179 function GetRecordCount: Integer;
180 function GetRowsAffected: Integer;
181 function GetSQLParams: ISQLParams;
182 function GetTransaction: TIBTransaction;
183 procedure SetDatabase(Value: TIBDatabase);
184 procedure SetSQL(Value: TStrings);
185 procedure SetTransaction(Value: TIBTransaction);
186 procedure SQLChanging(Sender: TObject);
187 procedure SQLChanged(Sender: TObject);
188 procedure BeforeTransactionEnd(Sender: TObject; Action: TTransactionAction);
189 public
190 constructor Create(AOwner: TComponent); override;
191 destructor Destroy; override;
192 procedure BatchInput(InputObject: TIBBatchInput);
193 procedure BatchOutput(OutputObject: TIBBatchOutput);
194 procedure CheckClosed; { raise error if query is not closed. }
195 procedure CheckOpen; { raise error if query is not open.}
196 procedure CheckValidStatement; { raise error if statement is invalid.}
197 procedure Close;
198 procedure ExecQuery;
199 function HasField(FieldName: String): boolean;
200 function FieldByName(FieldName: String): ISQLData;
201 function ParamByName(ParamName: String): ISQLParam;
202 procedure FreeHandle;
203 function Next: boolean;
204 procedure Prepare;
205 function GetUniqueRelationName: String;
206 property Bof: Boolean read FBOF;
207 property Eof: Boolean read GetEOF;
208 property Current: IResults read FResults;
209 property Fields[const Idx: Integer]: ISQLData read GetFields; default;
210 property FieldIndex[FieldName: String]: Integer read GetFieldIndex;
211 property FieldCount: integer read GetFieldCount;
212 property Open: Boolean read GetOpen;
213 property Params: ISQLParams read GetSQLParams;
214 property Plan: String read GetPlan;
215 property Prepared: Boolean read GetPrepared;
216 property RecordCount: Integer read GetRecordCount;
217 property RowsAffected: Integer read GetRowsAffected;
218 property SQLStatementType: TIBSQLStatementTypes read GetSQLStatementType;
219 property UniqueRelationName: String read GetUniqueRelationName;
220 property Statement: IStatement read FStatement;
221 property MetaData: IMetaData read FMetaData;
222 published
223 property Database: TIBDatabase read GetDatabase write SetDatabase;
224 property GenerateParamNames: Boolean read FGenerateParamNames write FGenerateParamNames;
225 property UniqueParamNames: Boolean read FUniqueParamNames write SetUniqueParamNames;
226 property GoToFirstRecordOnExecute: Boolean read FGoToFirstRecordOnExecute
227 write FGoToFirstRecordOnExecute
228 default True;
229 property ParamCheck: Boolean read FParamCheck write FParamCheck;
230 property SQL: TStrings read FSQL write SetSQL;
231 property Transaction: TIBTransaction read GetTransaction write SetTransaction;
232 property OnSQLChanging: TNotifyEvent read FOnSQLChanging write FOnSQLChanging;
233 property OnSQLChanged: TNotifyEvent read FOnSQLChanged write FOnSQLChanged;
234 end;
235
236 procedure IBAlloc(var P; OldSize, NewSize: Integer);
237
238 implementation
239
240 uses
241 Variants, IBSQLMonitor, FBMessages, IBCustomDataSet;
242
243 procedure IBAlloc(var P; OldSize, NewSize: Integer);
244 var
245 i: Integer;
246 begin
247 ReallocMem(Pointer(P), NewSize);
248 for i := OldSize to NewSize - 1 do PChar(P)[i] := #0;
249 end;
250
251 { TIBOutputDelimitedFile }
252
253 destructor TIBOutputDelimitedFile.Destroy;
254 begin
255 {$IFDEF UNIX}
256 if FHandle <> -1 then
257 fpclose(FHandle);
258 {$ELSE}
259 if FHandle <> 0 then
260 begin
261 FlushFileBuffers(FHandle);
262 CloseHandle(FHandle);
263 end;
264 {$ENDIF}
265 inherited Destroy;
266 end;
267
268 procedure TIBOutputDelimitedFile.ReadyFile;
269 var
270 i: Integer;
271 {$IFDEF UNIX}
272 BytesWritten: cint;
273 {$ELSE}
274 BytesWritten: DWORD;
275 {$ENDIF}
276 st: string;
277 begin
278 if FColDelimiter = '' then
279 FColDelimiter := TAB;
280 if FRowDelimiter = '' then
281 FRowDelimiter := CRLF;
282 {$IFDEF UNIX}
283 FHandle := FpOpen(Filename,O_WrOnly or O_Creat);
284 {$ELSE}
285 FHandle := CreateFile(PChar(Filename), GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
286 FILE_ATTRIBUTE_NORMAL, 0);
287 if FHandle = INVALID_HANDLE_VALUE then
288 FHandle := 0;
289 {$ENDIF}
290 if FOutputTitles then
291 begin
292 for i := 0 to Columns.Count - 1 do
293 if i = 0 then
294 st := Columns[i].GetAliasname
295 else
296 st := st + FColDelimiter + Columns[i].GetAliasname;
297 st := st + FRowDelimiter;
298 {$IFDEF UNIX}
299 if FHandle <> -1 then
300 BytesWritten := FpWrite(FHandle,st[1],Length(st));
301 if BytesWritten = -1 then
302 raise Exception.Create('File Write Error');
303 {$ELSE}
304 WriteFile(FHandle, st[1], Length(st), BytesWritten, nil);
305 {$ENDIF}
306 end;
307 end;
308
309 function TIBOutputDelimitedFile.WriteColumns: Boolean;
310 var
311 i: Integer;
312 {$IFDEF UNIX}
313 BytesWritten: cint;
314 {$ELSE}
315 BytesWritten: DWORD;
316 {$ENDIF}
317 st: string;
318 begin
319 result := False;
320 {$IFDEF UNIX}
321 if FHandle <> -1 then
322 {$ELSE}
323 if FHandle <> 0 then
324 {$ENDIF}
325 begin
326 st := '';
327 for i := 0 to Columns.Count - 1 do
328 begin
329 if i > 0 then
330 st := st + FColDelimiter;
331 st := st + StripString(Columns[i].AsString, FColDelimiter + FRowDelimiter);
332 end;
333 st := st + FRowDelimiter;
334 {$IFDEF UNIX}
335 BytesWritten := FpWrite(FHandle,st[1],Length(st));
336 {$ELSE}
337 WriteFile(FHandle, st[1], Length(st), BytesWritten, nil);
338 {$ENDIF}
339 if BytesWritten = DWORD(Length(st)) then
340 result := True;
341 end
342 end;
343
344 { TIBInputDelimitedFile }
345
346 destructor TIBInputDelimitedFile.Destroy;
347 begin
348 FFile.Free;
349 inherited Destroy;
350 end;
351
352 function TIBInputDelimitedFile.GetColumn(var Col: string): Integer;
353 var
354 c: Char;
355 BytesRead: Integer;
356
357 procedure ReadInput;
358 begin
359 if FLookAhead <> NULL_TERMINATOR then
360 begin
361 c := FLookAhead;
362 BytesRead := 1;
363 FLookAhead := NULL_TERMINATOR;
364 end else
365 BytesRead := FFile.Read(c, 1);
366 end;
367
368 procedure CheckCRLF(Delimiter: string);
369 begin
370 if (c = CR) and (Pos(LF, Delimiter) > 0) then {mbcs ok}
371 begin
372 BytesRead := FFile.Read(c, 1);
373 if (BytesRead = 1) and (c <> #10) then
374 FLookAhead := c
375 end;
376 end;
377
378 begin
379 Col := '';
380 result := 0;
381 ReadInput;
382 while BytesRead <> 0 do begin
383 if Pos(c, FColDelimiter) > 0 then {mbcs ok}
384 begin
385 CheckCRLF(FColDelimiter);
386 result := 1;
387 break;
388 end else if Pos(c, FRowDelimiter) > 0 then {mbcs ok}
389 begin
390 CheckCRLF(FRowDelimiter);
391 result := 2;
392 break;
393 end else
394 Col := Col + c;
395 ReadInput;
396 end;
397 end;
398
399 function TIBInputDelimitedFile.ReadParameters: Boolean;
400 var
401 i, curcol: Integer;
402 Col: string;
403 begin
404 result := False;
405 if not FEOF then begin
406 curcol := 0;
407 repeat
408 i := GetColumn(Col);
409 if (i = 0) then
410 FEOF := True;
411 if (curcol < Params.Count) then
412 begin
413 try
414 if (Col = '') and
415 (ReadBlanksAsNull) then
416 Params[curcol].IsNull := True
417 else
418 Params[curcol].AsString := Col;
419 Inc(curcol);
420 except
421 on E: Exception do begin
422 if not (FEOF and (curcol = Params.Count)) then
423 raise;
424 end;
425 end;
426 end;
427 until (FEOF) or (i = 2);
428 result := ((FEOF) and (curcol = Params.Count)) or
429 (not FEOF);
430 end;
431 end;
432
433 procedure TIBInputDelimitedFile.ReadyFile;
434 begin
435 if FColDelimiter = '' then
436 FColDelimiter := TAB;
437 if FRowDelimiter = '' then
438 FRowDelimiter := CRLF;
439 FLookAhead := NULL_TERMINATOR;
440 FEOF := False;
441 if FFile <> nil then
442 FFile.Free;
443 FFile := TFileStream.Create(FFilename, fmOpenRead or fmShareDenyWrite);
444 if FSkipTitles then
445 ReadParameters;
446 end;
447
448 { TIBOutputRawFile }
449 destructor TIBOutputRawFile.Destroy;
450 begin
451 {$IFDEF UNIX}
452 if FHandle <> -1 then
453 fpclose(FHandle);
454 {$ELSE}
455 if FHandle <> 0 then
456 begin
457 FlushFileBuffers(FHandle);
458 CloseHandle(FHandle);
459 end;
460 {$ENDIF}
461 inherited Destroy;
462 end;
463
464 procedure TIBOutputRawFile.ReadyFile;
465 begin
466 {$IFDEF UNIX}
467 FHandle := FpOpen(Filename,O_WrOnly or O_Creat);
468 {$ELSE}
469 FHandle := CreateFile(PChar(Filename), GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
470 FILE_ATTRIBUTE_NORMAL, 0);
471 if FHandle = INVALID_HANDLE_VALUE then
472 FHandle := 0;
473 {$ENDIF}
474 end;
475
476 function TIBOutputRawFile.WriteColumns: Boolean;
477 var
478 i: Integer;
479 BytesWritten: DWord;
480 begin
481 result := False;
482 if FHandle <> 0 then
483 begin
484 for i := 0 to Columns.Count - 1 do
485 begin
486 {$IFDEF UNIX}
487 BytesWritten := FpWrite(FHandle,Columns[i].GetAsPointer^, Columns[i].GetSize);
488 {$ELSE}
489 WriteFile(FHandle, Columns[i].GetAsPointer^, Columns[i].GetSize,
490 BytesWritten, nil);
491 {$ENDIF}
492 if BytesWritten <> DWORD(Columns[i].GetSize) then
493 exit;
494 end;
495 result := True;
496 end;
497 end;
498
499 { TIBInputRawFile }
500 destructor TIBInputRawFile.Destroy;
501 begin
502 {$IFDEF UNIX}
503 if FHandle <> -1 then
504 fpclose(FHandle);
505 {$ELSE}
506 if FHandle <> 0 then
507 CloseHandle(FHandle);
508 {$ENDIF}
509 inherited Destroy;
510 end;
511
512 function TIBInputRawFile.ReadParameters: Boolean;
513 var
514 i: Integer;
515 BytesRead: DWord;
516 begin
517 result := False;
518 {$IFDEF UNIX}
519 if FHandle <> -1 then
520 {$ELSE}
521 if FHandle <> 0 then
522 {$ENDIF}
523 begin
524 for i := 0 to Params.Count - 1 do
525 begin
526 {$IFDEF UNIX}
527 BytesRead := FpRead(FHandle,Params[i].GetAsPointer^,Params[i].GetSize);
528 {$ELSE}
529 ReadFile(FHandle, Params[i].GetAsPointer^, Params[i].GetSize,
530 BytesRead, nil);
531 {$ENDIF}
532 if BytesRead <> DWORD(Params[i].GetSize) then
533 exit;
534 end;
535 result := True;
536 end;
537 end;
538
539 procedure TIBInputRawFile.ReadyFile;
540 begin
541 {$IFDEF UNIX}
542 if FHandle <> -1 then
543 fpclose(FHandle);
544 FHandle := FpOpen(Filename,O_RdOnly);
545 if FHandle = -1 then
546 raise Exception.CreateFmt('Unable to open file %s',[Filename]);
547 {$ELSE}
548 if FHandle <> 0 then
549 CloseHandle(FHandle);
550 FHandle := CreateFile(PChar(Filename), GENERIC_READ, 0, nil, OPEN_EXISTING,
551 FILE_FLAG_SEQUENTIAL_SCAN, 0);
552 if FHandle = INVALID_HANDLE_VALUE then
553 FHandle := 0;
554 {$ENDIF}
555 end;
556
557 { TIBSQL }
558 constructor TIBSQL.Create(AOwner: TComponent);
559 begin
560 inherited Create(AOwner);
561 FGenerateParamNames := False;
562 FGoToFirstRecordOnExecute := True;
563 FBase := TIBBase.Create(Self);
564 FBase.BeforeDatabaseDisconnect := DoBeforeDatabaseDisconnect;
565 FBase.BeforeTransactionEnd := BeforeTransactionEnd;
566 FRecordCount := 0;
567 FSQL := TStringList.Create;
568 TStringList(FSQL).OnChanging := SQLChanging;
569 TStringList(FSQL).OnChange := SQLChanged;
570 FParamCheck := True;
571 if AOwner is TIBDatabase then
572 Database := TIBDatabase(AOwner)
573 else
574 if AOwner is TIBTransaction then
575 Transaction := TIBTransaction(AOwner);
576 end;
577
578 destructor TIBSQL.Destroy;
579 begin
580 FreeHandle;
581 FSQL.Free;
582 FBase.Free;
583 inherited Destroy;
584 end;
585
586 procedure TIBSQL.BatchInput(InputObject: TIBBatchInput);
587 begin
588 if not Prepared then
589 Prepare;
590 InputObject.FParams := Self.GetSQLParams;
591 InputObject.ReadyFile;
592 if GetSQLStatementType in [SQLInsert, SQLUpdate, SQLDelete, SQLExecProcedure] then
593 while InputObject.ReadParameters do
594 ExecQuery;
595 end;
596
597 procedure TIBSQL.BatchOutput(OutputObject: TIBBatchOutput);
598 begin
599 CheckClosed;
600 if not Prepared then
601 Prepare;
602 if GetSQLStatementType = SQLSelect then begin
603 try
604 ExecQuery;
605 OutputObject.FColumns := Self.FResults;
606 OutputObject.ReadyFile;
607 if not FGoToFirstRecordOnExecute then
608 Next;
609 while (not Eof) and (OutputObject.WriteColumns) do
610 Next;
611 finally
612 Close;
613 end;
614 end;
615 end;
616
617 procedure TIBSQL.CheckClosed;
618 begin
619 if FResultSet <> nil then IBError(ibxeSQLOpen, [nil]);
620 end;
621
622 procedure TIBSQL.CheckOpen;
623 begin
624 if FResultSet = nil then IBError(ibxeSQLClosed, [nil]);
625 end;
626
627 procedure TIBSQL.CheckValidStatement;
628 begin
629 FBase.CheckTransaction;
630 if (FStatement = nil) then
631 IBError(ibxeInvalidStatementHandle, [nil]);
632 end;
633
634 procedure TIBSQL.Close;
635 begin
636 if FResults <> nil then
637 FResults.SetRetainInterfaces(false);
638 FResultSet := nil;
639 FResults := nil;
640 FBOF := false;
641 FEOF := false;
642 FRecordCount := 0;
643 end;
644
645 function TIBSQL.GetFieldCount: integer;
646 begin
647 if FResults <> nil then
648 Result := FResults.GetCount
649 else
650 if FMetaData <> nil then
651 Result := FMetaData.GetCount
652 else
653 Result := 0;
654 end;
655
656 function TIBSQL.GetOpen: Boolean;
657 begin
658 Result := FResultSet <> nil;
659 end;
660
661 function TIBSQL.GetPrepared: Boolean;
662 begin
663 Result := (FStatement <> nil) and FStatement.IsPrepared;
664 end;
665
666 function TIBSQL.GetSQLStatementType: TIBSQLStatementTypes;
667 begin
668 if FStatement = nil then
669 Result := SQLUnknown
670 else
671 Result := FStatement.GetSQLStatementType;
672 end;
673
674 procedure TIBSQL.SetUniqueParamNames(AValue: Boolean);
675 begin
676 if FUniqueParamNames = AValue then Exit;
677 FreeHandle;
678 FUniqueParamNames := AValue;
679 end;
680
681 procedure TIBSQL.DoBeforeDatabaseDisconnect(Sender: TObject);
682 begin
683 FreeHandle;
684 end;
685
686 procedure TIBSQL.ExecQuery;
687 var
688 fetch_res: ISC_STATUS;
689 begin
690 CheckClosed;
691 if not Prepared then Prepare;
692 CheckValidStatement;
693 if SQLStatementType = SQLSelect then
694 begin
695 FResultSet := FStatement.OpenCursor;
696 FResults := FResultSet;
697 FResults.SetRetainInterfaces(true);
698 FBOF := True;
699 FEOF := False;
700 FRecordCount := 0;
701 if not (csDesigning in ComponentState) then
702 MonitorHook.SQLExecute(Self);
703 if FGoToFirstRecordOnExecute then
704 Next;
705 end
706 else
707 begin
708 FResults := FStatement.Execute;
709 if not (csDesigning in ComponentState) then
710 MonitorHook.SQLExecute(Self);
711 end;
712 FBase.DoAfterExecQuery(self);
713 end;
714
715 function TIBSQL.HasField(FieldName: String): boolean;
716 begin
717 if FResults = nil then
718 IBError(ibxeNoFieldAccess,[nil]);
719
720 Result := FResults.ByName(FieldName) <> nil;
721 end;
722
723 function TIBSQL.GetEOF: Boolean;
724 begin
725 result := FEOF or (FResultSet = nil);
726 end;
727
728 function TIBSQL.FieldByName(FieldName: String): ISQLData;
729 begin
730 if FResults = nil then
731 IBError(ibxeNoFieldAccess,[nil]);
732
733 Result := FResults.ByName(FieldName);
734
735 if Result = nil then
736 IBError(ibxeFieldNotFound, [FieldName]);
737 end;
738
739 function TIBSQL.ParamByName(ParamName: String): ISQLParam;
740 begin
741 Result := Params.ByName(ParamName);
742 end;
743
744 function TIBSQL.GetFields(const Idx: Integer): ISQLData;
745 begin
746 if FResults = nil then
747 IBError(ibxeNoFieldAccess,[nil]);
748
749 if (Idx < 0) or (Idx >= FResults.GetCount) then
750 IBError(ibxeFieldNotFound, [IntToStr(Idx)]);
751 result := FResults[Idx];
752 end;
753
754 function TIBSQL.GetFieldIndex(FieldName: String): Integer;
755 var Field: IColumnMetaData;
756 begin
757 if FMetaData = nil then
758 IBError(ibxeNoFieldAccess,[nil]);
759
760 Field := FMetaData.ByName(FieldName);
761
762 if Field = nil then
763 result := -1
764 else
765 result := Field.GetIndex;
766 end;
767
768 function TIBSQL.Next: boolean;
769 begin
770 result := false;
771 if not FEOF then
772 begin
773 CheckOpen;
774 try
775 Result := FResultSet.FetchNext;
776 except
777 Close;
778 raise;
779 end;
780
781 if Result then
782 begin
783 Inc(FRecordCount);
784 FBOF := False;
785 end
786 else
787 FEOF := true;
788
789 if not (csDesigning in ComponentState) then
790 MonitorHook.SQLFetch(Self);
791 end;
792 end;
793
794 procedure TIBSQL.FreeHandle;
795 begin
796 if FStatement <> nil then
797 FStatement.SetRetainInterfaces(false);
798 Close;
799 FStatement := nil;
800 FResults := nil;
801 FResultSet := nil;
802 FMetaData := nil;
803 FSQLParams := nil;
804 end;
805
806 function TIBSQL.GetDatabase: TIBDatabase;
807 begin
808 result := FBase.Database;
809 end;
810
811 function TIBSQL.GetPlan: String;
812 begin
813 if (not Prepared) or
814 (not (GetSQLStatementType in [SQLSelect, SQLSelectForUpdate,
815 {TODO: SQLExecProcedure, }
816 SQLUpdate, SQLDelete])) then
817 result := ''
818 else
819 Result := FStatement.GetPlan;
820 end;
821
822 function TIBSQL.GetRecordCount: Integer;
823 begin
824 Result := FRecordCount;
825 end;
826
827 function TIBSQL.GetRowsAffected: Integer;
828 var
829 SelectCount, InsertCount, UpdateCount, DeleteCount: integer;
830 begin
831 if not Prepared then
832 Result := -1
833 else
834 begin
835 FStatement.GetRowsAffected(SelectCount, InsertCount, UpdateCount, DeleteCount);
836 Result := InsertCount + UpdateCount + DeleteCount;
837 end;
838 end;
839
840 function TIBSQL.GetSQLParams: ISQLParams;
841 begin
842 if not Prepared then
843 Prepare;
844 result := Statement.SQLParams;
845 end;
846
847 function TIBSQL.GetTransaction: TIBTransaction;
848 begin
849 result := FBase.Transaction;
850 end;
851
852 procedure TIBSQL.SetDatabase(Value: TIBDatabase);
853 begin
854 FBase.Database := Value;
855 end;
856
857 procedure TIBSQL.Prepare;
858 begin
859 CheckClosed;
860 FBase.CheckDatabase;
861 FBase.CheckTransaction;
862 Close;
863 if Prepared then
864 exit;
865 if (FSQL.Text = '') then
866 IBError(ibxeEmptyQuery, [nil]);
867
868 if FStatement <> nil then
869 FStatement.Prepare(Transaction.TransactionIntf)
870 else
871 if not ParamCheck then
872 FStatement := Database.Attachment.Prepare(Transaction.TransactionIntf,SQL.Text)
873 else
874 FStatement := Database.Attachment.PrepareWithNamedParameters(
875 Transaction.TransactionIntf,
876 SQL.Text,
877 GenerateParamNames);
878 FMetaData := FStatement.GetMetaData;
879 FSQLParams := FStatement.GetSQLParams;
880 FStatement.SetRetainInterfaces(true);
881 if not (csDesigning in ComponentState) then
882 MonitorHook.SQLPrepare(Self);
883 end;
884
885 function TIBSQL.GetUniqueRelationName: String;
886 begin
887 if Prepared and (GetSQLStatementType = SQLSelect) then
888 result := FMetaData.GetUniqueRelationName
889 else
890 result := '';
891 end;
892
893 procedure TIBSQL.SetSQL(Value: TStrings);
894 begin
895 if FSQL.Text <> Value.Text then
896 begin
897 FSQL.BeginUpdate;
898 try
899 FSQL.Assign(Value);
900 finally
901 FSQL.EndUpdate;
902 end;
903 end;
904 end;
905
906 procedure TIBSQL.SetTransaction(Value: TIBTransaction);
907 begin
908 FBase.Transaction := Value;
909 end;
910
911 procedure TIBSQL.SQLChanging(Sender: TObject);
912 begin
913 if Assigned(OnSQLChanging) then
914 OnSQLChanging(Self);
915
916 FreeHandle;
917 end;
918
919 procedure TIBSQL.SQLChanged(Sender: TObject);
920 begin
921 if assigned(OnSQLChanged) then
922 OnSQLChanged(self);
923 end;
924
925 procedure TIBSQL.BeforeTransactionEnd(Sender: TObject;
926 Action: TTransactionAction);
927 begin
928 if not (Owner is TIBCustomDataSet) then
929 FreeHandle;
930 end;
931
932 end.