ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBAttachment.pas
Revision: 387
Committed: Wed Jan 19 13:34:42 2022 UTC (2 years, 10 months ago) by tony
Content type: text/x-pascal
File size: 58060 byte(s)
Log Message:
Transactions started within a UDR are not forcibly closed if still active immediately prior to UDR exit

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 except
1103 tr.Rollback(true);
1104 raise;
1105 end;
1106 end;
1107
1108 procedure TFBAttachment.ExecImmediate(transaction: ITransaction; sql: AnsiString);
1109 begin
1110 ExecImmediate(transaction,sql,FSQLDialect);
1111 end;
1112
1113 procedure TFBAttachment.ExecImmediate(TPB: array of byte; sql: AnsiString);
1114 begin
1115 ExecImmediate(TPB,sql,FSQLDialect);
1116 end;
1117
1118 function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
1119 SQLDialect: integer; params: array of const): IResults;
1120 var tr: ITransaction;
1121 begin
1122 tr := StartTransaction(TPB,taCommit);
1123 try
1124 Result := ExecuteSQL(tr,sql,SQLDialect,params);
1125 except
1126 tr.Rollback(true);
1127 raise;
1128 end;
1129 end;
1130
1131 function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
1132 SQLDialect: integer; params: array of const): IResults;
1133 begin
1134 with Prepare(transaction,sql,SQLDialect) do
1135 begin
1136 SetParameters(SQLParams,params);
1137 Result := Execute;
1138 end;
1139 end;
1140
1141 function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
1142 params: array of const): IResults;
1143 begin
1144 Result := ExecuteSQL(TPB,sql,FSQLDialect,params);
1145 end;
1146
1147 function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
1148 params: array of const): IResults;
1149 begin
1150 Result := ExecuteSQL(transaction,sql,FSQLDialect,params);
1151 end;
1152
1153 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1154 aSQLDialect: integer; Scrollable: boolean): IResultSet;
1155 begin
1156 Result := OpenCursor(transaction,sql,aSQLDialect,Scrollable,[]);
1157 end;
1158
1159 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1160 aSQLDialect: integer; params: array of const): IResultSet;
1161
1162 begin
1163 Result := OpenCursor(transaction,sql,FSQLDialect,false,params);
1164 end;
1165
1166 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1167 Scrollable: boolean): IResultSet;
1168 begin
1169 Result := OpenCursor(transaction,sql,FSQLDialect,Scrollable,[]);
1170 end;
1171
1172 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1173 params: array of const): IResultSet;
1174 begin
1175 Result := OpenCursor(transaction,sql,FSQLDialect,false,params);
1176 end;
1177
1178 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1179 Scrollable: boolean; params: array of const): IResultSet;
1180 begin
1181 Result := OpenCursor(transaction,sql,FSQLDialect,Scrollable,params);
1182 end;
1183
1184 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1185 aSQLDialect: integer; Scrollable: boolean;
1186 params: array of const): IResultSet;
1187 var Statement: IStatement;
1188 begin
1189 CheckHandle;
1190 Statement := Prepare(transaction,sql,aSQLDialect);
1191 SetParameters(Statement.SQLParams,params);
1192 Result := Statement.OpenCursor(Scrollable);
1193 end;
1194
1195 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1196 sql: AnsiString; aSQLDialect: integer; Scrollable: boolean): IResultSet;
1197 begin
1198 Result := OpenCursor(transaction,sql,aSQLDialect,Scrollable,[]);
1199 Result.FetchNext;
1200 end;
1201
1202 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1203 sql: AnsiString; aSQLDialect: integer; params: array of const): IResultSet;
1204 begin
1205 Result := OpenCursor(transaction,sql,aSQLDialect,params);
1206 Result.FetchNext;
1207 end;
1208
1209 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1210 sql: AnsiString; aSQLDialect: integer; Scrollable: boolean;
1211 params: array of const): IResultSet;
1212 begin
1213 Result := OpenCursor(transaction,sql,aSQLDialect,Scrollable,params);
1214 Result.FetchNext;
1215 end;
1216
1217 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1218 sql: AnsiString; Scrollable: boolean): IResultSet;
1219 begin
1220 Result := OpenCursorAtStart(transaction,sql,FSQLDialect,Scrollable,[]);
1221 end;
1222
1223 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1224 sql: AnsiString; params: array of const): IResultSet;
1225 begin
1226 Result := OpenCursorAtStart(transaction,sql,FSQLDialect,params);
1227 end;
1228
1229 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1230 sql: AnsiString; Scrollable: boolean; params: array of const): IResultSet;
1231 begin
1232 Result := OpenCursorAtStart(transaction,sql,FSQLDialect,Scrollable,params);
1233 end;
1234
1235 function TFBAttachment.OpenCursorAtStart(sql: AnsiString; Scrollable: boolean
1236 ): IResultSet;
1237 begin
1238 Result := OpenCursorAtStart(sql,Scrollable,[]);
1239 end;
1240
1241 function TFBAttachment.OpenCursorAtStart(sql: AnsiString; Scrollable: boolean;
1242 params: array of const): IResultSet;
1243 var tr: ITransaction;
1244 begin
1245 tr := StartTransaction([isc_tpb_read,isc_tpb_wait,isc_tpb_concurrency],taCommit);
1246 try
1247 Result := OpenCursorAtStart(tr,sql,FSQLDialect,Scrollable,params);
1248 except
1249 tr.Rollback(true);
1250 raise;
1251 end;
1252 end;
1253
1254 function TFBAttachment.OpenCursorAtStart(sql: AnsiString;
1255 params: array of const): IResultSet;
1256 begin
1257 Result := OpenCursorAtStart(sql,false,params);
1258 end;
1259
1260 function TFBAttachment.Prepare(transaction: ITransaction; sql: AnsiString;
1261 CursorName: AnsiString): IStatement;
1262 begin
1263 Result := Prepare(transaction,sql,FSQLDialect,CursorName);
1264 end;
1265
1266 function TFBAttachment.PrepareWithNamedParameters(transaction: ITransaction;
1267 sql: AnsiString; GenerateParamNames: boolean; CaseSensitiveParams: boolean;
1268 CursorName: AnsiString): IStatement;
1269 begin
1270 Result := PrepareWithNamedParameters(transaction,sql,FSQLDialect,GenerateParamNames,CaseSensitiveParams,CursorName);
1271 end;
1272
1273 function TFBAttachment.GetEventHandler(Event: AnsiString): IEvents;
1274 var S: TStringList;
1275 begin
1276 S := TStringList.Create;
1277 try
1278 S.Add(Event);
1279 Result := GetEventHandler(S);
1280 finally
1281 S.Free;
1282 end;
1283 end;
1284
1285 function TFBAttachment.GetSQLDialect: integer;
1286 begin
1287 NeedDBInfo;
1288 Result := FSQLDialect;
1289 end;
1290
1291 function TFBAttachment.GetAttachmentID: integer;
1292 begin
1293 NeedDBInfo;
1294 Result := FAttachmentID;
1295 end;
1296
1297 function TFBAttachment.CreateBlob(transaction: ITransaction; RelationName,
1298 ColumnName: AnsiString; BPB: IBPB): IBlob;
1299 begin
1300 Result := CreateBlob(transaction,GetBlobMetaData(Transaction,RelationName,ColumnName),BPB);
1301 end;
1302
1303 function TFBAttachment.OpenBlob(transaction: ITransaction; RelationName,
1304 ColumnName: AnsiString; BlobID: TISC_QUAD; BPB: IBPB): IBlob;
1305 begin
1306 Result := OpenBlob(Transaction,
1307 GetBlobMetaData(Transaction,RelationName,ColumnName),
1308 BlobID,BPB);
1309 end;
1310
1311 function TFBAttachment.OpenBlob(transaction: ITransaction; Field: ISQLData;
1312 BPB: IBPB): IBlob;
1313 begin
1314 Result := OpenBlob(Transaction,Field.GetBlobMetadata, Field.AsQuad,BPB);
1315 end;
1316
1317 function TFBAttachment.CreateArray(transaction: ITransaction; RelationName,
1318 ColumnName: AnsiString): IArray;
1319 begin
1320 Result := CreateArray(transaction,GetArrayMetaData(transaction,RelationName,ColumnName));
1321 end;
1322
1323 function TFBAttachment.OpenArray(transaction: ITransaction; RelationName,
1324 ColumnName: AnsiString; ArrayID: TISC_QUAD): IArray;
1325 begin
1326 Result := OpenArray(transaction,
1327 GetArrayMetaData(transaction,RelationName,ColumnName),ArrayID);
1328 end;
1329
1330 function TFBAttachment.GetDBInformation(Requests: array of byte
1331 ): IDBInformation;
1332 var ReqBuffer: PByte;
1333 i: integer;
1334 begin
1335 CheckHandle;
1336 if Length(Requests) = 1 then
1337 Result := GetDBInformation(Requests[0])
1338 else
1339 begin
1340 GetMem(ReqBuffer,Length(Requests));
1341 try
1342 for i := 0 to Length(Requests) - 1 do
1343 ReqBuffer[i] := Requests[i];
1344
1345 Result := GetDBInfo(ReqBuffer,Length(Requests));
1346
1347 finally
1348 FreeMem(ReqBuffer);
1349 end;
1350 end;
1351 end;
1352
1353 function TFBAttachment.GetDBInformation(Request: byte): IDBInformation;
1354 begin
1355 CheckHandle;
1356 Result := GetDBInfo(@Request,1);
1357 end;
1358
1359 function TFBAttachment.GetDBInformation(Requests: IDIRB): IDBInformation;
1360 begin
1361 CheckHandle;
1362 with Requests as TDIRB do
1363 Result := GetDBInfo(getBuffer,getDataLength);
1364 end;
1365
1366 function TFBAttachment.GetConnectString: AnsiString;
1367 begin
1368 Result := FDatabaseName;
1369 end;
1370
1371 function TFBAttachment.GetRemoteProtocol: AnsiString;
1372 begin
1373 NeedConnectionInfo;
1374 Result := FRemoteProtocol;
1375 end;
1376
1377 function TFBAttachment.GetAuthenticationMethod: AnsiString;
1378 begin
1379 NeedConnectionInfo;
1380 Result := FAuthMethod;
1381 end;
1382
1383 function TFBAttachment.GetSecurityDatabase: AnsiString;
1384 begin
1385 NeedConnectionInfo;
1386 Result := FSecDatabase;
1387 end;
1388
1389 function TFBAttachment.GetODSMajorVersion: integer;
1390 begin
1391 NeedDBInfo;
1392 Result := FODSMajorVersion;
1393 end;
1394
1395 function TFBAttachment.GetODSMinorVersion: integer;
1396 begin
1397 NeedDBInfo;
1398 Result := FODSMinorVersion;
1399 end;
1400
1401 function TFBAttachment.GetCharSetID: integer;
1402 begin
1403 NeedConnectionInfo;
1404 Result := FCharSetID;
1405 end;
1406
1407 function TFBAttachment.HasDecFloatSupport: boolean;
1408 begin
1409 Result := false;
1410 end;
1411
1412 function TFBAttachment.GetInlineBlobLimit: integer;
1413 begin
1414 Result := FInlineBlobLimit;
1415 end;
1416
1417 procedure TFBAttachment.SetInlineBlobLimit(limit: integer);
1418 begin
1419 if limit > 32*1024 then
1420 FInlineBlobLimit := 32*1024
1421 else
1422 FInlineBlobLimit := limit;
1423 end;
1424
1425 function TFBAttachment.HasBatchMode: boolean;
1426 begin
1427 Result := false;
1428 end;
1429
1430 function TFBAttachment.HasTable(aTableName: AnsiString): boolean;
1431 begin
1432 Result := OpenCursorAtStart(
1433 'Select count(*) From RDB$RELATIONS Where RDB$RELATION_NAME = ?',
1434 [aTableName])[0].AsInteger > 0;
1435 end;
1436
1437 function TFBAttachment.HasFunction(aFunctionName: AnsiString): boolean;
1438 begin
1439 Result := OpenCursorAtStart(
1440 'Select count(*) From RDB$FUNCTIONS Where RDB$FUNCTION_NAME = ?',
1441 [aFunctionName])[0].AsInteger > 0;
1442 end;
1443
1444 function TFBAttachment.HasProcedure(aProcName: AnsiString): boolean;
1445 begin
1446 Result := OpenCursorAtStart(
1447 'Select count(*) From RDB$PROCEDURES Where RDB$PROCEDURE_NAME = ?',
1448 [aProcName])[0].AsInteger > 0;
1449 end;
1450
1451 function TFBAttachment.HasDefaultCharSet: boolean;
1452 begin
1453 NeedConnectionInfo;
1454 Result := FHasDefaultCharSet
1455 end;
1456
1457 function TFBAttachment.GetDefaultCharSetID: integer;
1458 begin
1459 NeedConnectionInfo;
1460 Result := FCharsetID;
1461 end;
1462
1463 function TFBAttachment.GetCharsetName(CharSetID: integer): AnsiString;
1464 var i: integer;
1465 begin
1466 Result := '';
1467 if (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap)) and
1468 (CharSetMap[CharSetID].CharSetID = CharSetID) then
1469 begin
1470 Result := CharSetMap[CharSetID].CharSetName;
1471 Exit;
1472 end;
1473
1474 for i := 0 to Length(FUserCharSetMap) - 1 do
1475 if FUserCharSetMap[i].CharSetID = CharSetID then
1476 begin
1477 Result := FUserCharSetMap[i].CharSetName;
1478 Exit;
1479 end;
1480 end;
1481
1482 function TFBAttachment.CharSetID2CodePage(CharSetID: integer;
1483 var CodePage: TSystemCodePage): boolean;
1484 var i: integer;
1485 begin
1486 Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
1487 and (CharSetMap[CharSetID].CharSetID = CharSetID);
1488 if Result then
1489 begin
1490 CodePage := CharSetMap[CharSetID].CodePage;
1491 Result := true;
1492 Exit;
1493 end;
1494
1495 for i := 0 to Length(FUserCharSetMap) - 1 do
1496 if FUserCharSetMap[i].CharSetID = CharSetID then
1497 begin
1498 CodePage := FUserCharSetMap[i].CodePage;
1499 Result := true;
1500 Exit;
1501 end;
1502 end;
1503
1504 function TFBAttachment.CodePage2CharSetID(CodePage: TSystemCodePage;
1505 var CharSetID: integer): boolean;
1506 var i: integer;
1507 begin
1508 Result := false;
1509 for i := Low(CharSetMap) to High(CharSetMap) do
1510 if (CharSetMap[i].AllowReverseLookup) and (CharSetMap[i].CodePage = CodePage) then
1511 begin
1512 CharSetID := CharSetMap[i].CharSetID;
1513 Result := true;
1514 Exit;
1515 end;
1516
1517 for i := 0 to Length(FUserCharSetMap) - 1 do
1518 if (FUserCharSetMap[i].AllowReverseLookup) and (FUserCharSetMap[i].CodePage = CodePage) then
1519 begin
1520 CharSetID := FUserCharSetMap[i].CharSetID;
1521 Result := true;
1522 Exit;
1523 end;
1524 end;
1525
1526 function TFBAttachment.CharSetName2CharSetID(CharSetName: AnsiString;
1527 var CharSetID: integer): boolean;
1528 var i: integer;
1529 begin
1530 Result := false;
1531 for i := Low(CharSetMap) to High(CharSetMap) do
1532 if AnsiCompareText(CharSetMap[i].CharSetName, CharSetName) = 0 then
1533 begin
1534 CharSetID := CharSetMap[i].CharSetID;
1535 Result := true;
1536 Exit;
1537 end;
1538
1539 for i := 0 to Length(FUserCharSetMap) - 1 do
1540 if AnsiCompareText(FUserCharSetMap[i].CharSetName, CharSetName) = 0 then
1541 begin
1542 CharSetID := FUserCharSetMap[i].CharSetID;
1543 Result := true;
1544 Exit;
1545 end;
1546 end;
1547
1548 function TFBAttachment.CharSetWidth(CharSetID: integer; var Width: integer
1549 ): boolean;
1550 var i: integer;
1551 begin
1552 Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
1553 and (CharSetMap[CharSetID].CharSetID = CharSetID);
1554 if Result then
1555 begin
1556 Width := CharSetMap[CharSetID].CharSetWidth;
1557 Result := true;
1558 Exit;
1559 end;
1560
1561 for i := 0 to Length(FUserCharSetMap) - 1 do
1562 if FUserCharSetMap[i].CharSetID = CharSetID then
1563 begin
1564 Width := FUserCharSetMap[i].CharSetWidth;
1565 Result := true;
1566 Exit;
1567 end;
1568 end;
1569
1570 const
1571 sqlLookupCharSet = 'Select RDB$CHARACTER_SET_ID, RDB$BYTES_PER_CHARACTER From RDB$CHARACTER_SETS '+
1572 'Where RDB$SYSTEM_FLAG = 0 and RDB$CHARACTER_SET_NAME = UPPER(?)';
1573
1574 procedure TFBAttachment.RegisterCharSet(CharSetName: AnsiString;
1575 CodePage: TSystemCodePage; AllowReverseLookup: boolean; out CharSetID: integer
1576 );
1577 var CharSets: IResultSet;
1578 idx: integer;
1579 begin
1580 if CharSetName2CharSetID(CharSetName,CharSetID) then
1581 IBError(ibxeCharacterSetExists,[CharSetName]);
1582
1583 CharSets := OpenCursorAtStart(sqlLookupCharSet,[CharSetName]);
1584 if CharSets.IsEof then
1585 IBError(ibxeUnknownUserCharSet,[CharSetName]);
1586
1587 idx := Length(FUserCharSetMap);
1588 SetLength(FUserCharSetMap,idx+1);
1589 FUserCharSetMap[idx].AllowReverseLookup := AllowReverseLookup;
1590 FUserCharSetMap[idx].CharSetID := CharSets[0].AsInteger;
1591 FUserCharSetMap[idx].CharSetName := AnsiUpperCase(CharSetName);
1592 FUserCharSetMap[idx].CharSetWidth := CharSets[1].AsInteger;
1593 FUserCharSetMap[idx].CodePage := CodePage;
1594 CharSetID := CharSets[0].AsInteger;
1595 end;
1596
1597 function TFBAttachment.GetTimeZoneServices: ITimeZoneServices;
1598 begin
1599 IBError(ibxeNotSupported,[]);
1600 end;
1601
1602 function TFBAttachment.HasTimeZoneSupport: boolean;
1603 begin
1604 Result := false;
1605 end;
1606
1607 { TDPBItem }
1608
1609 function TDPBItem.getParamTypeName: AnsiString;
1610 begin
1611 Result := DPBPrefix + DPBConstantNames[getParamType];
1612 end;
1613
1614 { TDPB }
1615
1616 constructor TDPB.Create(api: TFBClientAPI);
1617 begin
1618 inherited Create(api);
1619 FDataLength := 1;
1620 FBuffer^ := isc_dpb_version1;
1621 end;
1622
1623 function TDPB.GetParamTypeName(ParamType: byte): Ansistring;
1624 begin
1625 if ParamType <= isc_dpb_last_dpb_constant then
1626 Result := DPBConstantNames[ParamType]
1627 else
1628 Result := '';
1629 end;
1630
1631 {$IFNDEF FPC}
1632 function TDPB.GetDPBParamTypeName(ParamType: byte): Ansistring;
1633 begin
1634 Result := GetParamTypeName(ParamType);
1635 end;
1636 {$ENDIF}
1637
1638 function TDPB.LookupItemType(ParamTypeName: AnsiString): byte;
1639 var i: byte;
1640 begin
1641 Result := 0;
1642 ParamTypeName := LowerCase(ParamTypeName);
1643 if (Pos(DPBPrefix, ParamTypeName) = 1) then
1644 Delete(ParamTypeName, 1, Length(DPBPrefix));
1645
1646 for i := 1 to isc_dpb_last_dpb_constant do
1647 if (ParamTypeName = DPBConstantNames[i]) then
1648 begin
1649 Result := i;
1650 break;
1651 end;
1652 end;
1653
1654 end.
1655

Properties

Name Value
svn:eol-style native