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

# User Rev Content
1 tony 45 (*
2     * Firebird Interface (fbintf). The fbintf components provide a set of
3     * Pascal language bindings for the Firebird API.
4     *
5     * The contents of this file are subject to the Initial Developer's
6     * Public License Version 1.0 (the "License"); you may not use this
7     * file except in compliance with the License. You may obtain a copy
8     * of the License here:
9     *
10     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11     *
12     * Software distributed under the License is distributed on an "AS
13     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14     * implied. See the License for the specific language governing rights
15     * and limitations under the License.
16     *
17     * The Initial Developer of the Original Code is Tony Whyman.
18     *
19 tony 371 * The Original Code is (C) 2016-2021 Tony Whyman, MWA Software
20 tony 45 * (http://www.mwasoftware.co.uk).
21     *
22     * All Rights Reserved.
23     *
24     * Contributor(s): ______________________________________.
25     *
26     *)
27     unit FBAttachment;
28 tony 56 {$IFDEF MSWINDOWS}
29     {$DEFINE WINDOWS}
30     {$ENDIF}
31 tony 45
32     {$IFDEF FPC}
33 tony 56 {$mode delphi}
34 tony 45 {$interfaces COM}
35 tony 118 {$define HASREQEX}
36 tony 45 {$ENDIF}
37    
38     interface
39    
40     uses
41 tony 263 Classes, SysUtils, {$IFDEF WINDOWS} windows, {$ENDIF} IB, FBParamBlock,
42 tony 363 FBActivityMonitor, FBClientAPI, IBUtils;
43 tony 45
44 tony 345 const
45     DefaultMaxInlineBlobLimit = 8192;
46    
47 tony 45 type
48 tony 60 TCharsetMap = record
49     CharsetID: integer;
50     CharSetName: AnsiString;
51     CharSetWidth: integer;
52     CodePage: TSystemCodePage;
53     AllowReverseLookup: boolean; {used to ensure that lookup of CP_UTF* does not return UNICODE_FSS}
54     end;
55 tony 45
56 tony 363 { Database Journalling.
57    
58     This class is intended to support a client side journal of all database
59     updates, inserts and deletes made by the client during a session. It also records
60     the transaction each update was made under.
61    
62     The database schema is required to include a control table "IBX$JOURNALS" and
63     an SQL Sequence IBX$SESSIONS. These are created by the class when the
64     database is opened, if they are not already present. However, it is recommended
65     that they are created as an orginal part of the database schema in order to
66     unnecessarily avoid each user being given sufficient priviledge to create tables
67     and Sequences.
68    
69     Syntax:
70    
71     Transaction Start:
72 tony 371 *S:<date/time>,<attachmentid>,<session id>,<transaction no.>,<string length>:<transaction Name>,<string length>:<TPB>,<default Completion>
73 tony 363
74     Transaction Commit:
75 tony 371 *C:<date/time>,<attachmentid>,<session id>,<transaction no.>
76 tony 363
77     Transaction Commit retaining :
78 tony 371 *c:<date/time>,<attachmentid>,<session id>,<transaction no.><old transaction no.>
79 tony 363
80     Transaction Rollback:
81 tony 371 *R:<date/time>,<attachmentid>,<session id>,<transaction no.>
82 tony 363
83     Transaction Rollback retaining:
84 tony 371 *r:<date/time>,<attachmentid>,<session id>,<transaction no.><old transaction no.>
85 tony 363
86     Update/Insert/Delete
87 tony 371 *Q:<date/time>,<attachmentid>,<session id>,<transaction no.>,<length of query text in bytes>:<query text>
88 tony 363
89     }
90    
91     { TFBJournaling }
92    
93     TFBJournaling = class(TActivityHandler, IJournallingHook)
94     private
95     {Logfile}
96 tony 371 const sQueryJournal = '*Q:''%s'',%d,%d,%d,%d:%s' + LineEnding;
97     const sTransStartJnl = '*S:''%s'',%d,%d,%d,%d:%s,%d:%s,%d' + LineEnding;
98     const sTransCommitJnl = '*C:''%s'',%d,%d,%d' + LineEnding;
99 tony 387 const sTransCommitFailJnl = '*F:''%s'',%d,%d,%d' + LineEnding;
100 tony 371 const sTransCommitRetJnl = '*c:''%s'',%d,%d,%d,%d' + LineEnding;
101     const sTransRollBackJnl = '*R:''%s'',%d,%d,%d' + LineEnding;
102 tony 387 const sTransRollBackFailJnl = '*f:''%s'',%d,%d,%d' + LineEnding;
103 tony 371 const sTransRollBackRetJnl = '*r:''%s'',%d,%d,%d,%d' + LineEnding;
104 tony 363 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 tony 387 function TransactionEnd( TransactionID: integer; Completion: TTrCompletionState): boolean;
121 tony 363 procedure TransactionRetained(Tr: ITransaction; OldTransactionID: integer;
122     Action: TTransactionAction);
123     procedure ExecQuery(Stmt: IStatement);
124 tony 387 procedure ExecImmediateJnl(sql: AnsiString; tr: ITransaction);
125 tony 363 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 tony 371 function StartJournaling(S: TStream; Options: TJournalOptions): integer; overload;
132 tony 363 procedure StopJournaling(RetainJournal: boolean);
133     end;
134    
135 tony 45 { TFBAttachment }
136    
137 tony 363 TFBAttachment = class(TFBJournaling)
138 tony 45 private
139     FDPB: IDPB;
140     FFirebirdAPI: IFirebirdAPI;
141 tony 117 FODSMajorVersion: integer;
142     FODSMinorVersion: integer;
143 tony 60 FUserCharSetMap: array of TCharSetMap;
144 tony 209 FSecDatabase: AnsiString;
145 tony 345 FInlineBlobLimit: integer;
146 tony 371 FAttachmentID: integer;
147 tony 45 FSQLDialect: integer;
148     FHasDefaultCharSet: boolean;
149     FCharSetID: integer;
150     FCodePage: TSystemCodePage;
151 tony 117 FRemoteProtocol: AnsiString;
152 tony 143 FAuthMethod: AnsiString;
153 tony 375 FHasConnectionInfo: boolean;
154     procedure NeedDBInfo;
155     procedure NeedConnectionInfo;
156     protected
157     FDatabaseName: AnsiString;
158     FRaiseExceptionOnConnectError: boolean;
159 tony 263 constructor Create(api: TFBClientAPI; DatabaseName: AnsiString; DPB: IDPB;
160 tony 45 RaiseExceptionOnConnectError: boolean);
161     procedure CheckHandle; virtual; abstract;
162 tony 375 procedure ClearCachedInfo;
163 tony 56 function GenerateCreateDatabaseSQL(DatabaseName: AnsiString; aDPB: IDPB): AnsiString;
164 tony 143 function GetDBInfo(ReqBuffer: PByte; ReqBufLen: integer): IDBInformation; virtual; abstract;
165 tony 117 function IsConnected: boolean; virtual; abstract;
166 tony 45 procedure EndAllTransactions;
167 tony 117 procedure DPBFromCreateSQL(CreateSQL: AnsiString);
168 tony 45 procedure SetParameters(SQLParams: ISQLParams; params: array of const);
169 tony 375 procedure SetSQLDialect(aValue: integer);
170 tony 315 procedure UseServerICUChanged; virtual;
171 tony 45 public
172     destructor Destroy; override;
173 tony 375 procedure Disconnect(Force: boolean); override;
174 tony 263 function getFirebirdAPI: IFirebirdAPI;
175 tony 45 function getDPB: IDPB;
176     function AllocateBPB: IBPB;
177 tony 143 function AllocateDIRB: IDIRB;
178 tony 363 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 tony 56 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 tony 350 Scrollable: boolean=false): IResultSet; overload;
193     function OpenCursor(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
194 tony 45 params: array of const): IResultSet; overload;
195 tony 350 function OpenCursor(transaction: ITransaction; sql: AnsiString; Scrollable: boolean=false): IResultSet; overload;
196 tony 56 function OpenCursor(transaction: ITransaction; sql: AnsiString;
197 tony 45 params: array of const): IResultSet; overload;
198 tony 350 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 tony 56 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
203 tony 350 Scrollable: boolean=false): IResultSet; overload;
204     function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
205 tony 45 params: array of const): IResultSet; overload;
206 tony 350 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 tony 56 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString;
210 tony 45 params: array of const): IResultSet; overload;
211 tony 350 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 tony 56 function OpenCursorAtStart(sql: AnsiString;
217 tony 45 params: array of const): IResultSet; overload;
218 tony 350 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 tony 56 function PrepareWithNamedParameters(transaction: ITransaction; sql: AnsiString;
221 tony 270 aSQLDialect: integer; GenerateParamNames: boolean=false;
222 tony 350 CaseSensitiveParams: boolean = false; CursorName: AnsiString=''): IStatement; overload; virtual; abstract;
223 tony 56 function PrepareWithNamedParameters(transaction: ITransaction; sql: AnsiString;
224 tony 270 GenerateParamNames: boolean=false;
225 tony 350 CaseSensitiveParams: boolean = false; CursorName: AnsiString=''): IStatement; overload;
226 tony 45 function GetEventHandler(Events: TStrings): IEvents; overload; virtual; abstract;
227 tony 56 function GetEventHandler(Event: AnsiString): IEvents; overload;
228 tony 45
229     function GetSQLDialect: integer;
230 tony 371 function GetAttachmentID: integer;
231 tony 291 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 tony 56 function OpenBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB=nil): IBlob; overload; virtual; abstract;
234 tony 291 function OpenBlob(transaction: ITransaction; RelationName, ColumnName: AnsiString; BlobID: TISC_QUAD; BPB: IBPB=nil): IBlob; overload;
235 tony 45 function OpenBlob(transaction: ITransaction; Field: ISQLData; BPB: IBPB=nil): IBlob; overload;
236 tony 291 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 tony 375 property SQLDialect: integer read GetSQLDialect;
242 tony 45 property DPB: IDPB read FDPB;
243 tony 315 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 tony 371 function GetCharSetID: integer;
254 tony 315 function HasDecFloatSupport: boolean; virtual;
255 tony 345 function GetInlineBlobLimit: integer;
256     procedure SetInlineBlobLimit(limit: integer);
257     function HasBatchMode: boolean; virtual;
258 tony 363 function HasTable(aTableName: AnsiString): boolean;
259 tony 371 function HasFunction(aFunctionName: AnsiString): boolean;
260     function HasProcedure(aProcName: AnsiString): boolean;
261 tony 315
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 tony 375 property CharSetID: integer read GetCharSetID;
276 tony 315 property CodePage: TSystemCodePage read FCodePage;
277    
278     public
279     {Time Zone Support}
280     function GetTimeZoneServices: ITimeZoneServices; virtual;
281     function HasTimeZoneSupport: boolean; virtual;
282    
283 tony 45 end;
284    
285 tony 315 { 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 tony 345 function GetParamTypeName(ParamType: byte): Ansistring;
300     {$IFDEF FPC}
301     function IDPB.GetDPBParamTypeName = GetParamTypeName;
302     {$ELSE}
303 tony 315 function GetDPBParamTypeName(ParamType: byte): Ansistring;
304 tony 345 {$ENDIF}
305 tony 315 end;
306    
307 tony 45 implementation
308    
309 tony 363 uses FBMessages, IBErrorCodes, FBTransaction {$IFDEF HASREQEX}, RegExpr{$ENDIF};
310 tony 45
311 tony 60 const
312 tony 363 {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 tony 60 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 tony 315 const
410     isc_dpb_last_dpb_constant = isc_dpb_decfloat_traps;
411 tony 60
412 tony 315 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 tony 387 'utf8_filename',
490 tony 315 '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 tony 60
510 tony 363 type
511 tony 60
512 tony 363 { TQueryProcessor }
513 tony 315
514 tony 363 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 tony 371 if JournalingActive and (FJournalFilePath <> '') then
627 tony 363 begin
628     FreeAndNil(FJournalFileStream);
629 tony 371 if not (joNoServerTable in FOptions) and not RetainJournal then
630 tony 363 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 tony 371 if not (joNoServerTable in FOptions) then
654 tony 363 try
655 tony 387 FDoNotJournal := true;
656 tony 363 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 tony 371 GetAttachment.GetAttachmentID,
663 tony 363 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 tony 387 Completion: TTrCompletionState): boolean;
675 tony 363
676     var LogEntry: AnsiString;
677     begin
678     Result := false;
679 tony 387 case Completion of
680     trRolledback:
681 tony 363 begin
682 tony 371 LogEntry := Format(sTransRollbackJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
683     GetAttachment.GetAttachmentID,
684     FSessionID,TransactionID]);
685 tony 363 Result := true;
686     end;
687 tony 387
688     trRollbackFailed:
689 tony 363 begin
690 tony 387 LogEntry := Format(sTransRollbackFailJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
691     GetAttachment.GetAttachmentID,
692     FSessionID,TransactionID]);
693     Result := true;
694     end;
695    
696     trCommitted:
697     begin
698 tony 371 LogEntry := Format(sTransCommitJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
699     GetAttachment.GetAttachmentID,
700     FSessionID,TransactionID]);
701 tony 363 Result := true;
702     end;
703 tony 387
704     trCommitFailed:
705     begin
706     LogEntry := Format(sTransCommitFailJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
707     GetAttachment.GetAttachmentID,
708     FSessionID,TransactionID]);
709     Result := true;
710     end;
711 tony 363 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 tony 371 GetAttachment.GetAttachmentID,
724 tony 363 FSessionID,Tr.GetTransactionID,OldTransactionID]);
725     TARollbackRetaining:
726     LogEntry := Format(sTransRollbackRetJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
727 tony 371 GetAttachment.GetAttachmentID,
728 tony 363 FSessionID,Tr.GetTransactionID,OldTransactionID]);
729     end;
730     if assigned(FJournalFileStream) then
731     FJournalFileStream.Write(LogEntry[1],Length(LogEntry));
732    
733 tony 371 if not (joNoServerTable in FOptions) then
734 tony 363 try
735 tony 387 FDoNotJournal := true;
736 tony 363 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 tony 371 GetAttachment.GetAttachmentID,
749 tony 363 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 tony 387 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 tony 363 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 tony 371 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 tony 363 FOptions := Options;
797 tony 371 if not (joNoServerTable in FOptions) then
798 tony 363 with GetAttachment do
799     begin
800 tony 371 if not HasTable(sJournalTableName) then
801 tony 363 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 tony 371 FJournalFileStream := S;
808 tony 363 Result := FSessionID;
809     end;
810    
811     procedure TFBJournaling.StopJournaling(RetainJournal: boolean);
812     begin
813     EndSession(RetainJournal);
814     end;
815    
816 tony 45 { TFBAttachment }
817    
818 tony 375 procedure TFBAttachment.NeedConnectionInfo;
819     var Stmt: IStatement;
820 tony 117 ResultSet: IResultSet;
821     Param: IDPBItem;
822     begin
823 tony 375 if not IsConnected or FHasConnectionInfo then Exit;
824     NeedDBInfo;
825 tony 143 FCharSetID := 0;
826     FRemoteProtocol := '';
827     FAuthMethod := 'Legacy_Auth';
828 tony 209 FSecDatabase := 'Default';
829 tony 143 if FODSMajorVersion > 11 then
830 tony 117 begin
831     Stmt := Prepare(StartTransaction([isc_tpb_read,isc_tpb_nowait,isc_tpb_concurrency],taCommit),
832 tony 209 'Select MON$CHARACTER_SET_ID, MON$REMOTE_PROTOCOL, MON$AUTH_METHOD, MON$SEC_DATABASE From MON$ATTACHMENTS, MON$DATABASE '+
833 tony 315 'Where MON$ATTACHMENT_ID = CURRENT_CONNECTION ');
834 tony 143 ResultSet := Stmt.OpenCursor;
835     if ResultSet.FetchNext then
836     begin
837     FCharSetID := ResultSet[0].AsInteger;
838 tony 209 FRemoteProtocol := Trim(ResultSet[1].AsString);
839     FAuthMethod := Trim(ResultSet[2].AsString);
840     FSecDatabase := Trim(ResultSet[3].AsString);
841 tony 143 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 tony 117 '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 tony 209 FRemoteProtocol := Trim(ResultSet[1].AsString);
854 tony 117 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 tony 143 case GetProtocol(FDatabaseName) of
863     TCP: FRemoteProtocol := 'TCPv4';
864     Local: FRemoteProtocol := '';
865     NamedPipe: FRemoteProtocol := 'Netbui';
866     SPX: FRemoteProtocol := 'SPX'
867     end;
868 tony 117 end;
869     FHasDefaultCharSet := CharSetID2CodePage(FCharSetID,FCodePage) and (FCharSetID > 1);
870 tony 375 FHasConnectionInfo := true;
871 tony 117 end;
872    
873 tony 375 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 tony 263 constructor TFBAttachment.Create(api: TFBClientAPI; DatabaseName: AnsiString;
895     DPB: IDPB; RaiseExceptionOnConnectError: boolean);
896 tony 45 begin
897     inherited Create;
898 tony 263 FFirebirdAPI := api.GetAPI; {Keep reference to interface}
899 tony 45 FSQLDialect := 3;
900     FDatabaseName := DatabaseName;
901 tony 60 SetLength(FUserCharSetMap,0);
902 tony 375 ClearCachedInfo;
903 tony 345 FInlineBlobLimit := DefaultMaxInlineBlobLimit;
904 tony 371 FDPB := DPB;
905     FRaiseExceptionOnConnectError := RaiseExceptionOnConnectError;
906 tony 45 end;
907    
908 tony 375 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 tony 56 function TFBAttachment.GenerateCreateDatabaseSQL(DatabaseName: AnsiString; aDPB: IDPB): AnsiString;
923     var CreateParams: AnsiString;
924 tony 45 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 tony 56 CreateParams := CreateParams + ' USER ''' + DPBItem.AsString + '''';
933 tony 45
934     DPBItem := aDPB.Find(isc_dpb_password);
935     if DPBItem <> nil then
936 tony 56 CreateParams := CreateParams + ' Password ''' + DPBItem.AsString + '''';
937 tony 45
938     DPBItem := aDPB.Find(isc_dpb_page_size);
939     if DPBItem <> nil then
940 tony 56 CreateParams := CreateParams + ' PAGE_SIZE ' + DPBItem.AsString;
941 tony 45
942     DPBItem := aDPB.Find(isc_dpb_lc_ctype);
943     if DPBItem <> nil then
944 tony 56 CreateParams := CreateParams + ' DEFAULT CHARACTER SET ' + DPBItem.AsString;
945 tony 45
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 tony 118 {$IFDEF HASREQEX}
967 tony 117 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 tony 118 {$ELSE}
996     procedure TFBAttachment.DPBFromCreateSQL(CreateSQL: AnsiString);
997 tony 119 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 tony 118 end;
1003     {$ENDIF}
1004 tony 117
1005 tony 45 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 tony 70 vtInt64:
1018     SQLParams[i].AsInt64 := params[i].VInt64^;
1019     {$IF declared (vtQWord)}
1020     vtQWord:
1021     SQLParams[i].AsInt64 := params[i].VQWord^;
1022     {$IFEND}
1023 tony 45 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 tony 70 SQLParams[i].AsString := strpas(PChar(params[i].VString));
1033 tony 45 vtPChar :
1034     SQLParams[i].AsString := strpas(params[i].VPChar);
1035     vtAnsiString :
1036 tony 70 SQLParams[i].AsString := strpas(PAnsiChar(params[i].VAnsiString));
1037 tony 45 vtVariant:
1038     SQLParams[i].AsVariant := params[i].VVariant^;
1039 tony 70 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 tony 45 else
1048     IBError(ibxeInvalidVariantType,[nil]);
1049     end;
1050     end;
1051     end;
1052    
1053 tony 375 procedure TFBAttachment.SetSQLDialect(aValue: integer);
1054     begin
1055     FSQLDialect := aValue;
1056     end;
1057    
1058 tony 315 procedure TFBAttachment.UseServerICUChanged;
1059     begin
1060     // Do nothing by default
1061     end;
1062    
1063 tony 45 destructor TFBAttachment.Destroy;
1064     begin
1065     Disconnect(true);
1066     inherited Destroy;
1067     end;
1068    
1069 tony 375 procedure TFBAttachment.Disconnect(Force: boolean);
1070     begin
1071     inherited Disconnect(Force);
1072     ClearCachedInfo;
1073     end;
1074    
1075 tony 263 function TFBAttachment.getFirebirdAPI: IFirebirdAPI;
1076     begin
1077     Result := FFirebirdAPI;
1078     end;
1079    
1080 tony 45 function TFBAttachment.getDPB: IDPB;
1081     begin
1082     Result := FDPB;
1083     end;
1084    
1085     function TFBAttachment.AllocateBPB: IBPB;
1086     begin
1087 tony 263 Result := TBPB.Create(FFirebirdAPI as TFBClientAPI);
1088 tony 45 end;
1089    
1090 tony 143 function TFBAttachment.AllocateDIRB: IDIRB;
1091     begin
1092 tony 263 Result := TDIRB.Create(FFirebirdAPI as TFBClientAPI);
1093 tony 143 end;
1094    
1095 tony 56 procedure TFBAttachment.ExecImmediate(TPB: array of byte; sql: AnsiString;
1096 tony 45 aSQLDialect: integer);
1097 tony 387 var tr: ITransaction;
1098 tony 45 begin
1099 tony 387 tr := StartTransaction(TPB,taCommit);
1100     try
1101     ExecImmediate(tr,sql,aSQLDialect);
1102     except
1103     tr.Rollback(true);
1104     raise;
1105     end;
1106 tony 45 end;
1107    
1108 tony 56 procedure TFBAttachment.ExecImmediate(transaction: ITransaction; sql: AnsiString);
1109 tony 45 begin
1110     ExecImmediate(transaction,sql,FSQLDialect);
1111     end;
1112    
1113 tony 56 procedure TFBAttachment.ExecImmediate(TPB: array of byte; sql: AnsiString);
1114 tony 45 begin
1115 tony 387 ExecImmediate(TPB,sql,FSQLDialect);
1116 tony 45 end;
1117    
1118 tony 56 function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
1119 tony 45 SQLDialect: integer; params: array of const): IResults;
1120 tony 387 var tr: ITransaction;
1121 tony 45 begin
1122 tony 387 tr := StartTransaction(TPB,taCommit);
1123     try
1124     Result := ExecuteSQL(tr,sql,SQLDialect,params);
1125     except
1126     tr.Rollback(true);
1127     raise;
1128     end;
1129 tony 45 end;
1130    
1131 tony 56 function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
1132 tony 45 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 tony 56 function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
1142 tony 45 params: array of const): IResults;
1143     begin
1144 tony 387 Result := ExecuteSQL(TPB,sql,FSQLDialect,params);
1145 tony 45 end;
1146    
1147 tony 56 function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
1148 tony 45 params: array of const): IResults;
1149     begin
1150 tony 387 Result := ExecuteSQL(transaction,sql,FSQLDialect,params);
1151 tony 45 end;
1152    
1153 tony 56 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1154 tony 350 aSQLDialect: integer; Scrollable: boolean): IResultSet;
1155 tony 45 begin
1156 tony 350 Result := OpenCursor(transaction,sql,aSQLDialect,Scrollable,[]);
1157 tony 45 end;
1158    
1159 tony 56 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1160 tony 45 aSQLDialect: integer; params: array of const): IResultSet;
1161 tony 350
1162 tony 45 begin
1163 tony 350 Result := OpenCursor(transaction,sql,FSQLDialect,false,params);
1164 tony 45 end;
1165    
1166 tony 350 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1167     Scrollable: boolean): IResultSet;
1168 tony 45 begin
1169 tony 350 Result := OpenCursor(transaction,sql,FSQLDialect,Scrollable,[]);
1170 tony 45 end;
1171    
1172 tony 56 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
1173 tony 45 params: array of const): IResultSet;
1174     begin
1175 tony 350 Result := OpenCursor(transaction,sql,FSQLDialect,false,params);
1176 tony 45 end;
1177    
1178 tony 350 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 tony 45 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1196 tony 350 sql: AnsiString; aSQLDialect: integer; Scrollable: boolean): IResultSet;
1197 tony 45 begin
1198 tony 350 Result := OpenCursor(transaction,sql,aSQLDialect,Scrollable,[]);
1199 tony 45 Result.FetchNext;
1200     end;
1201    
1202     function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1203 tony 56 sql: AnsiString; aSQLDialect: integer; params: array of const): IResultSet;
1204 tony 45 begin
1205     Result := OpenCursor(transaction,sql,aSQLDialect,params);
1206     Result.FetchNext;
1207     end;
1208    
1209 tony 350 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1210     sql: AnsiString; aSQLDialect: integer; Scrollable: boolean;
1211     params: array of const): IResultSet;
1212 tony 45 begin
1213 tony 350 Result := OpenCursor(transaction,sql,aSQLDialect,Scrollable,params);
1214     Result.FetchNext;
1215 tony 45 end;
1216    
1217     function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1218 tony 350 sql: AnsiString; Scrollable: boolean): IResultSet;
1219     begin
1220     Result := OpenCursorAtStart(transaction,sql,FSQLDialect,Scrollable,[]);
1221     end;
1222    
1223     function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1224 tony 56 sql: AnsiString; params: array of const): IResultSet;
1225 tony 45 begin
1226     Result := OpenCursorAtStart(transaction,sql,FSQLDialect,params);
1227     end;
1228    
1229 tony 350 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
1230     sql: AnsiString; Scrollable: boolean; params: array of const): IResultSet;
1231 tony 45 begin
1232 tony 350 Result := OpenCursorAtStart(transaction,sql,FSQLDialect,Scrollable,params);
1233 tony 45 end;
1234    
1235 tony 350 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 tony 387 var tr: ITransaction;
1244 tony 350 begin
1245 tony 387 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 tony 350 end;
1253    
1254 tony 56 function TFBAttachment.OpenCursorAtStart(sql: AnsiString;
1255 tony 45 params: array of const): IResultSet;
1256     begin
1257 tony 387 Result := OpenCursorAtStart(sql,false,params);
1258 tony 45 end;
1259    
1260 tony 350 function TFBAttachment.Prepare(transaction: ITransaction; sql: AnsiString;
1261     CursorName: AnsiString): IStatement;
1262 tony 45 begin
1263 tony 350 Result := Prepare(transaction,sql,FSQLDialect,CursorName);
1264 tony 45 end;
1265    
1266     function TFBAttachment.PrepareWithNamedParameters(transaction: ITransaction;
1267 tony 350 sql: AnsiString; GenerateParamNames: boolean; CaseSensitiveParams: boolean;
1268     CursorName: AnsiString): IStatement;
1269 tony 45 begin
1270 tony 350 Result := PrepareWithNamedParameters(transaction,sql,FSQLDialect,GenerateParamNames,CaseSensitiveParams,CursorName);
1271 tony 45 end;
1272    
1273 tony 56 function TFBAttachment.GetEventHandler(Event: AnsiString): IEvents;
1274 tony 45 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 tony 375 NeedDBInfo;
1288 tony 45 Result := FSQLDialect;
1289     end;
1290    
1291 tony 371 function TFBAttachment.GetAttachmentID: integer;
1292     begin
1293 tony 375 NeedDBInfo;
1294 tony 371 Result := FAttachmentID;
1295     end;
1296    
1297 tony 291 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 tony 45 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 tony 291 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 tony 143 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 tony 117 function TFBAttachment.GetConnectString: AnsiString;
1367     begin
1368     Result := FDatabaseName;
1369     end;
1370    
1371     function TFBAttachment.GetRemoteProtocol: AnsiString;
1372     begin
1373 tony 375 NeedConnectionInfo;
1374 tony 117 Result := FRemoteProtocol;
1375     end;
1376    
1377 tony 143 function TFBAttachment.GetAuthenticationMethod: AnsiString;
1378     begin
1379 tony 375 NeedConnectionInfo;
1380 tony 143 Result := FAuthMethod;
1381     end;
1382    
1383 tony 209 function TFBAttachment.GetSecurityDatabase: AnsiString;
1384     begin
1385 tony 375 NeedConnectionInfo;
1386 tony 209 Result := FSecDatabase;
1387     end;
1388    
1389 tony 117 function TFBAttachment.GetODSMajorVersion: integer;
1390     begin
1391 tony 375 NeedDBInfo;
1392 tony 117 Result := FODSMajorVersion;
1393     end;
1394    
1395     function TFBAttachment.GetODSMinorVersion: integer;
1396     begin
1397 tony 375 NeedDBInfo;
1398 tony 117 Result := FODSMinorVersion;
1399     end;
1400    
1401 tony 371 function TFBAttachment.GetCharSetID: integer;
1402     begin
1403 tony 375 NeedConnectionInfo;
1404 tony 371 Result := FCharSetID;
1405     end;
1406    
1407 tony 315 function TFBAttachment.HasDecFloatSupport: boolean;
1408     begin
1409     Result := false;
1410     end;
1411    
1412 tony 345 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 tony 363 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 tony 371 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 tony 109 function TFBAttachment.HasDefaultCharSet: boolean;
1452     begin
1453 tony 375 NeedConnectionInfo;
1454 tony 109 Result := FHasDefaultCharSet
1455     end;
1456    
1457     function TFBAttachment.GetDefaultCharSetID: integer;
1458     begin
1459 tony 375 NeedConnectionInfo;
1460 tony 109 Result := FCharsetID;
1461     end;
1462    
1463 tony 60 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 tony 233 if AnsiCompareText(CharSetMap[i].CharSetName, CharSetName) = 0 then
1533 tony 60 begin
1534     CharSetID := CharSetMap[i].CharSetID;
1535     Result := true;
1536     Exit;
1537     end;
1538    
1539     for i := 0 to Length(FUserCharSetMap) - 1 do
1540 tony 233 if AnsiCompareText(FUserCharSetMap[i].CharSetName, CharSetName) = 0 then
1541 tony 60 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 tony 315 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 tony 345 function TDPB.GetParamTypeName(ParamType: byte): Ansistring;
1624 tony 315 begin
1625     if ParamType <= isc_dpb_last_dpb_constant then
1626     Result := DPBConstantNames[ParamType]
1627     else
1628     Result := '';
1629     end;
1630    
1631 tony 345 {$IFNDEF FPC}
1632     function TDPB.GetDPBParamTypeName(ParamType: byte): Ansistring;
1633     begin
1634     Result := GetParamTypeName(ParamType);
1635     end;
1636     {$ENDIF}
1637    
1638 tony 315 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 tony 45 end.
1655    

Properties

Name Value
svn:eol-style native