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

File Contents

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

Properties

Name Value
svn:eol-style native