ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBAttachment.pas
Revision: 371
Committed: Wed Jan 5 15:21:22 2022 UTC (2 years, 10 months ago) by tony
Content type: text/x-pascal
File size: 55643 byte(s)
Log Message:
Beta Release 0.1

File Contents

# User Rev Content
1 tony 45 (*
2     * Firebird Interface (fbintf). The fbintf components provide a set of
3     * Pascal language bindings for the Firebird API.
4     *
5     * The contents of this file are subject to the Initial Developer's
6     * Public License Version 1.0 (the "License"); you may not use this
7     * file except in compliance with the License. You may obtain a copy
8     * of the License here:
9     *
10     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11     *
12     * Software distributed under the License is distributed on an "AS
13     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14     * implied. See the License for the specific language governing rights
15     * and limitations under the License.
16     *
17     * The Initial Developer of the Original Code is Tony Whyman.
18     *
19 tony 371 * The Original Code is (C) 2016-2021 Tony Whyman, MWA Software
20 tony 45 * (http://www.mwasoftware.co.uk).
21     *
22     * All Rights Reserved.
23     *
24     * Contributor(s): ______________________________________.
25     *
26     *)
27     unit FBAttachment;
28 tony 56 {$IFDEF MSWINDOWS}
29     {$DEFINE WINDOWS}
30     {$ENDIF}
31 tony 45
32     {$IFDEF FPC}
33 tony 56 {$mode delphi}
34 tony 45 {$interfaces COM}
35 tony 118 {$define HASREQEX}
36 tony 45 {$ENDIF}
37    
38     interface
39    
40     uses
41 tony 263 Classes, SysUtils, {$IFDEF WINDOWS} windows, {$ENDIF} IB, FBParamBlock,
42 tony 363 FBActivityMonitor, FBClientAPI, IBUtils;
43 tony 45
44 tony 345 const
45     DefaultMaxInlineBlobLimit = 8192;
46    
47 tony 45 type
48 tony 60 TCharsetMap = record
49     CharsetID: integer;
50     CharSetName: AnsiString;
51     CharSetWidth: integer;
52     CodePage: TSystemCodePage;
53     AllowReverseLookup: boolean; {used to ensure that lookup of CP_UTF* does not return UNICODE_FSS}
54     end;
55 tony 45
56 tony 363 { Database Journalling.
57    
58     This class is intended to support a client side journal of all database
59     updates, inserts and deletes made by the client during a session. It also records
60     the transaction each update was made under.
61    
62     The database schema is required to include a control table "IBX$JOURNALS" and
63     an SQL Sequence IBX$SESSIONS. These are created by the class when the
64     database is opened, if they are not already present. However, it is recommended
65     that they are created as an orginal part of the database schema in order to
66     unnecessarily avoid each user being given sufficient priviledge to create tables
67     and Sequences.
68    
69     Syntax:
70    
71     Transaction Start:
72 tony 371 *S:<date/time>,<attachmentid>,<session id>,<transaction no.>,<string length>:<transaction Name>,<string length>:<TPB>,<default Completion>
73 tony 363
74     Transaction Commit:
75 tony 371 *C:<date/time>,<attachmentid>,<session id>,<transaction no.>
76 tony 363
77     Transaction Commit retaining :
78 tony 371 *c:<date/time>,<attachmentid>,<session id>,<transaction no.><old transaction no.>
79 tony 363
80     Transaction Rollback:
81 tony 371 *R:<date/time>,<attachmentid>,<session id>,<transaction no.>
82 tony 363
83     Transaction Rollback retaining:
84 tony 371 *r:<date/time>,<attachmentid>,<session id>,<transaction no.><old transaction no.>
85 tony 363
86     Update/Insert/Delete
87 tony 371 *Q:<date/time>,<attachmentid>,<session id>,<transaction no.>,<length of query text in bytes>:<query text>
88 tony 363
89     }
90    
91     { TFBJournaling }
92    
93     TFBJournaling = class(TActivityHandler, IJournallingHook)
94     private
95     {Logfile}
96 tony 371 const sQueryJournal = '*Q:''%s'',%d,%d,%d,%d:%s' + LineEnding;
97     const sTransStartJnl = '*S:''%s'',%d,%d,%d,%d:%s,%d:%s,%d' + LineEnding;
98     const sTransCommitJnl = '*C:''%s'',%d,%d,%d' + LineEnding;
99     const sTransCommitRetJnl = '*c:''%s'',%d,%d,%d,%d' + LineEnding;
100     const sTransRollBackJnl = '*R:''%s'',%d,%d,%d' + LineEnding;
101     const sTransRollBackRetJnl = '*r:''%s'',%d,%d,%d,%d' + LineEnding;
102 tony 363 private
103     FOptions: TJournalOptions;
104     FJournalFilePath: string;
105     FJournalFileStream: TStream;
106     FSessionID: integer;
107     FDoNotJournal: boolean;
108     function GetDateTimeFmt: AnsiString;
109     protected
110     procedure EndSession(RetainJournal: boolean);
111     function GetAttachment: IAttachment; virtual; abstract;
112     public
113     {IAttachment}
114     procedure Disconnect(Force: boolean=false); virtual;
115     public
116     {IJournallingHook}
117     procedure TransactionStart(Tr: ITransaction);
118     function TransactionEnd( TransactionID: integer; Action: TTransactionAction): boolean;
119     procedure TransactionRetained(Tr: ITransaction; OldTransactionID: integer;
120     Action: TTransactionAction);
121     procedure ExecQuery(Stmt: IStatement);
122     public
123     {Client side Journaling}
124     function JournalingActive: boolean;
125     function GetJournalOptions: TJournalOptions;
126     function StartJournaling(aJournalLogFile: AnsiString): integer; overload;
127     function StartJournaling(aJournalLogFile: AnsiString; Options: TJournalOptions): integer; overload;
128 tony 371 function StartJournaling(S: TStream; Options: TJournalOptions): integer; overload;
129 tony 363 procedure StopJournaling(RetainJournal: boolean);
130     end;
131    
132 tony 45 { TFBAttachment }
133    
134 tony 363 TFBAttachment = class(TFBJournaling)
135 tony 45 private
136     FDPB: IDPB;
137     FFirebirdAPI: IFirebirdAPI;
138 tony 117 FODSMajorVersion: integer;
139     FODSMinorVersion: integer;
140 tony 60 FUserCharSetMap: array of TCharSetMap;
141 tony 209 FSecDatabase: AnsiString;
142 tony 345 FInlineBlobLimit: integer;
143 tony 371 FAttachmentID: integer;
144 tony 45 protected
145 tony 56 FDatabaseName: AnsiString;
146 tony 45 FRaiseExceptionOnConnectError: boolean;
147     FSQLDialect: integer;
148     FHasDefaultCharSet: boolean;
149     FCharSetID: integer;
150     FCodePage: TSystemCodePage;
151 tony 117 FRemoteProtocol: AnsiString;
152 tony 143 FAuthMethod: AnsiString;
153 tony 263 constructor Create(api: TFBClientAPI; DatabaseName: AnsiString; DPB: IDPB;
154 tony 45 RaiseExceptionOnConnectError: boolean);
155     procedure CheckHandle; virtual; abstract;
156 tony 56 function GenerateCreateDatabaseSQL(DatabaseName: AnsiString; aDPB: IDPB): AnsiString;
157 tony 117 procedure GetODSAndConnectionInfo;
158 tony 143 function GetDBInfo(ReqBuffer: PByte; ReqBufLen: integer): IDBInformation; virtual; abstract;
159 tony 117 function IsConnected: boolean; virtual; abstract;
160 tony 45 procedure EndAllTransactions;
161 tony 117 procedure DPBFromCreateSQL(CreateSQL: AnsiString);
162 tony 45 procedure SetParameters(SQLParams: ISQLParams; params: array of const);
163 tony 315 procedure UseServerICUChanged; virtual;
164 tony 45 public
165     destructor Destroy; override;
166 tony 263 function getFirebirdAPI: IFirebirdAPI;
167 tony 45 function getDPB: IDPB;
168     function AllocateBPB: IBPB;
169 tony 143 function AllocateDIRB: IDIRB;
170 tony 363 function StartTransaction(TPB: array of byte;
171     DefaultCompletion: TTransactionCompletion;
172     aName: AnsiString=''): ITransaction; overload; virtual; abstract;
173     function StartTransaction(TPB: ITPB; DefaultCompletion: TTransactionCompletion;
174     aName: AnsiString=''): ITransaction; overload; virtual; abstract;
175 tony 56 procedure ExecImmediate(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer); overload; virtual; abstract;
176     procedure ExecImmediate(TPB: array of byte; sql: AnsiString; aSQLDialect: integer); overload;
177     procedure ExecImmediate(transaction: ITransaction; sql: AnsiString); overload;
178     procedure ExecImmediate(TPB: array of byte; sql: AnsiString); overload;
179     function ExecuteSQL(TPB: array of byte; sql: AnsiString; SQLDialect: integer; params: array of const): IResults; overload;
180     function ExecuteSQL(transaction: ITransaction; sql: AnsiString; SQLDialect: integer; params: array of const): IResults; overload;
181     function ExecuteSQL(TPB: array of byte; sql: AnsiString; params: array of const): IResults; overload;
182     function ExecuteSQL(transaction: ITransaction; sql: AnsiString; params: array of const): IResults; overload;
183     function OpenCursor(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
184 tony 350 Scrollable: boolean=false): IResultSet; overload;
185     function OpenCursor(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
186 tony 45 params: array of const): IResultSet; overload;
187 tony 350 function OpenCursor(transaction: ITransaction; sql: AnsiString; Scrollable: boolean=false): IResultSet; overload;
188 tony 56 function OpenCursor(transaction: ITransaction; sql: AnsiString;
189 tony 45 params: array of const): IResultSet; overload;
190 tony 350 function OpenCursor(transaction: ITransaction; sql: AnsiString; Scrollable: boolean;
191     params: array of const): IResultSet; overload;
192     function OpenCursor(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer; Scrollable: boolean;
193     params: array of const): IResultSet; overload;
194 tony 56 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
195 tony 350 Scrollable: boolean=false): IResultSet; overload;
196     function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
197 tony 45 params: array of const): IResultSet; overload;
198 tony 350 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer; Scrollable: boolean;
199     params: array of const): IResultSet; overload;
200     function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString; Scrollable: boolean=false): IResultSet; overload;
201 tony 56 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString;
202 tony 45 params: array of const): IResultSet; overload;
203 tony 350 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString; Scrollable: boolean;
204     params: array of const): IResultSet; overload;
205     function OpenCursorAtStart(sql: AnsiString;Scrollable: boolean=false): IResultSet; overload;
206     function OpenCursorAtStart(sql: AnsiString; Scrollable: boolean;
207     params: array of const): IResultSet; overload;
208 tony 56 function OpenCursorAtStart(sql: AnsiString;
209 tony 45 params: array of const): IResultSet; overload;
210 tony 350 function Prepare(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer; CursorName: AnsiString=''): IStatement; overload; virtual; abstract;
211     function Prepare(transaction: ITransaction; sql: AnsiString; CursorName: AnsiString=''): IStatement; overload;
212 tony 56 function PrepareWithNamedParameters(transaction: ITransaction; sql: AnsiString;
213 tony 270 aSQLDialect: integer; GenerateParamNames: boolean=false;
214 tony 350 CaseSensitiveParams: boolean = false; CursorName: AnsiString=''): IStatement; overload; virtual; abstract;
215 tony 56 function PrepareWithNamedParameters(transaction: ITransaction; sql: AnsiString;
216 tony 270 GenerateParamNames: boolean=false;
217 tony 350 CaseSensitiveParams: boolean = false; CursorName: AnsiString=''): IStatement; overload;
218 tony 45 function GetEventHandler(Events: TStrings): IEvents; overload; virtual; abstract;
219 tony 56 function GetEventHandler(Event: AnsiString): IEvents; overload;
220 tony 45
221     function GetSQLDialect: integer;
222 tony 371 function GetAttachmentID: integer;
223 tony 291 function CreateBlob(transaction: ITransaction; RelationName, ColumnName: AnsiString; BPB: IBPB=nil): IBlob; overload;
224     function CreateBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BPB: IBPB=nil): IBlob; overload; virtual; abstract;
225 tony 56 function OpenBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB=nil): IBlob; overload; virtual; abstract;
226 tony 291 function OpenBlob(transaction: ITransaction; RelationName, ColumnName: AnsiString; BlobID: TISC_QUAD; BPB: IBPB=nil): IBlob; overload;
227 tony 45 function OpenBlob(transaction: ITransaction; Field: ISQLData; BPB: IBPB=nil): IBlob; overload;
228 tony 291 function CreateArray(transaction: ITransaction; RelationName, ColumnName: AnsiString
229     ): IArray; overload;
230     function CreateArray(transaction: ITransaction; ArrayMetaData: IArrayMetaData): IArray; overload; virtual; abstract;
231     function OpenArray(transaction: ITransaction; RelationName, ColumnName: AnsiString; ArrayID: TISC_QUAD): IArray; overload;
232     function OpenArray(transaction: ITransaction; ArrayMetaData: IArrayMetaData; ArrayID: TISC_QUAD): IArray; overload; virtual; abstract;
233 tony 45 property SQLDialect: integer read FSQLDialect;
234     property DPB: IDPB read FDPB;
235 tony 315 public
236     function GetDBInformation(Requests: array of byte): IDBInformation; overload;
237     function GetDBInformation(Request: byte): IDBInformation; overload;
238     function GetDBInformation(Requests: IDIRB): IDBInformation; overload;
239     function GetConnectString: AnsiString;
240     function GetRemoteProtocol: AnsiString;
241     function GetAuthenticationMethod: AnsiString;
242     function GetSecurityDatabase: AnsiString;
243     function GetODSMajorVersion: integer;
244     function GetODSMinorVersion: integer;
245 tony 371 function GetCharSetID: integer;
246 tony 315 function HasDecFloatSupport: boolean; virtual;
247 tony 345 function GetInlineBlobLimit: integer;
248     procedure SetInlineBlobLimit(limit: integer);
249     function HasBatchMode: boolean; virtual;
250 tony 363 function HasTable(aTableName: AnsiString): boolean;
251 tony 371 function HasFunction(aFunctionName: AnsiString): boolean;
252     function HasProcedure(aProcName: AnsiString): boolean;
253 tony 315
254     public
255     {Character Sets}
256     function HasDefaultCharSet: boolean;
257     function GetDefaultCharSetID: integer;
258     function GetCharsetName(CharSetID: integer): AnsiString;
259     function CharSetID2CodePage(CharSetID: integer; var CodePage: TSystemCodePage): boolean;
260     function CodePage2CharSetID(CodePage: TSystemCodePage; var CharSetID: integer): boolean;
261     function CharSetName2CharSetID(CharSetName: AnsiString; var CharSetID: integer): boolean;
262     function CharSetWidth(CharSetID: integer; var Width: integer): boolean;
263     procedure RegisterCharSet(CharSetName: AnsiString; CodePage: TSystemCodePage;
264     AllowReverseLookup:boolean; out CharSetID: integer);
265     function GetBlobMetaData(Transaction: ITransaction; tableName, columnName: AnsiString): IBlobMetaData; virtual; abstract;
266     function GetArrayMetaData(Transaction: ITransaction; tableName, columnName: AnsiString): IArrayMetaData; virtual; abstract;
267     property CharSetID: integer read FCharSetID;
268     property CodePage: TSystemCodePage read FCodePage;
269    
270     public
271     {Time Zone Support}
272     function GetTimeZoneServices: ITimeZoneServices; virtual;
273     function HasTimeZoneSupport: boolean; virtual;
274    
275 tony 45 end;
276    
277 tony 315 { TDPBItem }
278    
279     TDPBItem = class(TParamBlockItem,IDPBItem)
280     public
281     function getParamTypeName: AnsiString; override;
282     end;
283    
284     { TDPB }
285    
286     TDPB = class (TCustomParamBlock<TDPBItem,IDPBItem>, IDPB)
287     protected
288     function LookupItemType(ParamTypeName: AnsiString): byte; override;
289     public
290     constructor Create(api: TFBClientAPI);
291 tony 345 function GetParamTypeName(ParamType: byte): Ansistring;
292     {$IFDEF FPC}
293     function IDPB.GetDPBParamTypeName = GetParamTypeName;
294     {$ELSE}
295 tony 315 function GetDPBParamTypeName(ParamType: byte): Ansistring;
296 tony 345 {$ENDIF}
297 tony 315 end;
298    
299 tony 45 implementation
300    
301 tony 363 uses FBMessages, IBErrorCodes, FBTransaction {$IFDEF HASREQEX}, RegExpr{$ENDIF};
302 tony 45
303 tony 60 const
304 tony 363 {Journaling}
305     sJournalTableName = 'IBX$JOURNALS';
306     sSequenceName = 'IBX$SESSIONS';
307    
308     sqlCreateJournalTable =
309     'Create Table ' + sJournalTableName + '(' +
310     ' IBX$SessionID Integer not null, '+
311     ' IBX$TransactionID Integer not null, '+
312     ' IBX$OldTransactionID Integer, '+
313     ' IBX$USER VarChar(32) Default CURRENT_USER, '+
314     ' IBX$CREATED TIMESTAMP Default CURRENT_TIMESTAMP, '+
315     ' Primary Key(IBX$SessionID,IBX$TransactionID)' +
316     ')';
317    
318     sqlCreateSequence = 'CREATE SEQUENCE ' + sSequenceName;
319    
320     sqlGetNextSessionID = 'Select Gen_ID(' + sSequenceName + ',1) as SessionID From RDB$DATABASE';
321    
322     sqlRecordJournalEntry = 'Insert into ' + sJournalTableName + '(IBX$SessionID,IBX$TransactionID,IBX$OldTransactionID) '+
323     'Values(?,?,?)';
324    
325     sqlCleanUpSession = 'Delete From ' + sJournalTableName + ' Where IBX$SessionID = ?';
326    
327     const
328 tony 60 CharSetMap: array [0..69] of TCharsetMap = (
329     (CharsetID: 0; CharSetName: 'NONE'; CharSetWidth: 1; CodePage: CP_ACP; AllowReverseLookup: true),
330     (CharsetID: 1; CharSetName: 'OCTETS'; CharSetWidth: 1; CodePage: CP_NONE; AllowReverseLookup: true),
331     (CharsetID: 2; CharSetName: 'ASCII'; CharSetWidth: 1; CodePage: CP_ASCII; AllowReverseLookup: true),
332     (CharsetID: 3; CharSetName: 'UNICODE_FSS'; CharSetWidth: 3; CodePage: CP_UTF8; AllowReverseLookup: false),
333     (CharsetID: 4; CharSetName: 'UTF8'; CharSetWidth: 4; CodePage: CP_UTF8; AllowReverseLookup: true),
334     (CharsetID: 5; CharSetName: 'SJIS_0208'; CharSetWidth: 2; CodePage: 20932; AllowReverseLookup: true),
335     (CharsetID: 6; CharSetName: 'EUCJ_0208'; CharSetWidth: 2; CodePage: 20932; AllowReverseLookup: true),
336     (CharsetID: 7; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: true),
337     (CharsetID: 8; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: true),
338     (CharsetID: 9; CharSetName: 'DOS737'; CharSetWidth: 1; CodePage: 737; AllowReverseLookup: true),
339     (CharsetID: 10; CharSetName: 'DOS437'; CharSetWidth: 1; CodePage: 437; AllowReverseLookup: true),
340     (CharsetID: 11; CharSetName: 'DOS850'; CharSetWidth: 1; CodePage: 850; AllowReverseLookup: true),
341     (CharsetID: 12; CharSetName: 'DOS865'; CharSetWidth: 1; CodePage: 865; AllowReverseLookup: true),
342     (CharsetID: 13; CharSetName: 'DOS860'; CharSetWidth: 1; CodePage: 860; AllowReverseLookup: true),
343     (CharsetID: 14; CharSetName: 'DOS863'; CharSetWidth: 1; CodePage: 863; AllowReverseLookup: true),
344     (CharsetID: 15; CharSetName: 'DOS775'; CharSetWidth: 1; CodePage: 775; AllowReverseLookup: true),
345     (CharsetID: 16; CharSetName: 'DOS858'; CharSetWidth: 1; CodePage: 858; AllowReverseLookup: true),
346     (CharsetID: 17; CharSetName: 'DOS862'; CharSetWidth: 1; CodePage: 862; AllowReverseLookup: true),
347     (CharsetID: 18; CharSetName: 'DOS864'; CharSetWidth: 1; CodePage: 864; AllowReverseLookup: true),
348     (CharsetID: 19; CharSetName: 'NEXT'; CharSetWidth: 1; CodePage: CP_NONE; AllowReverseLookup: true),
349     (CharsetID: 20; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: true),
350     (CharsetID: 21; CharSetName: 'ISO8859_1'; CharSetWidth: 1; CodePage: 28591; AllowReverseLookup: true),
351     (CharsetID: 22; CharSetName: 'ISO8859_2'; CharSetWidth: 1; CodePage: 28592; AllowReverseLookup: true),
352     (CharsetID: 23; CharSetName: 'ISO8859_3'; CharSetWidth: 1; CodePage: 28593; AllowReverseLookup: true),
353     (CharsetID: 24; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
354     (CharsetID: 25; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
355     (CharsetID: 26; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
356     (CharsetID: 27; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
357     (CharsetID: 28; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
358     (CharsetID: 29; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
359     (CharsetID: 30; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
360     (CharsetID: 31; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
361     (CharsetID: 32; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
362     (CharsetID: 33; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
363     (CharsetID: 34; CharSetName: 'ISO8859_4'; CharSetWidth: 1; CodePage: 28594; AllowReverseLookup: true),
364     (CharsetID: 35; CharSetName: 'ISO8859_5'; CharSetWidth: 1; CodePage: 28595; AllowReverseLookup: true),
365     (CharsetID: 36; CharSetName: 'ISO8859_6'; CharSetWidth: 1; CodePage: 28596; AllowReverseLookup: true),
366     (CharsetID: 37; CharSetName: 'ISO8859_7'; CharSetWidth: 1; CodePage: 28597; AllowReverseLookup: true),
367     (CharsetID: 38; CharSetName: 'ISO8859_8'; CharSetWidth: 1; CodePage: 28598; AllowReverseLookup: true),
368     (CharsetID: 39; CharSetName: 'ISO8859_9'; CharSetWidth: 1; CodePage: 28599; AllowReverseLookup: true),
369     (CharsetID: 40; CharSetName: 'ISO8859_13'; CharSetWidth: 1; CodePage: 28603; AllowReverseLookup: true),
370     (CharsetID: 41; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
371     (CharsetID: 42; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
372     (CharsetID: 43; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
373     (CharsetID: 44; CharSetName: 'KSC_5601'; CharSetWidth: 2; CodePage: 949; AllowReverseLookup: true),
374     (CharsetID: 45; CharSetName: 'DOS852'; CharSetWidth: 1; CodePage: 852; AllowReverseLookup: true),
375     (CharsetID: 46; CharSetName: 'DOS857'; CharSetWidth: 1; CodePage: 857; AllowReverseLookup: true),
376     (CharsetID: 47; CharSetName: 'DOS861'; CharSetWidth: 1; CodePage: 861; AllowReverseLookup: true),
377     (CharsetID: 48; CharSetName: 'DOS866'; CharSetWidth: 1; CodePage: 866; AllowReverseLookup: true),
378     (CharsetID: 49; CharSetName: 'DOS869'; CharSetWidth: 1; CodePage: 869; AllowReverseLookup: true),
379     (CharsetID: 50; CharSetName: 'CYRL'; CharSetWidth: 1; CodePage: 1251; AllowReverseLookup: true),
380     (CharsetID: 51; CharSetName: 'WIN1250'; CharSetWidth: 1; CodePage: 1250; AllowReverseLookup: true),
381     (CharsetID: 52; CharSetName: 'WIN1251'; CharSetWidth: 1; CodePage: 1251; AllowReverseLookup: true),
382     (CharsetID: 53; CharSetName: 'WIN1252'; CharSetWidth: 1; CodePage: 1252; AllowReverseLookup: true),
383     (CharsetID: 54; CharSetName: 'WIN1253'; CharSetWidth: 1; CodePage: 1253; AllowReverseLookup: true),
384     (CharsetID: 55; CharSetName: 'WIN1254'; CharSetWidth: 1; CodePage: 1254; AllowReverseLookup: true),
385     (CharsetID: 56; CharSetName: 'BIG_5'; CharSetWidth: 2; CodePage: 950; AllowReverseLookup: true),
386     (CharsetID: 57; CharSetName: 'GB_2312'; CharSetWidth: 2; CodePage: 936; AllowReverseLookup: true),
387     (CharsetID: 58; CharSetName: 'WIN1255'; CharSetWidth: 1; CodePage: 1255; AllowReverseLookup: true),
388     (CharsetID: 59; CharSetName: 'WIN1256'; CharSetWidth: 1; CodePage: 1256; AllowReverseLookup: true),
389     (CharsetID: 60; CharSetName: 'WIN1257'; CharSetWidth: 1; CodePage: 1257; AllowReverseLookup: true),
390     (CharsetID: 61; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
391     (CharsetID: 62; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
392     (CharsetID: 63; CharSetName: 'KOI8R'; CharSetWidth: 1; CodePage: 20866; AllowReverseLookup: true),
393     (CharsetID: 64; CharSetName: 'KOI8U'; CharSetWidth: 1; CodePage: 21866; AllowReverseLookup: true),
394     (CharsetID: 65; CharSetName: 'WIN1258'; CharSetWidth: 1; CodePage: 1258; AllowReverseLookup: true),
395     (CharsetID: 66; CharSetName: 'TIS620'; CharSetWidth: 1; CodePage: 874; AllowReverseLookup: true),
396     (CharsetID: 67; CharSetName: 'GBK'; CharSetWidth: 2; CodePage: 936; AllowReverseLookup: true),
397     (CharsetID: 68; CharSetName: 'CP943C'; CharSetWidth: 2; CodePage: 943; AllowReverseLookup: true),
398     (CharsetID: 69; CharSetName: 'GB18030'; CharSetWidth: 4; CodePage: 54936; AllowReverseLookup: true)
399     );
400    
401 tony 315 const
402     isc_dpb_last_dpb_constant = isc_dpb_decfloat_traps;
403 tony 60
404 tony 315 DPBConstantNames: array[1..isc_dpb_last_dpb_constant] of string = (
405     'cdd_pathname',
406     'allocation',
407     'journal',
408     'page_size',
409     'num_buffers',
410     'buffer_length',
411     'debug',
412     'garbage_collect',
413     'verify',
414     'sweep',
415     'enable_journal',
416     'disable_journal',
417     'dbkey_scope',
418     'number_of_users',
419     'trace',
420     'no_garbage_collect',
421     'damaged',
422     'license',
423     'sys_user_name',
424     'encrypt_key',
425     'activate_shadow',
426     'sweep_interval',
427     'delete_shadow',
428     'force_write',
429     'begin_log',
430     'quit_log',
431     'no_reserve',
432     'user_name',
433     'password',
434     'password_enc',
435     'sys_user_name_enc',
436     'interp',
437     'online_dump',
438     'old_file_size',
439     'old_num_files',
440     'old_file',
441     'old_start_page',
442     'old_start_seqno',
443     'old_start_file',
444     'drop_walfile',
445     'old_dump_id',
446     'wal_backup_dir',
447     'wal_chkptlen',
448     'wal_numbufs',
449     'wal_bufsize',
450     'wal_grp_cmt_wait',
451     'lc_messages',
452     'lc_ctype',
453     'cache_manager',
454     'shutdown',
455     'online',
456     'shutdown_delay',
457     'reserved',
458     'overwrite',
459     'sec_attach',
460     'disable_wal',
461     'connect_timeout',
462     'dummy_packet_interval',
463     'gbak_attach',
464     'sql_role_name',
465     'set_page_buffers',
466     'working_directory',
467     'sql_dialect',
468     'set_db_readonly',
469     'set_db_sql_dialect',
470     'gfix_attach',
471     'gstat_attach',
472     'set_db_charset',
473     'gsec_attach',
474     'address_path' ,
475     'process_id',
476     'no_db_triggers',
477     'trusted_auth',
478     'process_name',
479     'trusted_role',
480     'org_filename',
481     'utf8_ilename',
482     'ext_call_depth',
483     'auth_block',
484     'client_version',
485     'remote_protocol',
486     'host_name',
487     'os_user',
488     'specific_auth_data',
489     'auth_plugin_list',
490     'auth_plugin_name',
491     'config',
492     'nolinger',
493     'reset_icu',
494     'map_attach',
495     'session_time_zone',
496     'set_db_replica',
497     'set_bind',
498     'decfloat_round',
499     'decfloat_traps'
500     );
501 tony 60
502 tony 363 type
503 tony 60
504 tony 363 { TQueryProcessor }
505 tony 315
506 tony 363 TQueryProcessor=class(TSQLTokeniser)
507     private
508     FInString: AnsiString;
509     FIndex: integer;
510     FStmt: IStatement;
511     function DoExecute: AnsiString;
512     function GetParamValue(ParamIndex: integer): AnsiString;
513     protected
514     function GetChar: AnsiChar; override;
515     public
516     class function Execute(Stmt: IStatement): AnsiString;
517     end;
518    
519     { TQueryProcessor }
520    
521     function TQueryProcessor.DoExecute: AnsiString;
522     var token: TSQLTokens;
523     ParamIndex: integer;
524     begin
525     Result := '';
526     ParamIndex := 0;
527    
528     while not EOF do
529     begin
530     token := GetNextToken;
531     case token of
532     sqltPlaceHolder:
533     begin
534     Result := Result + GetParamValue(ParamIndex);
535     Inc(ParamIndex);
536     end;
537     else
538     Result := Result + TokenText;
539     end;
540     end;
541     end;
542    
543     function TQueryProcessor.GetParamValue(ParamIndex: integer): AnsiString;
544     begin
545     with FStmt.SQLParams[ParamIndex] do
546     begin
547     if IsNull then
548     Result := 'NULL'
549     else
550     case GetSQLType of
551     SQL_BLOB:
552     if getSubType = 1 then {string}
553     Result := '''' + SQLSafeString(GetAsString) + ''''
554     else
555     Result := TSQLXMLReader.FormatBlob(GetAsString,getSubType);
556    
557     SQL_ARRAY:
558     Result := TSQLXMLReader.FormatArray(getAsArray);
559    
560     SQL_VARYING,
561     SQL_TEXT,
562     SQL_TIMESTAMP,
563     SQL_TYPE_DATE,
564     SQL_TYPE_TIME,
565     SQL_TIMESTAMP_TZ_EX,
566     SQL_TIME_TZ_EX,
567     SQL_TIMESTAMP_TZ,
568     SQL_TIME_TZ:
569     Result := '''' + SQLSafeString(GetAsString) + '''';
570     else
571     Result := GetAsString;
572     end;
573     end;
574     end;
575    
576     function TQueryProcessor.GetChar: AnsiChar;
577     begin
578     if FIndex <= Length(FInString) then
579     begin
580     Result := FInString[FIndex];
581     Inc(FIndex);
582     end
583     else
584     Result := #0;
585     end;
586    
587     class function TQueryProcessor.Execute(Stmt: IStatement): AnsiString;
588     begin
589     if not Stmt.IsPrepared then
590     IBError(ibxeSQLClosed,[]);
591     with self.Create do
592     try
593     FStmt := Stmt;
594     FInString := Stmt.GetProcessedSQLText;
595     FIndex := 1;
596     Result := Trim(DoExecute);
597     finally
598     Free;
599     end;
600     end;
601    
602     { TFBJournaling }
603    
604     function TFBJournaling.GetDateTimeFmt: AnsiString;
605     begin
606     {$IF declared(DefaultFormatSettings)}
607     with DefaultFormatSettings do
608     {$ELSE}
609     {$IF declared(FormatSettings)}
610     with FormatSettings do
611     {$IFEND}
612     {$IFEND}
613     Result := ShortDateFormat + ' ' + LongTimeFormat + '.zzzz'
614     end;
615    
616     procedure TFBJournaling.EndSession(RetainJournal: boolean);
617     begin
618 tony 371 if JournalingActive and (FJournalFilePath <> '') then
619 tony 363 begin
620     FreeAndNil(FJournalFileStream);
621 tony 371 if not (joNoServerTable in FOptions) and not RetainJournal then
622 tony 363 try
623     GetAttachment.ExecuteSQL([isc_tpb_write,isc_tpb_wait,isc_tpb_consistency],
624     sqlCleanUpSession,[FSessionID]);
625     sysutils.DeleteFile(FJournalFilePath);
626     except On E: EIBInterBaseError do
627     if E.IBErrorCode <> isc_lost_db_connection then
628     raise;
629     {ignore - do not delete journal if database gone away}
630     end;
631     FSessionID := -1;
632     end;
633     end;
634    
635     procedure TFBJournaling.Disconnect(Force: boolean);
636     begin
637     if JournalingActive then
638     EndSession(Force);
639     end;
640    
641     procedure TFBJournaling.TransactionStart(Tr: ITransaction);
642     var LogEntry: AnsiString;
643     TPBText: AnsiString;
644     begin
645     FDoNotJournal := true;
646 tony 371 if not (joNoServerTable in FOptions) then
647 tony 363 try
648     GetAttachment.ExecuteSQL(Tr,sqlRecordJournalEntry,[FSessionID,Tr.GetTransactionID,NULL]);
649     finally
650     FDoNotJournal := false;
651     end;
652     TPBText := Tr.getTPB.AsText;
653     LogEntry := Format(sTransStartJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
654 tony 371 GetAttachment.GetAttachmentID,
655 tony 363 FSessionID,
656     Tr.GetTransactionID,
657     Length(Tr.TransactionName),
658     Tr.TransactionName,
659     Length(TPBText),TPBText,
660     ord(tr.GetDefaultCompletion)]);
661     if assigned(FJournalFileStream) then
662     FJournalFileStream.Write(LogEntry[1],Length(LogEntry));
663     end;
664    
665     function TFBJournaling.TransactionEnd(TransactionID: integer;
666     Action: TTransactionAction): boolean;
667    
668     var LogEntry: AnsiString;
669     begin
670     Result := false;
671     case Action of
672     TARollback:
673     begin
674 tony 371 LogEntry := Format(sTransRollbackJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
675     GetAttachment.GetAttachmentID,
676     FSessionID,TransactionID]);
677 tony 363 Result := true;
678     end;
679     TACommit:
680     begin
681 tony 371 LogEntry := Format(sTransCommitJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
682     GetAttachment.GetAttachmentID,
683     FSessionID,TransactionID]);
684 tony 363 Result := true;
685     end;
686     end;
687     if assigned(FJournalFileStream) then
688     FJournalFileStream.Write(LogEntry[1],Length(LogEntry));
689     end;
690    
691     procedure TFBJournaling.TransactionRetained(Tr: ITransaction;
692     OldTransactionID: integer; Action: TTransactionAction);
693     var LogEntry: AnsiString;
694     begin
695     case Action of
696     TACommitRetaining:
697     LogEntry := Format(sTransCommitRetJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
698 tony 371 GetAttachment.GetAttachmentID,
699 tony 363 FSessionID,Tr.GetTransactionID,OldTransactionID]);
700     TARollbackRetaining:
701     LogEntry := Format(sTransRollbackRetJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
702 tony 371 GetAttachment.GetAttachmentID,
703 tony 363 FSessionID,Tr.GetTransactionID,OldTransactionID]);
704     end;
705     if assigned(FJournalFileStream) then
706     FJournalFileStream.Write(LogEntry[1],Length(LogEntry));
707    
708     FDoNotJournal := true;
709 tony 371 if not (joNoServerTable in FOptions) then
710 tony 363 try
711     GetAttachment.ExecuteSQL(Tr,sqlRecordJournalEntry,[FSessionID,Tr.GetTransactionID,OldTransactionID]);
712     finally
713     FDoNotJournal := false;
714     end;
715     end;
716    
717     procedure TFBJournaling.ExecQuery(Stmt: IStatement);
718     var SQL: AnsiString;
719     LogEntry: AnsiString;
720     begin
721     SQL := TQueryProcessor.Execute(Stmt);
722     LogEntry := Format(sQueryJournal,[FBFormatDateTime(GetDateTimeFmt,Now),
723 tony 371 GetAttachment.GetAttachmentID,
724 tony 363 FSessionID,
725     Stmt.GetTransaction.GetTransactionID,
726     Length(SQL),SQL]);
727     if assigned(FJournalFileStream) then
728     FJournalFileStream.Write(LogEntry[1],Length(LogEntry));
729     end;
730    
731     function TFBJournaling.JournalingActive: boolean;
732     begin
733     Result := (FJournalFileStream <> nil) and not FDoNotJournal;
734     end;
735    
736     function TFBJournaling.GetJournalOptions: TJournalOptions;
737     begin
738     Result := FOptions;
739     end;
740    
741     function TFBJournaling.StartJournaling(aJournalLogFile: AnsiString): integer;
742     begin
743     Result := StartJournaling(aJournalLogFile,[joReadWriteTransactions,joModifyQueries]);
744     end;
745    
746     function TFBJournaling.StartJournaling(aJournalLogFile: AnsiString;
747     Options: TJournalOptions): integer;
748     begin
749 tony 371 try
750     StartJournaling(TFileStream.Create(aJournalLogFile,fmCreate),Options);
751     finally
752     FJournalFilePath := aJournalLogFile;
753     end;
754     end;
755    
756     function TFBJournaling.StartJournaling(S: TStream; Options: TJournalOptions
757     ): integer;
758     begin
759 tony 363 FOptions := Options;
760 tony 371 if not (joNoServerTable in FOptions) then
761 tony 363 with GetAttachment do
762     begin
763 tony 371 if not HasTable(sJournalTableName) then
764 tony 363 begin
765     ExecImmediate([isc_tpb_write,isc_tpb_wait,isc_tpb_consistency],sqlCreateJournalTable);
766     ExecImmediate([isc_tpb_write,isc_tpb_wait,isc_tpb_consistency],sqlCreateSequence);
767     end;
768     FSessionID := OpenCursorAtStart(sqlGetNextSessionID)[0].AsInteger;
769     end;
770 tony 371 FJournalFileStream := S;
771 tony 363 Result := FSessionID;
772     end;
773    
774     procedure TFBJournaling.StopJournaling(RetainJournal: boolean);
775     begin
776     EndSession(RetainJournal);
777     end;
778    
779    
780    
781    
782 tony 45 { TFBAttachment }
783    
784 tony 117 procedure TFBAttachment.GetODSAndConnectionInfo;
785     var DBInfo: IDBInformation;
786     i: integer;
787     Stmt: IStatement;
788     ResultSet: IResultSet;
789     Param: IDPBItem;
790     begin
791     if not IsConnected then Exit;
792     DBInfo := GetDBInformation([isc_info_db_id,isc_info_ods_version,isc_info_ods_minor_version,
793 tony 371 isc_info_db_SQL_Dialect, isc_info_attachment_id]);
794 tony 117 for i := 0 to DBInfo.GetCount - 1 do
795     with DBInfo[i] do
796     case getItemType of
797     isc_info_ods_minor_version:
798     FODSMinorVersion := getAsInteger;
799     isc_info_ods_version:
800     FODSMajorVersion := getAsInteger;
801     isc_info_db_SQL_Dialect:
802     FSQLDialect := getAsInteger;
803 tony 371 isc_info_attachment_id:
804     FAttachmentID := getAsInteger;
805 tony 117 end;
806    
807 tony 143 FCharSetID := 0;
808     FRemoteProtocol := '';
809     FAuthMethod := 'Legacy_Auth';
810 tony 209 FSecDatabase := 'Default';
811 tony 143 if FODSMajorVersion > 11 then
812 tony 117 begin
813     Stmt := Prepare(StartTransaction([isc_tpb_read,isc_tpb_nowait,isc_tpb_concurrency],taCommit),
814 tony 209 'Select MON$CHARACTER_SET_ID, MON$REMOTE_PROTOCOL, MON$AUTH_METHOD, MON$SEC_DATABASE From MON$ATTACHMENTS, MON$DATABASE '+
815 tony 315 'Where MON$ATTACHMENT_ID = CURRENT_CONNECTION ');
816 tony 143 ResultSet := Stmt.OpenCursor;
817     if ResultSet.FetchNext then
818     begin
819     FCharSetID := ResultSet[0].AsInteger;
820 tony 209 FRemoteProtocol := Trim(ResultSet[1].AsString);
821     FAuthMethod := Trim(ResultSet[2].AsString);
822     FSecDatabase := Trim(ResultSet[3].AsString);
823 tony 143 end
824     end
825     else
826     if (FODSMajorVersion = 11) and (FODSMinorVersion >= 1) then
827     begin
828     Stmt := Prepare(StartTransaction([isc_tpb_read,isc_tpb_nowait,isc_tpb_concurrency],taCommit),
829 tony 117 'Select MON$CHARACTER_SET_ID, MON$REMOTE_PROTOCOL From MON$ATTACHMENTS '+
830     'Where MON$ATTACHMENT_ID = CURRENT_CONNECTION');
831     ResultSet := Stmt.OpenCursor;
832     if ResultSet.FetchNext then
833     begin
834     FCharSetID := ResultSet[0].AsInteger;
835 tony 209 FRemoteProtocol := Trim(ResultSet[1].AsString);
836 tony 117 end
837     end
838     else
839     if DPB <> nil then
840     begin
841     Param := DPB.Find(isc_dpb_lc_ctype);
842     if (Param = nil) or not CharSetName2CharSetID(Param.AsString,FCharSetID) then
843     FCharSetID := 0;
844 tony 143 case GetProtocol(FDatabaseName) of
845     TCP: FRemoteProtocol := 'TCPv4';
846     Local: FRemoteProtocol := '';
847     NamedPipe: FRemoteProtocol := 'Netbui';
848     SPX: FRemoteProtocol := 'SPX'
849     end;
850 tony 117 end;
851     FHasDefaultCharSet := CharSetID2CodePage(FCharSetID,FCodePage) and (FCharSetID > 1);
852     end;
853    
854 tony 263 constructor TFBAttachment.Create(api: TFBClientAPI; DatabaseName: AnsiString;
855     DPB: IDPB; RaiseExceptionOnConnectError: boolean);
856 tony 45 begin
857     inherited Create;
858 tony 263 FFirebirdAPI := api.GetAPI; {Keep reference to interface}
859 tony 45 FSQLDialect := 3;
860     FDatabaseName := DatabaseName;
861 tony 60 SetLength(FUserCharSetMap,0);
862 tony 117 FODSMajorVersion := 0;
863     FODSMinorVersion := 0;
864 tony 345 FInlineBlobLimit := DefaultMaxInlineBlobLimit;
865 tony 371 FDPB := DPB;
866     FRaiseExceptionOnConnectError := RaiseExceptionOnConnectError;
867 tony 45 end;
868    
869 tony 56 function TFBAttachment.GenerateCreateDatabaseSQL(DatabaseName: AnsiString; aDPB: IDPB): AnsiString;
870     var CreateParams: AnsiString;
871 tony 45 DPBItem: IDPBItem;
872     begin
873     CreateParams := '';
874    
875     if aDPB <> nil then
876     begin
877     DPBItem := aDPB.Find(isc_dpb_user_name);
878     if DPBItem <> nil then
879 tony 56 CreateParams := CreateParams + ' USER ''' + DPBItem.AsString + '''';
880 tony 45
881     DPBItem := aDPB.Find(isc_dpb_password);
882     if DPBItem <> nil then
883 tony 56 CreateParams := CreateParams + ' Password ''' + DPBItem.AsString + '''';
884 tony 45
885     DPBItem := aDPB.Find(isc_dpb_page_size);
886     if DPBItem <> nil then
887 tony 56 CreateParams := CreateParams + ' PAGE_SIZE ' + DPBItem.AsString;
888 tony 45
889     DPBItem := aDPB.Find(isc_dpb_lc_ctype);
890     if DPBItem <> nil then
891 tony 56 CreateParams := CreateParams + ' DEFAULT CHARACTER SET ' + DPBItem.AsString;
892 tony 45
893     DPBItem := aDPB.Find(isc_dpb_sql_dialect);
894     if DPBItem <> nil then
895     FSQLDialect := DPBItem.AsInteger;
896     end;
897    
898     Result := 'CREATE DATABASE ''' + DatabaseName + ''' ' + CreateParams; {do not localize}
899     end;
900    
901     procedure TFBAttachment.EndAllTransactions;
902     var i: integer;
903     intf: TInterfacedObject;
904     begin
905     for i := 0 to InterfaceCount - 1 do
906     begin
907     intf := GetInterface(i);
908     if (intf <> nil) and (intf is TFBTransaction) then
909     TFBTransaction(intf).DoDefaultTransactionEnd(true);
910     end;
911     end;
912    
913 tony 118 {$IFDEF HASREQEX}
914 tony 117 procedure TFBAttachment.DPBFromCreateSQL(CreateSQL: AnsiString);
915     var RegexObj: TRegExpr;
916     begin
917     FDPB := FFirebirdAPI.AllocateDPB;
918     RegexObj := TRegExpr.Create;
919     try
920     {extact database file spec}
921     RegexObj.ModifierG := false; {turn off greedy matches}
922     RegexObj.ModifierI := true; {case insensitive match}
923     RegexObj.Expression := '^ *CREATE +(DATABASE|SCHEMA) +''.*'' +USER +''(.+)'' PASSWORD +''(.+)''';
924     if RegexObj.Exec(CreateSQL) then
925     begin
926     DPB.Add(isc_dpb_user_name).AsString := system.copy(CreateSQL,RegexObj.MatchPos[2],RegexObj.MatchLen[2]);
927     DPB.Add(isc_dpb_password).AsString := system.copy(CreateSQL,RegexObj.MatchPos[3],RegexObj.MatchLen[3]);
928     end
929     else
930     begin
931     RegexObj.Expression := '^ *CREATE +(DATABASE|SCHEMA) +(''.*'') +USER +''(.+)''';
932     if RegexObj.Exec(CreateSQL) then
933     DPB.Add(isc_dpb_user_name).AsString := system.copy(CreateSQL,RegexObj.MatchPos[2],RegexObj.MatchLen[2]);
934     end;
935     finally
936     RegexObj.Free;
937     end;
938     if FCharSetID > 0 then
939     DPB.Add(isc_dpb_lc_ctype).AsString := GetCharSetName(FCharSetID);
940     DPB.Add(isc_dpb_set_db_SQL_dialect).setAsByte(FSQLDialect);
941     end;
942 tony 118 {$ELSE}
943     procedure TFBAttachment.DPBFromCreateSQL(CreateSQL: AnsiString);
944 tony 119 begin
945     FDPB := FFirebirdAPI.AllocateDPB;
946     if FCharSetID > 0 then
947     DPB.Add(isc_dpb_lc_ctype).AsString := GetCharSetName(FCharSetID);
948     DPB.Add(isc_dpb_set_db_SQL_dialect).setAsByte(FSQLDialect);
949 tony 118 end;
950     {$ENDIF}
951 tony 117
952 tony 45 procedure TFBAttachment.SetParameters(SQLParams: ISQLParams;
953     params: array of const);
954     var i: integer;
955     begin
956     if SQLParams.Count <> Length(params) then
957     IBError(ibxeInvalidParamCount,[SQLParams.Count,Length(params)]);
958    
959     for i := 0 to High(params) do
960     begin
961     case params[i].vtype of
962     vtinteger :
963     SQLParams[i].AsInteger := params[i].vinteger;
964 tony 70 vtInt64:
965     SQLParams[i].AsInt64 := params[i].VInt64^;
966     {$IF declared (vtQWord)}
967     vtQWord:
968     SQLParams[i].AsInt64 := params[i].VQWord^;
969     {$IFEND}
970 tony 45 vtboolean :
971     SQLParams[i].AsBoolean := params[i].vboolean;
972     vtchar :
973     SQLParams[i].AsString := params[i].vchar;
974     vtextended :
975     SQLParams[i].AsDouble := params[i].VExtended^;
976     vtCurrency:
977     SQLParams[i].AsDouble := params[i].VCurrency^;
978     vtString :
979 tony 70 SQLParams[i].AsString := strpas(PChar(params[i].VString));
980 tony 45 vtPChar :
981     SQLParams[i].AsString := strpas(params[i].VPChar);
982     vtAnsiString :
983 tony 70 SQLParams[i].AsString := strpas(PAnsiChar(params[i].VAnsiString));
984 tony 45 vtVariant:
985     SQLParams[i].AsVariant := params[i].VVariant^;
986 tony 70 vtWideChar:
987     SQLParams[i].AsString := UTF8Encode(WideCharLenToString(@params[i].VWideChar,1));
988     vtPWideChar:
989     SQLParams[i].AsString := UTF8Encode(strpas(PWideChar(params[i].VPWideChar)));
990     vtWideString:
991     SQLParams[i].AsString := UTF8Encode(strpas(PWideChar(params[i].VWideString)));
992     vtUnicodeString:
993     SQLParams[i].AsString := UTF8Encode(strpas(PWideChar(params[i].VUnicodeString)));
994 tony 45 else
995     IBError(ibxeInvalidVariantType,[nil]);
996     end;
997     end;
998     end;
999    
1000 tony 315 procedure TFBAttachment.UseServerICUChanged;
1001     begin
1002     // Do nothing by default
1003     end;
1004    
1005 tony 45 destructor TFBAttachment.Destroy;
1006     begin
1007     Disconnect(true);
1008     inherited Destroy;
1009     end;
1010    
1011 tony 263 function TFBAttachment.getFirebirdAPI: IFirebirdAPI;
1012     begin
1013     Result := FFirebirdAPI;
1014     end;
1015    
1016 tony 45 function TFBAttachment.getDPB: IDPB;
1017     begin
1018     Result := FDPB;
1019     end;
1020    
1021     function TFBAttachment.AllocateBPB: IBPB;
1022     begin
1023 tony 263 Result := TBPB.Create(FFirebirdAPI as TFBClientAPI);
1024 tony 45 end;
1025    
1026 tony 143 function TFBAttachment.AllocateDIRB: IDIRB;
1027     begin
1028 tony 263 Result := TDIRB.Create(FFirebirdAPI as TFBClientAPI);
1029 tony 143 end;
1030    
1031 tony 56 procedure TFBAttachment.ExecImmediate(TPB: array of byte; sql: AnsiString;
1032 tony 45 aSQLDialect: integer);
1033     begin
1034     ExecImmediate(StartTransaction(TPB,taCommit),sql,aSQLDialect);
1035     end;
1036    
1037 tony 56 procedure TFBAttachment.ExecImmediate(transaction: ITransaction; sql: AnsiString);
1038 tony 45 begin
1039     ExecImmediate(transaction,sql,FSQLDialect);
1040     end;
1041    
1042 tony 56 procedure TFBAttachment.ExecImmediate(TPB: array of byte; sql: AnsiString);
1043 tony 45 begin
1044     ExecImmediate(StartTransaction(TPB,taCommit),sql,FSQLDialect);
1045     end;
1046    
1047 tony 56 function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
1048 tony 45 SQLDialect: integer; params: array of const): IResults;
1049     begin
1050 tony 117 Result := ExecuteSQL(StartTransaction(TPB,taCommit),sql,SQLDialect,params);
1051 tony 45 end;
1052    
1053 tony 56 function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
1054 tony 45 SQLDialect: integer; params: array of const): IResults;
1055     begin
1056     with Prepare(transaction,sql,SQLDialect) do
1057     begin
1058     SetParameters(SQLParams,params);
1059     Result := Execute;
1060     end;
1061     end;
1062    
1063 tony 56 function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
1064 tony 45 params: array of const): IResults;
1065     begin
1066     Result := ExecuteSQL(StartTransaction(TPB,taCommit),sql,params);
1067     end;
1068    
1069 tony 56 function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
1070 tony 45 params: array of const): IResults;
1071     begin
1072     with Prepare(transaction,sql,FSQLDialect) do
1073     begin
1074     SetParameters(SQLParams,params);
1075     Result := Execute;
1076     end;
1077     end;
1078    
1079 tony 56 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1080 tony 350 aSQLDialect: integer; Scrollable: boolean): IResultSet;
1081 tony 45 begin
1082 tony 350 Result := OpenCursor(transaction,sql,aSQLDialect,Scrollable,[]);
1083 tony 45 end;
1084    
1085 tony 56 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1086 tony 45 aSQLDialect: integer; params: array of const): IResultSet;
1087 tony 350
1088 tony 45 begin
1089 tony 350 Result := OpenCursor(transaction,sql,FSQLDialect,false,params);
1090 tony 45 end;
1091    
1092 tony 350 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1093     Scrollable: boolean): IResultSet;
1094 tony 45 begin
1095 tony 350 Result := OpenCursor(transaction,sql,FSQLDialect,Scrollable,[]);
1096 tony 45 end;
1097    
1098 tony 56 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1099 tony 45 params: array of const): IResultSet;
1100     begin
1101 tony 350 Result := OpenCursor(transaction,sql,FSQLDialect,false,params);
1102 tony 45 end;
1103    
1104 tony 350 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1105     Scrollable: boolean; params: array of const): IResultSet;
1106     begin
1107     Result := OpenCursor(transaction,sql,FSQLDialect,Scrollable,params);
1108     end;
1109    
1110     function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1111     aSQLDialect: integer; Scrollable: boolean;
1112     params: array of const): IResultSet;
1113     var Statement: IStatement;
1114     begin
1115     CheckHandle;
1116     Statement := Prepare(transaction,sql,aSQLDialect);
1117     SetParameters(Statement.SQLParams,params);
1118     Result := Statement.OpenCursor(Scrollable);
1119     end;
1120    
1121 tony 45 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1122 tony 350 sql: AnsiString; aSQLDialect: integer; Scrollable: boolean): IResultSet;
1123 tony 45 begin
1124 tony 350 Result := OpenCursor(transaction,sql,aSQLDialect,Scrollable,[]);
1125 tony 45 Result.FetchNext;
1126     end;
1127    
1128     function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1129 tony 56 sql: AnsiString; aSQLDialect: integer; params: array of const): IResultSet;
1130 tony 45 begin
1131     Result := OpenCursor(transaction,sql,aSQLDialect,params);
1132     Result.FetchNext;
1133     end;
1134    
1135 tony 350 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1136     sql: AnsiString; aSQLDialect: integer; Scrollable: boolean;
1137     params: array of const): IResultSet;
1138 tony 45 begin
1139 tony 350 Result := OpenCursor(transaction,sql,aSQLDialect,Scrollable,params);
1140     Result.FetchNext;
1141 tony 45 end;
1142    
1143     function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1144 tony 350 sql: AnsiString; Scrollable: boolean): IResultSet;
1145     begin
1146     Result := OpenCursorAtStart(transaction,sql,FSQLDialect,Scrollable,[]);
1147     end;
1148    
1149     function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1150 tony 56 sql: AnsiString; params: array of const): IResultSet;
1151 tony 45 begin
1152     Result := OpenCursorAtStart(transaction,sql,FSQLDialect,params);
1153     end;
1154    
1155 tony 350 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1156     sql: AnsiString; Scrollable: boolean; params: array of const): IResultSet;
1157 tony 45 begin
1158 tony 350 Result := OpenCursorAtStart(transaction,sql,FSQLDialect,Scrollable,params);
1159 tony 45 end;
1160    
1161 tony 350 function TFBAttachment.OpenCursorAtStart(sql: AnsiString; Scrollable: boolean
1162     ): IResultSet;
1163     begin
1164     Result := OpenCursorAtStart(sql,Scrollable,[]);
1165     end;
1166    
1167     function TFBAttachment.OpenCursorAtStart(sql: AnsiString; Scrollable: boolean;
1168     params: array of const): IResultSet;
1169     begin
1170     Result := OpenCursorAtStart(StartTransaction([isc_tpb_read,isc_tpb_wait,isc_tpb_concurrency],taCommit),sql,FSQLDialect,
1171     Scrollable,params);
1172     end;
1173    
1174 tony 56 function TFBAttachment.OpenCursorAtStart(sql: AnsiString;
1175 tony 45 params: array of const): IResultSet;
1176     begin
1177 tony 350 Result := OpenCursorAtStart(StartTransaction([isc_tpb_read,isc_tpb_wait,isc_tpb_concurrency],taCommit),sql,FSQLDialect,
1178     false,params);
1179 tony 45 end;
1180    
1181 tony 350 function TFBAttachment.Prepare(transaction: ITransaction; sql: AnsiString;
1182     CursorName: AnsiString): IStatement;
1183 tony 45 begin
1184 tony 350 Result := Prepare(transaction,sql,FSQLDialect,CursorName);
1185 tony 45 end;
1186    
1187     function TFBAttachment.PrepareWithNamedParameters(transaction: ITransaction;
1188 tony 350 sql: AnsiString; GenerateParamNames: boolean; CaseSensitiveParams: boolean;
1189     CursorName: AnsiString): IStatement;
1190 tony 45 begin
1191 tony 350 Result := PrepareWithNamedParameters(transaction,sql,FSQLDialect,GenerateParamNames,CaseSensitiveParams,CursorName);
1192 tony 45 end;
1193    
1194 tony 56 function TFBAttachment.GetEventHandler(Event: AnsiString): IEvents;
1195 tony 45 var S: TStringList;
1196     begin
1197     S := TStringList.Create;
1198     try
1199     S.Add(Event);
1200     Result := GetEventHandler(S);
1201     finally
1202     S.Free;
1203     end;
1204     end;
1205    
1206     function TFBAttachment.GetSQLDialect: integer;
1207     begin
1208     Result := FSQLDialect;
1209     end;
1210    
1211 tony 371 function TFBAttachment.GetAttachmentID: integer;
1212     begin
1213     Result := FAttachmentID;
1214     end;
1215    
1216 tony 291 function TFBAttachment.CreateBlob(transaction: ITransaction; RelationName,
1217     ColumnName: AnsiString; BPB: IBPB): IBlob;
1218     begin
1219     Result := CreateBlob(transaction,GetBlobMetaData(Transaction,RelationName,ColumnName),BPB);
1220     end;
1221    
1222     function TFBAttachment.OpenBlob(transaction: ITransaction; RelationName,
1223     ColumnName: AnsiString; BlobID: TISC_QUAD; BPB: IBPB): IBlob;
1224     begin
1225     Result := OpenBlob(Transaction,
1226     GetBlobMetaData(Transaction,RelationName,ColumnName),
1227     BlobID,BPB);
1228     end;
1229    
1230 tony 45 function TFBAttachment.OpenBlob(transaction: ITransaction; Field: ISQLData;
1231     BPB: IBPB): IBlob;
1232     begin
1233     Result := OpenBlob(Transaction,Field.GetBlobMetadata, Field.AsQuad,BPB);
1234     end;
1235    
1236 tony 291 function TFBAttachment.CreateArray(transaction: ITransaction; RelationName,
1237     ColumnName: AnsiString): IArray;
1238     begin
1239     Result := CreateArray(transaction,GetArrayMetaData(transaction,RelationName,ColumnName));
1240     end;
1241    
1242     function TFBAttachment.OpenArray(transaction: ITransaction; RelationName,
1243     ColumnName: AnsiString; ArrayID: TISC_QUAD): IArray;
1244     begin
1245     Result := OpenArray(transaction,
1246     GetArrayMetaData(transaction,RelationName,ColumnName),ArrayID);
1247     end;
1248    
1249 tony 143 function TFBAttachment.GetDBInformation(Requests: array of byte
1250     ): IDBInformation;
1251     var ReqBuffer: PByte;
1252     i: integer;
1253     begin
1254     CheckHandle;
1255     if Length(Requests) = 1 then
1256     Result := GetDBInformation(Requests[0])
1257     else
1258     begin
1259     GetMem(ReqBuffer,Length(Requests));
1260     try
1261     for i := 0 to Length(Requests) - 1 do
1262     ReqBuffer[i] := Requests[i];
1263    
1264     Result := GetDBInfo(ReqBuffer,Length(Requests));
1265    
1266     finally
1267     FreeMem(ReqBuffer);
1268     end;
1269     end;
1270     end;
1271    
1272     function TFBAttachment.GetDBInformation(Request: byte): IDBInformation;
1273     begin
1274     CheckHandle;
1275     Result := GetDBInfo(@Request,1);
1276     end;
1277    
1278     function TFBAttachment.GetDBInformation(Requests: IDIRB): IDBInformation;
1279     begin
1280     CheckHandle;
1281     with Requests as TDIRB do
1282     Result := GetDBInfo(getBuffer,getDataLength);
1283     end;
1284    
1285 tony 117 function TFBAttachment.GetConnectString: AnsiString;
1286     begin
1287     Result := FDatabaseName;
1288     end;
1289    
1290     function TFBAttachment.GetRemoteProtocol: AnsiString;
1291     begin
1292     Result := FRemoteProtocol;
1293     end;
1294    
1295 tony 143 function TFBAttachment.GetAuthenticationMethod: AnsiString;
1296     begin
1297     Result := FAuthMethod;
1298     end;
1299    
1300 tony 209 function TFBAttachment.GetSecurityDatabase: AnsiString;
1301     begin
1302     Result := FSecDatabase;
1303     end;
1304    
1305 tony 117 function TFBAttachment.GetODSMajorVersion: integer;
1306     begin
1307     Result := FODSMajorVersion;
1308     end;
1309    
1310     function TFBAttachment.GetODSMinorVersion: integer;
1311     begin
1312     Result := FODSMinorVersion;
1313     end;
1314    
1315 tony 371 function TFBAttachment.GetCharSetID: integer;
1316     begin
1317     Result := FCharSetID;
1318     end;
1319    
1320 tony 315 function TFBAttachment.HasDecFloatSupport: boolean;
1321     begin
1322     Result := false;
1323     end;
1324    
1325 tony 345 function TFBAttachment.GetInlineBlobLimit: integer;
1326     begin
1327     Result := FInlineBlobLimit;
1328     end;
1329    
1330     procedure TFBAttachment.SetInlineBlobLimit(limit: integer);
1331     begin
1332     if limit > 32*1024 then
1333     FInlineBlobLimit := 32*1024
1334     else
1335     FInlineBlobLimit := limit;
1336     end;
1337    
1338     function TFBAttachment.HasBatchMode: boolean;
1339     begin
1340     Result := false;
1341     end;
1342    
1343 tony 363 function TFBAttachment.HasTable(aTableName: AnsiString): boolean;
1344     begin
1345     Result := OpenCursorAtStart(
1346     'Select count(*) From RDB$RELATIONS Where RDB$RELATION_NAME = ?',
1347     [aTableName])[0].AsInteger > 0;
1348     end;
1349    
1350 tony 371 function TFBAttachment.HasFunction(aFunctionName: AnsiString): boolean;
1351     begin
1352     Result := OpenCursorAtStart(
1353     'Select count(*) From RDB$FUNCTIONS Where RDB$FUNCTION_NAME = ?',
1354     [aFunctionName])[0].AsInteger > 0;
1355     end;
1356    
1357     function TFBAttachment.HasProcedure(aProcName: AnsiString): boolean;
1358     begin
1359     Result := OpenCursorAtStart(
1360     'Select count(*) From RDB$PROCEDURES Where RDB$PROCEDURE_NAME = ?',
1361     [aProcName])[0].AsInteger > 0;
1362     end;
1363    
1364 tony 109 function TFBAttachment.HasDefaultCharSet: boolean;
1365     begin
1366     Result := FHasDefaultCharSet
1367     end;
1368    
1369     function TFBAttachment.GetDefaultCharSetID: integer;
1370     begin
1371     Result := FCharsetID;
1372     end;
1373    
1374 tony 60 function TFBAttachment.GetCharsetName(CharSetID: integer): AnsiString;
1375     var i: integer;
1376     begin
1377     Result := '';
1378     if (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap)) and
1379     (CharSetMap[CharSetID].CharSetID = CharSetID) then
1380     begin
1381     Result := CharSetMap[CharSetID].CharSetName;
1382     Exit;
1383     end;
1384    
1385     for i := 0 to Length(FUserCharSetMap) - 1 do
1386     if FUserCharSetMap[i].CharSetID = CharSetID then
1387     begin
1388     Result := FUserCharSetMap[i].CharSetName;
1389     Exit;
1390     end;
1391     end;
1392    
1393     function TFBAttachment.CharSetID2CodePage(CharSetID: integer;
1394     var CodePage: TSystemCodePage): boolean;
1395     var i: integer;
1396     begin
1397     Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
1398     and (CharSetMap[CharSetID].CharSetID = CharSetID);
1399     if Result then
1400     begin
1401     CodePage := CharSetMap[CharSetID].CodePage;
1402     Result := true;
1403     Exit;
1404     end;
1405    
1406     for i := 0 to Length(FUserCharSetMap) - 1 do
1407     if FUserCharSetMap[i].CharSetID = CharSetID then
1408     begin
1409     CodePage := FUserCharSetMap[i].CodePage;
1410     Result := true;
1411     Exit;
1412     end;
1413     end;
1414    
1415     function TFBAttachment.CodePage2CharSetID(CodePage: TSystemCodePage;
1416     var CharSetID: integer): boolean;
1417     var i: integer;
1418     begin
1419     Result := false;
1420     for i := Low(CharSetMap) to High(CharSetMap) do
1421     if (CharSetMap[i].AllowReverseLookup) and (CharSetMap[i].CodePage = CodePage) then
1422     begin
1423     CharSetID := CharSetMap[i].CharSetID;
1424     Result := true;
1425     Exit;
1426     end;
1427    
1428     for i := 0 to Length(FUserCharSetMap) - 1 do
1429     if (FUserCharSetMap[i].AllowReverseLookup) and (FUserCharSetMap[i].CodePage = CodePage) then
1430     begin
1431     CharSetID := FUserCharSetMap[i].CharSetID;
1432     Result := true;
1433     Exit;
1434     end;
1435     end;
1436    
1437     function TFBAttachment.CharSetName2CharSetID(CharSetName: AnsiString;
1438     var CharSetID: integer): boolean;
1439     var i: integer;
1440     begin
1441     Result := false;
1442     for i := Low(CharSetMap) to High(CharSetMap) do
1443 tony 233 if AnsiCompareText(CharSetMap[i].CharSetName, CharSetName) = 0 then
1444 tony 60 begin
1445     CharSetID := CharSetMap[i].CharSetID;
1446     Result := true;
1447     Exit;
1448     end;
1449    
1450     for i := 0 to Length(FUserCharSetMap) - 1 do
1451 tony 233 if AnsiCompareText(FUserCharSetMap[i].CharSetName, CharSetName) = 0 then
1452 tony 60 begin
1453     CharSetID := FUserCharSetMap[i].CharSetID;
1454     Result := true;
1455     Exit;
1456     end;
1457     end;
1458    
1459     function TFBAttachment.CharSetWidth(CharSetID: integer; var Width: integer
1460     ): boolean;
1461     var i: integer;
1462     begin
1463     Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
1464     and (CharSetMap[CharSetID].CharSetID = CharSetID);
1465     if Result then
1466     begin
1467     Width := CharSetMap[CharSetID].CharSetWidth;
1468     Result := true;
1469     Exit;
1470     end;
1471    
1472     for i := 0 to Length(FUserCharSetMap) - 1 do
1473     if FUserCharSetMap[i].CharSetID = CharSetID then
1474     begin
1475     Width := FUserCharSetMap[i].CharSetWidth;
1476     Result := true;
1477     Exit;
1478     end;
1479     end;
1480    
1481     const
1482     sqlLookupCharSet = 'Select RDB$CHARACTER_SET_ID, RDB$BYTES_PER_CHARACTER From RDB$CHARACTER_SETS '+
1483     'Where RDB$SYSTEM_FLAG = 0 and RDB$CHARACTER_SET_NAME = UPPER(?)';
1484    
1485     procedure TFBAttachment.RegisterCharSet(CharSetName: AnsiString;
1486     CodePage: TSystemCodePage; AllowReverseLookup: boolean; out CharSetID: integer
1487     );
1488     var CharSets: IResultSet;
1489     idx: integer;
1490     begin
1491     if CharSetName2CharSetID(CharSetName,CharSetID) then
1492     IBError(ibxeCharacterSetExists,[CharSetName]);
1493    
1494     CharSets := OpenCursorAtStart(sqlLookupCharSet,[CharSetName]);
1495     if CharSets.IsEof then
1496     IBError(ibxeUnknownUserCharSet,[CharSetName]);
1497    
1498     idx := Length(FUserCharSetMap);
1499     SetLength(FUserCharSetMap,idx+1);
1500     FUserCharSetMap[idx].AllowReverseLookup := AllowReverseLookup;
1501     FUserCharSetMap[idx].CharSetID := CharSets[0].AsInteger;
1502     FUserCharSetMap[idx].CharSetName := AnsiUpperCase(CharSetName);
1503     FUserCharSetMap[idx].CharSetWidth := CharSets[1].AsInteger;
1504     FUserCharSetMap[idx].CodePage := CodePage;
1505     CharSetID := CharSets[0].AsInteger;
1506     end;
1507    
1508 tony 315 function TFBAttachment.GetTimeZoneServices: ITimeZoneServices;
1509     begin
1510     IBError(ibxeNotSupported,[]);
1511     end;
1512    
1513     function TFBAttachment.HasTimeZoneSupport: boolean;
1514     begin
1515     Result := false;
1516     end;
1517    
1518     { TDPBItem }
1519    
1520     function TDPBItem.getParamTypeName: AnsiString;
1521     begin
1522     Result := DPBPrefix + DPBConstantNames[getParamType];
1523     end;
1524    
1525     { TDPB }
1526    
1527     constructor TDPB.Create(api: TFBClientAPI);
1528     begin
1529     inherited Create(api);
1530     FDataLength := 1;
1531     FBuffer^ := isc_dpb_version1;
1532     end;
1533    
1534 tony 345 function TDPB.GetParamTypeName(ParamType: byte): Ansistring;
1535 tony 315 begin
1536     if ParamType <= isc_dpb_last_dpb_constant then
1537     Result := DPBConstantNames[ParamType]
1538     else
1539     Result := '';
1540     end;
1541    
1542 tony 345 {$IFNDEF FPC}
1543     function TDPB.GetDPBParamTypeName(ParamType: byte): Ansistring;
1544     begin
1545     Result := GetParamTypeName(ParamType);
1546     end;
1547     {$ENDIF}
1548    
1549 tony 315 function TDPB.LookupItemType(ParamTypeName: AnsiString): byte;
1550     var i: byte;
1551     begin
1552     Result := 0;
1553     ParamTypeName := LowerCase(ParamTypeName);
1554     if (Pos(DPBPrefix, ParamTypeName) = 1) then
1555     Delete(ParamTypeName, 1, Length(DPBPrefix));
1556    
1557     for i := 1 to isc_dpb_last_dpb_constant do
1558     if (ParamTypeName = DPBConstantNames[i]) then
1559     begin
1560     Result := i;
1561     break;
1562     end;
1563     end;
1564    
1565 tony 45 end.
1566