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, 4 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

# User Rev Content
1 tony 19 {************************************************************************}
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 tony 39 {$codepage UTF8}
39    
40 tony 19 interface
41    
42     uses
43     {$IFDEF WINDOWS }
44     Windows,
45     {$ELSE}
46     baseunix, unix,
47     {$ENDIF}
48 tony 45 SysUtils, Classes, IBExternals, IB, IBDatabase, IBUtils;
49 tony 19
50     type
51     { TIBBatch }
52    
53     TIBBatch = class(TObject)
54     protected
55     FFilename: String;
56 tony 45 FColumns: IResults;
57     FParams: ISQLParams;
58 tony 19 public
59     procedure ReadyFile; virtual; abstract;
60 tony 45 property Columns: IResults read FColumns;
61 tony 19 property Filename: String read FFilename write FFilename;
62 tony 45 property Params: ISQLParams read FParams;
63 tony 19 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 tony 45 FMetaData: IMetaData;
152     FSQLParams: ISQLParams;
153     FStatement: IStatement;
154 tony 35 FOnSQLChanged: TNotifyEvent;
155 tony 19 FUniqueParamNames: Boolean;
156 tony 45 FBOF: boolean;
157     FEOF: boolean;
158 tony 19 function GetFieldCount: integer;
159 tony 45 function GetOpen: Boolean;
160     function GetPrepared: Boolean;
161     function GetSQLStatementType: TIBSQLStatementTypes;
162 tony 19 procedure SetUniqueParamNames(AValue: Boolean);
163     protected
164     FBase: TIBBase;
165 tony 45 FGoToFirstRecordOnExecute: boolean; { Automatically position record on first record after executing }
166 tony 19 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 tony 45 FResults: IResults; {Single row results from exec}
171     FResultSet: IResultSet; {Multi-row results from open cursor}
172 tony 19 FGenerateParamNames: Boolean; { Auto generate param names ?}
173     procedure DoBeforeDatabaseDisconnect(Sender: TObject);
174     function GetDatabase: TIBDatabase;
175     function GetEOF: Boolean;
176 tony 45 function GetFields(const Idx: Integer): ISQLData;
177 tony 19 function GetFieldIndex(FieldName: String): Integer;
178     function GetPlan: String;
179     function GetRecordCount: Integer;
180     function GetRowsAffected: Integer;
181 tony 45 function GetSQLParams: ISQLParams;
182 tony 19 function GetTransaction: TIBTransaction;
183     procedure SetDatabase(Value: TIBDatabase);
184     procedure SetSQL(Value: TStrings);
185     procedure SetTransaction(Value: TIBTransaction);
186     procedure SQLChanging(Sender: TObject);
187 tony 35 procedure SQLChanged(Sender: TObject);
188 tony 27 procedure BeforeTransactionEnd(Sender: TObject; Action: TTransactionAction);
189 tony 19 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 tony 45 function HasField(FieldName: String): boolean;
200     function FieldByName(FieldName: String): ISQLData;
201     function ParamByName(ParamName: String): ISQLParam;
202 tony 19 procedure FreeHandle;
203 tony 45 function Next: boolean;
204 tony 19 procedure Prepare;
205     function GetUniqueRelationName: String;
206     property Bof: Boolean read FBOF;
207     property Eof: Boolean read GetEOF;
208 tony 45 property Current: IResults read FResults;
209     property Fields[const Idx: Integer]: ISQLData read GetFields; default;
210 tony 19 property FieldIndex[FieldName: String]: Integer read GetFieldIndex;
211     property FieldCount: integer read GetFieldCount;
212 tony 45 property Open: Boolean read GetOpen;
213     property Params: ISQLParams read GetSQLParams;
214 tony 19 property Plan: String read GetPlan;
215 tony 45 property Prepared: Boolean read GetPrepared;
216 tony 19 property RecordCount: Integer read GetRecordCount;
217     property RowsAffected: Integer read GetRowsAffected;
218 tony 45 property SQLStatementType: TIBSQLStatementTypes read GetSQLStatementType;
219 tony 19 property UniqueRelationName: String read GetUniqueRelationName;
220 tony 45 property Statement: IStatement read FStatement;
221     property MetaData: IMetaData read FMetaData;
222 tony 19 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 tony 35 property OnSQLChanged: TNotifyEvent read FOnSQLChanged write FOnSQLChanged;
234 tony 19 end;
235    
236 tony 45 procedure IBAlloc(var P; OldSize, NewSize: Integer);
237    
238 tony 19 implementation
239    
240     uses
241 tony 45 Variants, IBSQLMonitor, FBMessages, IBCustomDataSet;
242 tony 19
243 tony 45 procedure IBAlloc(var P; OldSize, NewSize: Integer);
244 tony 19 var
245     i: Integer;
246     begin
247 tony 45 ReallocMem(Pointer(P), NewSize);
248     for i := OldSize to NewSize - 1 do PChar(P)[i] := #0;
249 tony 19 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 tony 45 st := Columns[i].GetAliasname
295 tony 19 else
296 tony 45 st := st + FColDelimiter + Columns[i].GetAliasname;
297 tony 19 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 tony 45 BytesWritten := FpWrite(FHandle,Columns[i].GetAsPointer^, Columns[i].GetSize);
488 tony 19 {$ELSE}
489 tony 45 WriteFile(FHandle, Columns[i].GetAsPointer^, Columns[i].GetSize,
490 tony 19 BytesWritten, nil);
491     {$ENDIF}
492 tony 45 if BytesWritten <> DWORD(Columns[i].GetSize) then
493 tony 19 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 tony 45 BytesRead := FpRead(FHandle,Params[i].GetAsPointer^,Params[i].GetSize);
528 tony 19 {$ELSE}
529 tony 45 ReadFile(FHandle, Params[i].GetAsPointer^, Params[i].GetSize,
530 tony 19 BytesRead, nil);
531     {$ENDIF}
532 tony 45 if BytesRead <> DWORD(Params[i].GetSize) then
533 tony 19 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 tony 35 TStringList(FSQL).OnChange := SQLChanged;
570 tony 19 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 tony 45 FreeHandle;
581     FSQL.Free;
582     FBase.Free;
583 tony 19 inherited Destroy;
584     end;
585    
586     procedure TIBSQL.BatchInput(InputObject: TIBBatchInput);
587     begin
588     if not Prepared then
589     Prepare;
590 tony 45 InputObject.FParams := Self.GetSQLParams;
591 tony 19 InputObject.ReadyFile;
592 tony 45 if GetSQLStatementType in [SQLInsert, SQLUpdate, SQLDelete, SQLExecProcedure] then
593 tony 19 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 tony 45 if GetSQLStatementType = SQLSelect then begin
603 tony 19 try
604     ExecQuery;
605 tony 45 OutputObject.FColumns := Self.FResults;
606 tony 19 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 tony 45 if FResultSet <> nil then IBError(ibxeSQLOpen, [nil]);
620 tony 19 end;
621    
622     procedure TIBSQL.CheckOpen;
623     begin
624 tony 45 if FResultSet = nil then IBError(ibxeSQLClosed, [nil]);
625 tony 19 end;
626    
627     procedure TIBSQL.CheckValidStatement;
628     begin
629     FBase.CheckTransaction;
630 tony 45 if (FStatement = nil) then
631 tony 19 IBError(ibxeInvalidStatementHandle, [nil]);
632     end;
633    
634     procedure TIBSQL.Close;
635     begin
636 tony 45 if FResults <> nil then
637     FResults.SetRetainInterfaces(false);
638     FResultSet := nil;
639     FResults := nil;
640     FBOF := false;
641     FEOF := false;
642     FRecordCount := 0;
643 tony 19 end;
644    
645 tony 45 function TIBSQL.GetFieldCount: integer;
646 tony 19 begin
647 tony 45 if FResults <> nil then
648     Result := FResults.GetCount
649 tony 19 else
650 tony 45 if FMetaData <> nil then
651     Result := FMetaData.GetCount
652     else
653     Result := 0;
654 tony 19 end;
655    
656 tony 45 function TIBSQL.GetOpen: Boolean;
657 tony 19 begin
658 tony 45 Result := FResultSet <> nil;
659 tony 19 end;
660    
661 tony 45 function TIBSQL.GetPrepared: Boolean;
662 tony 19 begin
663 tony 45 Result := (FStatement <> nil) and FStatement.IsPrepared;
664 tony 19 end;
665    
666 tony 45 function TIBSQL.GetSQLStatementType: TIBSQLStatementTypes;
667     begin
668     if FStatement = nil then
669     Result := SQLUnknown
670     else
671     Result := FStatement.GetSQLStatementType;
672     end;
673    
674 tony 19 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 tony 45 FreeHandle;
684 tony 19 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 tony 45 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 tony 19 end;
712 tony 27 FBase.DoAfterExecQuery(self);
713 tony 19 end;
714    
715 tony 45 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 tony 19 function TIBSQL.GetEOF: Boolean;
724     begin
725 tony 45 result := FEOF or (FResultSet = nil);
726 tony 19 end;
727    
728 tony 45 function TIBSQL.FieldByName(FieldName: String): ISQLData;
729 tony 19 begin
730 tony 45 if FResults = nil then
731     IBError(ibxeNoFieldAccess,[nil]);
732    
733     Result := FResults.ByName(FieldName);
734    
735     if Result = nil then
736 tony 19 IBError(ibxeFieldNotFound, [FieldName]);
737     end;
738    
739 tony 45 function TIBSQL.ParamByName(ParamName: String): ISQLParam;
740 tony 19 begin
741     Result := Params.ByName(ParamName);
742     end;
743    
744 tony 45 function TIBSQL.GetFields(const Idx: Integer): ISQLData;
745 tony 19 begin
746 tony 45 if FResults = nil then
747     IBError(ibxeNoFieldAccess,[nil]);
748    
749     if (Idx < 0) or (Idx >= FResults.GetCount) then
750 tony 19 IBError(ibxeFieldNotFound, [IntToStr(Idx)]);
751 tony 45 result := FResults[Idx];
752 tony 19 end;
753    
754     function TIBSQL.GetFieldIndex(FieldName: String): Integer;
755 tony 45 var Field: IColumnMetaData;
756 tony 19 begin
757 tony 45 if FMetaData = nil then
758     IBError(ibxeNoFieldAccess,[nil]);
759    
760     Field := FMetaData.ByName(FieldName);
761    
762     if Field = nil then
763 tony 19 result := -1
764     else
765 tony 45 result := Field.GetIndex;
766 tony 19 end;
767    
768 tony 45 function TIBSQL.Next: boolean;
769 tony 19 begin
770 tony 45 result := false;
771     if not FEOF then
772     begin
773 tony 19 CheckOpen;
774 tony 45 try
775     Result := FResultSet.FetchNext;
776     except
777     Close;
778     raise;
779     end;
780    
781     if Result then
782     begin
783 tony 19 Inc(FRecordCount);
784     FBOF := False;
785 tony 45 end
786     else
787     FEOF := true;
788    
789 tony 19 if not (csDesigning in ComponentState) then
790     MonitorHook.SQLFetch(Self);
791     end;
792     end;
793    
794     procedure TIBSQL.FreeHandle;
795     begin
796 tony 45 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 tony 19 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 tony 45 (not (GetSQLStatementType in [SQLSelect, SQLSelectForUpdate,
815 tony 19 {TODO: SQLExecProcedure, }
816     SQLUpdate, SQLDelete])) then
817     result := ''
818 tony 45 else
819     Result := FStatement.GetPlan;
820 tony 19 end;
821    
822     function TIBSQL.GetRecordCount: Integer;
823     begin
824 tony 45 Result := FRecordCount;
825 tony 19 end;
826    
827     function TIBSQL.GetRowsAffected: Integer;
828     var
829 tony 45 SelectCount, InsertCount, UpdateCount, DeleteCount: integer;
830 tony 19 begin
831     if not Prepared then
832 tony 45 Result := -1
833     else
834     begin
835     FStatement.GetRowsAffected(SelectCount, InsertCount, UpdateCount, DeleteCount);
836     Result := InsertCount + UpdateCount + DeleteCount;
837 tony 19 end;
838     end;
839    
840 tony 45 function TIBSQL.GetSQLParams: ISQLParams;
841 tony 19 begin
842     if not Prepared then
843     Prepare;
844 tony 45 result := Statement.SQLParams;
845 tony 19 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 tony 45 Close;
863     if Prepared then
864 tony 19 exit;
865     if (FSQL.Text = '') then
866     IBError(ibxeEmptyQuery, [nil]);
867 tony 45
868     if FStatement <> nil then
869     FStatement.Prepare(Transaction.TransactionIntf)
870     else
871 tony 19 if not ParamCheck then
872 tony 45 FStatement := Database.Attachment.Prepare(Transaction.TransactionIntf,SQL.Text)
873 tony 19 else
874 tony 45 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 tony 19 MonitorHook.SQLPrepare(Self);
883     end;
884    
885     function TIBSQL.GetUniqueRelationName: String;
886     begin
887 tony 45 if Prepared and (GetSQLStatementType = SQLSelect) then
888     result := FMetaData.GetUniqueRelationName
889 tony 19 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 tony 45
916     FreeHandle;
917 tony 19 end;
918    
919 tony 35 procedure TIBSQL.SQLChanged(Sender: TObject);
920     begin
921     if assigned(OnSQLChanged) then
922     OnSQLChanged(self);
923     end;
924    
925 tony 27 procedure TIBSQL.BeforeTransactionEnd(Sender: TObject;
926     Action: TTransactionAction);
927 tony 19 begin
928 tony 45 if not (Owner is TIBCustomDataSet) then
929     FreeHandle;
930 tony 19 end;
931    
932     end.