ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBAttachment.pas
Revision: 402
Committed: Mon Aug 1 10:07:24 2022 UTC (20 months, 4 weeks ago) by tony
Content type: text/x-pascal
File size: 60004 byte(s)
Log Message:
IBX Release 2.5.0

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

Properties

Name Value
svn:eol-style native