ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBAttachment.pas
Revision: 389
Committed: Thu Jan 20 23:33:40 2022 UTC (2 years, 10 months ago) by tony
Content type: text/x-pascal
File size: 58075 byte(s)
Log Message:
commit bug fix

File Contents

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

Properties

Name Value
svn:eol-style native