ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBAttachment.pas
Revision: 263
Committed: Thu Dec 6 15:55:01 2018 UTC (5 years, 4 months ago) by tony
Content type: text/x-pascal
File size: 32635 byte(s)
Log Message:
Release 2.3.2 committed

File Contents

# Content
1 (*
2 * Firebird Interface (fbintf). The fbintf components provide a set of
3 * Pascal language bindings for the Firebird API.
4 *
5 * The contents of this file are subject to the Initial Developer's
6 * Public License Version 1.0 (the "License"); you may not use this
7 * file except in compliance with the License. You may obtain a copy
8 * of the License here:
9 *
10 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11 *
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing rights
15 * and limitations under the License.
16 *
17 * The Initial Developer of the Original Code is Tony Whyman.
18 *
19 * The Original Code is (C) 2016 Tony Whyman, MWA Software
20 * (http://www.mwasoftware.co.uk).
21 *
22 * All Rights Reserved.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 *)
27 unit FBAttachment;
28 {$IFDEF MSWINDOWS}
29 {$DEFINE WINDOWS}
30 {$ENDIF}
31
32 {$IFDEF FPC}
33 {$mode delphi}
34 {$interfaces COM}
35 {$define HASREQEX}
36 {$ENDIF}
37
38 interface
39
40 uses
41 Classes, SysUtils, {$IFDEF WINDOWS} windows, {$ENDIF} IB, FBParamBlock,
42 FBActivityMonitor, FBClientAPI;
43
44 type
45 TCharsetMap = record
46 CharsetID: integer;
47 CharSetName: AnsiString;
48 CharSetWidth: integer;
49 CodePage: TSystemCodePage;
50 AllowReverseLookup: boolean; {used to ensure that lookup of CP_UTF* does not return UNICODE_FSS}
51 end;
52
53 { TFBAttachment }
54
55 TFBAttachment = class(TActivityHandler)
56 private
57 FDPB: IDPB;
58 FFirebirdAPI: IFirebirdAPI;
59 FODSMajorVersion: integer;
60 FODSMinorVersion: integer;
61 FUserCharSetMap: array of TCharSetMap;
62 FSecDatabase: AnsiString;
63 protected
64 FDatabaseName: AnsiString;
65 FRaiseExceptionOnConnectError: boolean;
66 FSQLDialect: integer;
67 FHasDefaultCharSet: boolean;
68 FCharSetID: integer;
69 FCodePage: TSystemCodePage;
70 FRemoteProtocol: AnsiString;
71 FAuthMethod: AnsiString;
72 constructor Create(api: TFBClientAPI; DatabaseName: AnsiString; DPB: IDPB;
73 RaiseExceptionOnConnectError: boolean);
74 procedure CheckHandle; virtual; abstract;
75 function GenerateCreateDatabaseSQL(DatabaseName: AnsiString; aDPB: IDPB): AnsiString;
76 procedure GetODSAndConnectionInfo;
77 function GetDBInfo(ReqBuffer: PByte; ReqBufLen: integer): IDBInformation; virtual; abstract;
78 function IsConnected: boolean; virtual; abstract;
79 procedure EndAllTransactions;
80 procedure DPBFromCreateSQL(CreateSQL: AnsiString);
81 procedure SetParameters(SQLParams: ISQLParams; params: array of const);
82 public
83 destructor Destroy; override;
84 function getFirebirdAPI: IFirebirdAPI;
85 function getDPB: IDPB;
86 function AllocateBPB: IBPB;
87 function AllocateDIRB: IDIRB;
88 function StartTransaction(TPB: array of byte; DefaultCompletion: TTransactionCompletion): ITransaction; overload; virtual; abstract;
89 function StartTransaction(TPB: ITPB; DefaultCompletion: TTransactionCompletion): ITransaction; overload; virtual; abstract;
90 procedure Disconnect(Force: boolean=false); virtual; abstract;
91 procedure ExecImmediate(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer); overload; virtual; abstract;
92 procedure ExecImmediate(TPB: array of byte; sql: AnsiString; aSQLDialect: integer); overload;
93 procedure ExecImmediate(transaction: ITransaction; sql: AnsiString); overload;
94 procedure ExecImmediate(TPB: array of byte; sql: AnsiString); overload;
95 function ExecuteSQL(TPB: array of byte; sql: AnsiString; SQLDialect: integer; params: array of const): IResults; overload;
96 function ExecuteSQL(transaction: ITransaction; sql: AnsiString; SQLDialect: integer; params: array of const): IResults; overload;
97 function ExecuteSQL(TPB: array of byte; sql: AnsiString; params: array of const): IResults; overload;
98 function ExecuteSQL(transaction: ITransaction; sql: AnsiString; params: array of const): IResults; overload;
99 function OpenCursor(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer): IResultSet; overload;
100 function OpenCursor(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
101 params: array of const): IResultSet; overload;
102 function OpenCursor(transaction: ITransaction; sql: AnsiString): IResultSet; overload;
103 function OpenCursor(transaction: ITransaction; sql: AnsiString;
104 params: array of const): IResultSet; overload;
105 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer): IResultSet; overload;
106 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
107 params: array of const): IResultSet; overload;
108 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString): IResultSet; overload;
109 function OpenCursorAtStart(transaction: ITransaction; sql: AnsiString;
110 params: array of const): IResultSet; overload;
111 function OpenCursorAtStart(sql: AnsiString): IResultSet; overload;
112 function OpenCursorAtStart(sql: AnsiString;
113 params: array of const): IResultSet; overload;
114 function Prepare(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer): IStatement; overload; virtual; abstract;
115 function Prepare(transaction: ITransaction; sql: AnsiString): IStatement; overload;
116 function PrepareWithNamedParameters(transaction: ITransaction; sql: AnsiString;
117 aSQLDialect: integer; GenerateParamNames: boolean=false): IStatement; overload; virtual; abstract;
118 function PrepareWithNamedParameters(transaction: ITransaction; sql: AnsiString;
119 GenerateParamNames: boolean=false): IStatement; overload;
120 function GetEventHandler(Events: TStrings): IEvents; overload; virtual; abstract;
121 function GetEventHandler(Event: AnsiString): IEvents; overload;
122
123 function GetSQLDialect: integer;
124 function OpenBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB=nil): IBlob; overload; virtual; abstract;
125 function OpenBlob(transaction: ITransaction; Field: ISQLData; BPB: IBPB=nil): IBlob; overload;
126 property SQLDialect: integer read FSQLDialect;
127 property DPB: IDPB read FDPB;
128 public
129 function GetDBInformation(Requests: array of byte): IDBInformation; overload;
130 function GetDBInformation(Request: byte): IDBInformation; overload;
131 function GetDBInformation(Requests: IDIRB): IDBInformation; overload;
132 function GetConnectString: AnsiString;
133 function GetRemoteProtocol: AnsiString;
134 function GetAuthenticationMethod: AnsiString;
135 function GetSecurityDatabase: AnsiString;
136 function GetODSMajorVersion: integer;
137 function GetODSMinorVersion: integer;
138 {Character Sets}
139 function HasDefaultCharSet: boolean;
140 function GetDefaultCharSetID: integer;
141 function GetCharsetName(CharSetID: integer): AnsiString;
142 function CharSetID2CodePage(CharSetID: integer; var CodePage: TSystemCodePage): boolean;
143 function CodePage2CharSetID(CodePage: TSystemCodePage; var CharSetID: integer): boolean;
144 function CharSetName2CharSetID(CharSetName: AnsiString; var CharSetID: integer): boolean;
145 function CharSetWidth(CharSetID: integer; var Width: integer): boolean;
146 procedure RegisterCharSet(CharSetName: AnsiString; CodePage: TSystemCodePage;
147 AllowReverseLookup:boolean; out CharSetID: integer);
148 property CharSetID: integer read FCharSetID;
149 property CodePage: TSystemCodePage read FCodePage;
150 end;
151
152 implementation
153
154 uses FBMessages, IBUtils, FBTransaction {$IFDEF HASREQEX}, RegExpr{$ENDIF};
155
156 const
157 CharSetMap: array [0..69] of TCharsetMap = (
158 (CharsetID: 0; CharSetName: 'NONE'; CharSetWidth: 1; CodePage: CP_ACP; AllowReverseLookup: true),
159 (CharsetID: 1; CharSetName: 'OCTETS'; CharSetWidth: 1; CodePage: CP_NONE; AllowReverseLookup: true),
160 (CharsetID: 2; CharSetName: 'ASCII'; CharSetWidth: 1; CodePage: CP_ASCII; AllowReverseLookup: true),
161 (CharsetID: 3; CharSetName: 'UNICODE_FSS'; CharSetWidth: 3; CodePage: CP_UTF8; AllowReverseLookup: false),
162 (CharsetID: 4; CharSetName: 'UTF8'; CharSetWidth: 4; CodePage: CP_UTF8; AllowReverseLookup: true),
163 (CharsetID: 5; CharSetName: 'SJIS_0208'; CharSetWidth: 2; CodePage: 20932; AllowReverseLookup: true),
164 (CharsetID: 6; CharSetName: 'EUCJ_0208'; CharSetWidth: 2; CodePage: 20932; AllowReverseLookup: true),
165 (CharsetID: 7; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: true),
166 (CharsetID: 8; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: true),
167 (CharsetID: 9; CharSetName: 'DOS737'; CharSetWidth: 1; CodePage: 737; AllowReverseLookup: true),
168 (CharsetID: 10; CharSetName: 'DOS437'; CharSetWidth: 1; CodePage: 437; AllowReverseLookup: true),
169 (CharsetID: 11; CharSetName: 'DOS850'; CharSetWidth: 1; CodePage: 850; AllowReverseLookup: true),
170 (CharsetID: 12; CharSetName: 'DOS865'; CharSetWidth: 1; CodePage: 865; AllowReverseLookup: true),
171 (CharsetID: 13; CharSetName: 'DOS860'; CharSetWidth: 1; CodePage: 860; AllowReverseLookup: true),
172 (CharsetID: 14; CharSetName: 'DOS863'; CharSetWidth: 1; CodePage: 863; AllowReverseLookup: true),
173 (CharsetID: 15; CharSetName: 'DOS775'; CharSetWidth: 1; CodePage: 775; AllowReverseLookup: true),
174 (CharsetID: 16; CharSetName: 'DOS858'; CharSetWidth: 1; CodePage: 858; AllowReverseLookup: true),
175 (CharsetID: 17; CharSetName: 'DOS862'; CharSetWidth: 1; CodePage: 862; AllowReverseLookup: true),
176 (CharsetID: 18; CharSetName: 'DOS864'; CharSetWidth: 1; CodePage: 864; AllowReverseLookup: true),
177 (CharsetID: 19; CharSetName: 'NEXT'; CharSetWidth: 1; CodePage: CP_NONE; AllowReverseLookup: true),
178 (CharsetID: 20; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: true),
179 (CharsetID: 21; CharSetName: 'ISO8859_1'; CharSetWidth: 1; CodePage: 28591; AllowReverseLookup: true),
180 (CharsetID: 22; CharSetName: 'ISO8859_2'; CharSetWidth: 1; CodePage: 28592; AllowReverseLookup: true),
181 (CharsetID: 23; CharSetName: 'ISO8859_3'; CharSetWidth: 1; CodePage: 28593; AllowReverseLookup: true),
182 (CharsetID: 24; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
183 (CharsetID: 25; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
184 (CharsetID: 26; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
185 (CharsetID: 27; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
186 (CharsetID: 28; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
187 (CharsetID: 29; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
188 (CharsetID: 30; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
189 (CharsetID: 31; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
190 (CharsetID: 32; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
191 (CharsetID: 33; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
192 (CharsetID: 34; CharSetName: 'ISO8859_4'; CharSetWidth: 1; CodePage: 28594; AllowReverseLookup: true),
193 (CharsetID: 35; CharSetName: 'ISO8859_5'; CharSetWidth: 1; CodePage: 28595; AllowReverseLookup: true),
194 (CharsetID: 36; CharSetName: 'ISO8859_6'; CharSetWidth: 1; CodePage: 28596; AllowReverseLookup: true),
195 (CharsetID: 37; CharSetName: 'ISO8859_7'; CharSetWidth: 1; CodePage: 28597; AllowReverseLookup: true),
196 (CharsetID: 38; CharSetName: 'ISO8859_8'; CharSetWidth: 1; CodePage: 28598; AllowReverseLookup: true),
197 (CharsetID: 39; CharSetName: 'ISO8859_9'; CharSetWidth: 1; CodePage: 28599; AllowReverseLookup: true),
198 (CharsetID: 40; CharSetName: 'ISO8859_13'; CharSetWidth: 1; CodePage: 28603; AllowReverseLookup: true),
199 (CharsetID: 41; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
200 (CharsetID: 42; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
201 (CharsetID: 43; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
202 (CharsetID: 44; CharSetName: 'KSC_5601'; CharSetWidth: 2; CodePage: 949; AllowReverseLookup: true),
203 (CharsetID: 45; CharSetName: 'DOS852'; CharSetWidth: 1; CodePage: 852; AllowReverseLookup: true),
204 (CharsetID: 46; CharSetName: 'DOS857'; CharSetWidth: 1; CodePage: 857; AllowReverseLookup: true),
205 (CharsetID: 47; CharSetName: 'DOS861'; CharSetWidth: 1; CodePage: 861; AllowReverseLookup: true),
206 (CharsetID: 48; CharSetName: 'DOS866'; CharSetWidth: 1; CodePage: 866; AllowReverseLookup: true),
207 (CharsetID: 49; CharSetName: 'DOS869'; CharSetWidth: 1; CodePage: 869; AllowReverseLookup: true),
208 (CharsetID: 50; CharSetName: 'CYRL'; CharSetWidth: 1; CodePage: 1251; AllowReverseLookup: true),
209 (CharsetID: 51; CharSetName: 'WIN1250'; CharSetWidth: 1; CodePage: 1250; AllowReverseLookup: true),
210 (CharsetID: 52; CharSetName: 'WIN1251'; CharSetWidth: 1; CodePage: 1251; AllowReverseLookup: true),
211 (CharsetID: 53; CharSetName: 'WIN1252'; CharSetWidth: 1; CodePage: 1252; AllowReverseLookup: true),
212 (CharsetID: 54; CharSetName: 'WIN1253'; CharSetWidth: 1; CodePage: 1253; AllowReverseLookup: true),
213 (CharsetID: 55; CharSetName: 'WIN1254'; CharSetWidth: 1; CodePage: 1254; AllowReverseLookup: true),
214 (CharsetID: 56; CharSetName: 'BIG_5'; CharSetWidth: 2; CodePage: 950; AllowReverseLookup: true),
215 (CharsetID: 57; CharSetName: 'GB_2312'; CharSetWidth: 2; CodePage: 936; AllowReverseLookup: true),
216 (CharsetID: 58; CharSetName: 'WIN1255'; CharSetWidth: 1; CodePage: 1255; AllowReverseLookup: true),
217 (CharsetID: 59; CharSetName: 'WIN1256'; CharSetWidth: 1; CodePage: 1256; AllowReverseLookup: true),
218 (CharsetID: 60; CharSetName: 'WIN1257'; CharSetWidth: 1; CodePage: 1257; AllowReverseLookup: true),
219 (CharsetID: 61; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
220 (CharsetID: 62; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE; AllowReverseLookup: false),
221 (CharsetID: 63; CharSetName: 'KOI8R'; CharSetWidth: 1; CodePage: 20866; AllowReverseLookup: true),
222 (CharsetID: 64; CharSetName: 'KOI8U'; CharSetWidth: 1; CodePage: 21866; AllowReverseLookup: true),
223 (CharsetID: 65; CharSetName: 'WIN1258'; CharSetWidth: 1; CodePage: 1258; AllowReverseLookup: true),
224 (CharsetID: 66; CharSetName: 'TIS620'; CharSetWidth: 1; CodePage: 874; AllowReverseLookup: true),
225 (CharsetID: 67; CharSetName: 'GBK'; CharSetWidth: 2; CodePage: 936; AllowReverseLookup: true),
226 (CharsetID: 68; CharSetName: 'CP943C'; CharSetWidth: 2; CodePage: 943; AllowReverseLookup: true),
227 (CharsetID: 69; CharSetName: 'GB18030'; CharSetWidth: 4; CodePage: 54936; AllowReverseLookup: true)
228 );
229
230
231
232
233 { TFBAttachment }
234
235 procedure TFBAttachment.GetODSAndConnectionInfo;
236 var DBInfo: IDBInformation;
237 i: integer;
238 Stmt: IStatement;
239 ResultSet: IResultSet;
240 Param: IDPBItem;
241 begin
242 if not IsConnected then Exit;
243 DBInfo := GetDBInformation([isc_info_db_id,isc_info_ods_version,isc_info_ods_minor_version,
244 isc_info_db_SQL_Dialect]);
245 for i := 0 to DBInfo.GetCount - 1 do
246 with DBInfo[i] do
247 case getItemType of
248 isc_info_ods_minor_version:
249 FODSMinorVersion := getAsInteger;
250 isc_info_ods_version:
251 FODSMajorVersion := getAsInteger;
252 isc_info_db_SQL_Dialect:
253 FSQLDialect := getAsInteger;
254 end;
255
256 FCharSetID := 0;
257 FRemoteProtocol := '';
258 FAuthMethod := 'Legacy_Auth';
259 FSecDatabase := 'Default';
260 if FODSMajorVersion > 11 then
261 begin
262 Stmt := Prepare(StartTransaction([isc_tpb_read,isc_tpb_nowait,isc_tpb_concurrency],taCommit),
263 'Select MON$CHARACTER_SET_ID, MON$REMOTE_PROTOCOL, MON$AUTH_METHOD, MON$SEC_DATABASE From MON$ATTACHMENTS, MON$DATABASE '+
264 'Where MON$ATTACHMENT_ID = CURRENT_CONNECTION');
265 ResultSet := Stmt.OpenCursor;
266 if ResultSet.FetchNext then
267 begin
268 FCharSetID := ResultSet[0].AsInteger;
269 FRemoteProtocol := Trim(ResultSet[1].AsString);
270 FAuthMethod := Trim(ResultSet[2].AsString);
271 FSecDatabase := Trim(ResultSet[3].AsString);
272 end
273 end
274 else
275 if (FODSMajorVersion = 11) and (FODSMinorVersion >= 1) then
276 begin
277 Stmt := Prepare(StartTransaction([isc_tpb_read,isc_tpb_nowait,isc_tpb_concurrency],taCommit),
278 'Select MON$CHARACTER_SET_ID, MON$REMOTE_PROTOCOL From MON$ATTACHMENTS '+
279 'Where MON$ATTACHMENT_ID = CURRENT_CONNECTION');
280 ResultSet := Stmt.OpenCursor;
281 if ResultSet.FetchNext then
282 begin
283 FCharSetID := ResultSet[0].AsInteger;
284 FRemoteProtocol := Trim(ResultSet[1].AsString);
285 end
286 end
287 else
288 if DPB <> nil then
289 begin
290 Param := DPB.Find(isc_dpb_lc_ctype);
291 if (Param = nil) or not CharSetName2CharSetID(Param.AsString,FCharSetID) then
292 FCharSetID := 0;
293 case GetProtocol(FDatabaseName) of
294 TCP: FRemoteProtocol := 'TCPv4';
295 Local: FRemoteProtocol := '';
296 NamedPipe: FRemoteProtocol := 'Netbui';
297 SPX: FRemoteProtocol := 'SPX'
298 end;
299 end;
300 FHasDefaultCharSet := CharSetID2CodePage(FCharSetID,FCodePage) and (FCharSetID > 1);
301 end;
302
303 constructor TFBAttachment.Create(api: TFBClientAPI; DatabaseName: AnsiString;
304 DPB: IDPB; RaiseExceptionOnConnectError: boolean);
305 begin
306 inherited Create;
307 FFirebirdAPI := api.GetAPI; {Keep reference to interface}
308 FSQLDialect := 3;
309 FDatabaseName := DatabaseName;
310 FDPB := DPB;
311 SetLength(FUserCharSetMap,0);
312 FRaiseExceptionOnConnectError := RaiseExceptionOnConnectError;
313 FODSMajorVersion := 0;
314 FODSMinorVersion := 0;
315 end;
316
317 function TFBAttachment.GenerateCreateDatabaseSQL(DatabaseName: AnsiString; aDPB: IDPB): AnsiString;
318 var CreateParams: AnsiString;
319 DPBItem: IDPBItem;
320 begin
321 CreateParams := '';
322
323 if aDPB <> nil then
324 begin
325 DPBItem := aDPB.Find(isc_dpb_user_name);
326 if DPBItem <> nil then
327 CreateParams := CreateParams + ' USER ''' + DPBItem.AsString + '''';
328
329 DPBItem := aDPB.Find(isc_dpb_password);
330 if DPBItem <> nil then
331 CreateParams := CreateParams + ' Password ''' + DPBItem.AsString + '''';
332
333 DPBItem := aDPB.Find(isc_dpb_page_size);
334 if DPBItem <> nil then
335 CreateParams := CreateParams + ' PAGE_SIZE ' + DPBItem.AsString;
336
337 DPBItem := aDPB.Find(isc_dpb_lc_ctype);
338 if DPBItem <> nil then
339 CreateParams := CreateParams + ' DEFAULT CHARACTER SET ' + DPBItem.AsString;
340
341 DPBItem := aDPB.Find(isc_dpb_sql_dialect);
342 if DPBItem <> nil then
343 FSQLDialect := DPBItem.AsInteger;
344 end;
345
346 Result := 'CREATE DATABASE ''' + DatabaseName + ''' ' + CreateParams; {do not localize}
347 end;
348
349 procedure TFBAttachment.EndAllTransactions;
350 var i: integer;
351 intf: TInterfacedObject;
352 begin
353 for i := 0 to InterfaceCount - 1 do
354 begin
355 intf := GetInterface(i);
356 if (intf <> nil) and (intf is TFBTransaction) then
357 TFBTransaction(intf).DoDefaultTransactionEnd(true);
358 end;
359 end;
360
361 {$IFDEF HASREQEX}
362 procedure TFBAttachment.DPBFromCreateSQL(CreateSQL: AnsiString);
363 var RegexObj: TRegExpr;
364 begin
365 FDPB := FFirebirdAPI.AllocateDPB;
366 RegexObj := TRegExpr.Create;
367 try
368 {extact database file spec}
369 RegexObj.ModifierG := false; {turn off greedy matches}
370 RegexObj.ModifierI := true; {case insensitive match}
371 RegexObj.Expression := '^ *CREATE +(DATABASE|SCHEMA) +''.*'' +USER +''(.+)'' PASSWORD +''(.+)''';
372 if RegexObj.Exec(CreateSQL) then
373 begin
374 DPB.Add(isc_dpb_user_name).AsString := system.copy(CreateSQL,RegexObj.MatchPos[2],RegexObj.MatchLen[2]);
375 DPB.Add(isc_dpb_password).AsString := system.copy(CreateSQL,RegexObj.MatchPos[3],RegexObj.MatchLen[3]);
376 end
377 else
378 begin
379 RegexObj.Expression := '^ *CREATE +(DATABASE|SCHEMA) +(''.*'') +USER +''(.+)''';
380 if RegexObj.Exec(CreateSQL) then
381 DPB.Add(isc_dpb_user_name).AsString := system.copy(CreateSQL,RegexObj.MatchPos[2],RegexObj.MatchLen[2]);
382 end;
383 finally
384 RegexObj.Free;
385 end;
386 if FCharSetID > 0 then
387 DPB.Add(isc_dpb_lc_ctype).AsString := GetCharSetName(FCharSetID);
388 DPB.Add(isc_dpb_set_db_SQL_dialect).setAsByte(FSQLDialect);
389 end;
390 {$ELSE}
391 procedure TFBAttachment.DPBFromCreateSQL(CreateSQL: AnsiString);
392 begin
393 FDPB := FFirebirdAPI.AllocateDPB;
394 if FCharSetID > 0 then
395 DPB.Add(isc_dpb_lc_ctype).AsString := GetCharSetName(FCharSetID);
396 DPB.Add(isc_dpb_set_db_SQL_dialect).setAsByte(FSQLDialect);
397 end;
398 {$ENDIF}
399
400 procedure TFBAttachment.SetParameters(SQLParams: ISQLParams;
401 params: array of const);
402 var i: integer;
403 begin
404 if SQLParams.Count <> Length(params) then
405 IBError(ibxeInvalidParamCount,[SQLParams.Count,Length(params)]);
406
407 for i := 0 to High(params) do
408 begin
409 case params[i].vtype of
410 vtinteger :
411 SQLParams[i].AsInteger := params[i].vinteger;
412 vtInt64:
413 SQLParams[i].AsInt64 := params[i].VInt64^;
414 {$IF declared (vtQWord)}
415 vtQWord:
416 SQLParams[i].AsInt64 := params[i].VQWord^;
417 {$IFEND}
418 vtboolean :
419 SQLParams[i].AsBoolean := params[i].vboolean;
420 vtchar :
421 SQLParams[i].AsString := params[i].vchar;
422 vtextended :
423 SQLParams[i].AsDouble := params[i].VExtended^;
424 vtCurrency:
425 SQLParams[i].AsDouble := params[i].VCurrency^;
426 vtString :
427 SQLParams[i].AsString := strpas(PChar(params[i].VString));
428 vtPChar :
429 SQLParams[i].AsString := strpas(params[i].VPChar);
430 vtAnsiString :
431 SQLParams[i].AsString := strpas(PAnsiChar(params[i].VAnsiString));
432 vtVariant:
433 SQLParams[i].AsVariant := params[i].VVariant^;
434 vtWideChar:
435 SQLParams[i].AsString := UTF8Encode(WideCharLenToString(@params[i].VWideChar,1));
436 vtPWideChar:
437 SQLParams[i].AsString := UTF8Encode(strpas(PWideChar(params[i].VPWideChar)));
438 vtWideString:
439 SQLParams[i].AsString := UTF8Encode(strpas(PWideChar(params[i].VWideString)));
440 vtUnicodeString:
441 SQLParams[i].AsString := UTF8Encode(strpas(PWideChar(params[i].VUnicodeString)));
442 else
443 IBError(ibxeInvalidVariantType,[nil]);
444 end;
445 end;
446 end;
447
448 destructor TFBAttachment.Destroy;
449 begin
450 Disconnect(true);
451 inherited Destroy;
452 end;
453
454 function TFBAttachment.getFirebirdAPI: IFirebirdAPI;
455 begin
456 Result := FFirebirdAPI;
457 end;
458
459 function TFBAttachment.getDPB: IDPB;
460 begin
461 Result := FDPB;
462 end;
463
464 function TFBAttachment.AllocateBPB: IBPB;
465 begin
466 Result := TBPB.Create(FFirebirdAPI as TFBClientAPI);
467 end;
468
469 function TFBAttachment.AllocateDIRB: IDIRB;
470 begin
471 Result := TDIRB.Create(FFirebirdAPI as TFBClientAPI);
472 end;
473
474 procedure TFBAttachment.ExecImmediate(TPB: array of byte; sql: AnsiString;
475 aSQLDialect: integer);
476 begin
477 ExecImmediate(StartTransaction(TPB,taCommit),sql,aSQLDialect);
478 end;
479
480 procedure TFBAttachment.ExecImmediate(transaction: ITransaction; sql: AnsiString);
481 begin
482 ExecImmediate(transaction,sql,FSQLDialect);
483 end;
484
485 procedure TFBAttachment.ExecImmediate(TPB: array of byte; sql: AnsiString);
486 begin
487 ExecImmediate(StartTransaction(TPB,taCommit),sql,FSQLDialect);
488 end;
489
490 function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
491 SQLDialect: integer; params: array of const): IResults;
492 begin
493 Result := ExecuteSQL(StartTransaction(TPB,taCommit),sql,SQLDialect,params);
494 end;
495
496 function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
497 SQLDialect: integer; params: array of const): IResults;
498 begin
499 with Prepare(transaction,sql,SQLDialect) do
500 begin
501 SetParameters(SQLParams,params);
502 Result := Execute;
503 end;
504 end;
505
506 function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
507 params: array of const): IResults;
508 begin
509 Result := ExecuteSQL(StartTransaction(TPB,taCommit),sql,params);
510 end;
511
512 function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
513 params: array of const): IResults;
514 begin
515 with Prepare(transaction,sql,FSQLDialect) do
516 begin
517 SetParameters(SQLParams,params);
518 Result := Execute;
519 end;
520 end;
521
522 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
523 aSQLDialect: integer): IResultSet;
524 begin
525 Result := OpenCursor(transaction,sql,aSQLDialect,[]);
526 end;
527
528 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
529 aSQLDialect: integer; params: array of const): IResultSet;
530 var Statement: IStatement;
531 begin
532 CheckHandle;
533 Statement := Prepare(transaction,sql,aSQLDialect);
534 SetParameters(Statement.SQLParams,params);
535 Result := Statement.OpenCursor;
536 end;
537
538 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString
539 ): IResultSet;
540 begin
541 Result := OpenCursor(transaction,sql,FSQLDialect,[]);
542 end;
543
544 function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
545 params: array of const): IResultSet;
546 begin
547 Result := OpenCursor(transaction,sql,FSQLDialect,params);
548 end;
549
550 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
551 sql: AnsiString; aSQLDialect: integer): IResultSet;
552 begin
553 Result := OpenCursor(transaction,sql,aSQLDialect,[]);
554 Result.FetchNext;
555 end;
556
557 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
558 sql: AnsiString; aSQLDialect: integer; params: array of const): IResultSet;
559 begin
560 Result := OpenCursor(transaction,sql,aSQLDialect,params);
561 Result.FetchNext;
562 end;
563
564 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction; sql: AnsiString
565 ): IResultSet;
566 begin
567 Result := OpenCursorAtStart(transaction,sql,FSQLDialect,[]);
568 end;
569
570 function TFBAttachment.OpenCursorAtStart(transaction: ITransaction;
571 sql: AnsiString; params: array of const): IResultSet;
572 begin
573 Result := OpenCursorAtStart(transaction,sql,FSQLDialect,params);
574 end;
575
576 function TFBAttachment.OpenCursorAtStart(sql: AnsiString): IResultSet;
577 begin
578 Result := OpenCursorAtStart(sql,[]);
579 end;
580
581 function TFBAttachment.OpenCursorAtStart(sql: AnsiString;
582 params: array of const): IResultSet;
583 begin
584 Result := OpenCursorAtStart(StartTransaction([isc_tpb_read,isc_tpb_wait,isc_tpb_concurrency],taCommit),sql,FSQLDialect,params);
585 end;
586
587 function TFBAttachment.Prepare(transaction: ITransaction; sql: AnsiString
588 ): IStatement;
589 begin
590 Result := Prepare(transaction,sql,FSQLDialect);
591 end;
592
593 function TFBAttachment.PrepareWithNamedParameters(transaction: ITransaction;
594 sql: AnsiString; GenerateParamNames: boolean): IStatement;
595 begin
596 Result := PrepareWithNamedParameters(transaction,sql,FSQLDialect,GenerateParamNames);
597 end;
598
599 function TFBAttachment.GetEventHandler(Event: AnsiString): IEvents;
600 var S: TStringList;
601 begin
602 S := TStringList.Create;
603 try
604 S.Add(Event);
605 Result := GetEventHandler(S);
606 finally
607 S.Free;
608 end;
609 end;
610
611 function TFBAttachment.GetSQLDialect: integer;
612 begin
613 Result := FSQLDialect;
614 end;
615
616 function TFBAttachment.OpenBlob(transaction: ITransaction; Field: ISQLData;
617 BPB: IBPB): IBlob;
618 begin
619 Result := OpenBlob(Transaction,Field.GetBlobMetadata, Field.AsQuad,BPB);
620 end;
621
622 function TFBAttachment.GetDBInformation(Requests: array of byte
623 ): IDBInformation;
624 var ReqBuffer: PByte;
625 i: integer;
626 begin
627 CheckHandle;
628 if Length(Requests) = 1 then
629 Result := GetDBInformation(Requests[0])
630 else
631 begin
632 GetMem(ReqBuffer,Length(Requests));
633 try
634 for i := 0 to Length(Requests) - 1 do
635 ReqBuffer[i] := Requests[i];
636
637 Result := GetDBInfo(ReqBuffer,Length(Requests));
638
639 finally
640 FreeMem(ReqBuffer);
641 end;
642 end;
643 end;
644
645 function TFBAttachment.GetDBInformation(Request: byte): IDBInformation;
646 begin
647 CheckHandle;
648 Result := GetDBInfo(@Request,1);
649 end;
650
651 function TFBAttachment.GetDBInformation(Requests: IDIRB): IDBInformation;
652 begin
653 CheckHandle;
654 with Requests as TDIRB do
655 Result := GetDBInfo(getBuffer,getDataLength);
656 end;
657
658 function TFBAttachment.GetConnectString: AnsiString;
659 begin
660 Result := FDatabaseName;
661 end;
662
663 function TFBAttachment.GetRemoteProtocol: AnsiString;
664 begin
665 Result := FRemoteProtocol;
666 end;
667
668 function TFBAttachment.GetAuthenticationMethod: AnsiString;
669 begin
670 Result := FAuthMethod;
671 end;
672
673 function TFBAttachment.GetSecurityDatabase: AnsiString;
674 begin
675 Result := FSecDatabase;
676 end;
677
678 function TFBAttachment.GetODSMajorVersion: integer;
679 begin
680 Result := FODSMajorVersion;
681 end;
682
683 function TFBAttachment.GetODSMinorVersion: integer;
684 begin
685 Result := FODSMinorVersion;
686 end;
687
688 function TFBAttachment.HasDefaultCharSet: boolean;
689 begin
690 Result := FHasDefaultCharSet
691 end;
692
693 function TFBAttachment.GetDefaultCharSetID: integer;
694 begin
695 Result := FCharsetID;
696 end;
697
698 function TFBAttachment.GetCharsetName(CharSetID: integer): AnsiString;
699 var i: integer;
700 begin
701 Result := '';
702 if (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap)) and
703 (CharSetMap[CharSetID].CharSetID = CharSetID) then
704 begin
705 Result := CharSetMap[CharSetID].CharSetName;
706 Exit;
707 end;
708
709 for i := 0 to Length(FUserCharSetMap) - 1 do
710 if FUserCharSetMap[i].CharSetID = CharSetID then
711 begin
712 Result := FUserCharSetMap[i].CharSetName;
713 Exit;
714 end;
715 end;
716
717 function TFBAttachment.CharSetID2CodePage(CharSetID: integer;
718 var CodePage: TSystemCodePage): boolean;
719 var i: integer;
720 begin
721 Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
722 and (CharSetMap[CharSetID].CharSetID = CharSetID);
723 if Result then
724 begin
725 CodePage := CharSetMap[CharSetID].CodePage;
726 Result := true;
727 Exit;
728 end;
729
730 for i := 0 to Length(FUserCharSetMap) - 1 do
731 if FUserCharSetMap[i].CharSetID = CharSetID then
732 begin
733 CodePage := FUserCharSetMap[i].CodePage;
734 Result := true;
735 Exit;
736 end;
737 end;
738
739 function TFBAttachment.CodePage2CharSetID(CodePage: TSystemCodePage;
740 var CharSetID: integer): boolean;
741 var i: integer;
742 begin
743 Result := false;
744 for i := Low(CharSetMap) to High(CharSetMap) do
745 if (CharSetMap[i].AllowReverseLookup) and (CharSetMap[i].CodePage = CodePage) then
746 begin
747 CharSetID := CharSetMap[i].CharSetID;
748 Result := true;
749 Exit;
750 end;
751
752 for i := 0 to Length(FUserCharSetMap) - 1 do
753 if (FUserCharSetMap[i].AllowReverseLookup) and (FUserCharSetMap[i].CodePage = CodePage) then
754 begin
755 CharSetID := FUserCharSetMap[i].CharSetID;
756 Result := true;
757 Exit;
758 end;
759 end;
760
761 function TFBAttachment.CharSetName2CharSetID(CharSetName: AnsiString;
762 var CharSetID: integer): boolean;
763 var i: integer;
764 begin
765 Result := false;
766 for i := Low(CharSetMap) to High(CharSetMap) do
767 if AnsiCompareText(CharSetMap[i].CharSetName, CharSetName) = 0 then
768 begin
769 CharSetID := CharSetMap[i].CharSetID;
770 Result := true;
771 Exit;
772 end;
773
774 for i := 0 to Length(FUserCharSetMap) - 1 do
775 if AnsiCompareText(FUserCharSetMap[i].CharSetName, CharSetName) = 0 then
776 begin
777 CharSetID := FUserCharSetMap[i].CharSetID;
778 Result := true;
779 Exit;
780 end;
781 end;
782
783 function TFBAttachment.CharSetWidth(CharSetID: integer; var Width: integer
784 ): boolean;
785 var i: integer;
786 begin
787 Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
788 and (CharSetMap[CharSetID].CharSetID = CharSetID);
789 if Result then
790 begin
791 Width := CharSetMap[CharSetID].CharSetWidth;
792 Result := true;
793 Exit;
794 end;
795
796 for i := 0 to Length(FUserCharSetMap) - 1 do
797 if FUserCharSetMap[i].CharSetID = CharSetID then
798 begin
799 Width := FUserCharSetMap[i].CharSetWidth;
800 Result := true;
801 Exit;
802 end;
803 end;
804
805 const
806 sqlLookupCharSet = 'Select RDB$CHARACTER_SET_ID, RDB$BYTES_PER_CHARACTER From RDB$CHARACTER_SETS '+
807 'Where RDB$SYSTEM_FLAG = 0 and RDB$CHARACTER_SET_NAME = UPPER(?)';
808
809 procedure TFBAttachment.RegisterCharSet(CharSetName: AnsiString;
810 CodePage: TSystemCodePage; AllowReverseLookup: boolean; out CharSetID: integer
811 );
812 var CharSets: IResultSet;
813 idx: integer;
814 begin
815 if CharSetName2CharSetID(CharSetName,CharSetID) then
816 IBError(ibxeCharacterSetExists,[CharSetName]);
817
818 CharSets := OpenCursorAtStart(sqlLookupCharSet,[CharSetName]);
819 if CharSets.IsEof then
820 IBError(ibxeUnknownUserCharSet,[CharSetName]);
821
822 idx := Length(FUserCharSetMap);
823 SetLength(FUserCharSetMap,idx+1);
824 FUserCharSetMap[idx].AllowReverseLookup := AllowReverseLookup;
825 FUserCharSetMap[idx].CharSetID := CharSets[0].AsInteger;
826 FUserCharSetMap[idx].CharSetName := AnsiUpperCase(CharSetName);
827 FUserCharSetMap[idx].CharSetWidth := CharSets[1].AsInteger;
828 FUserCharSetMap[idx].CodePage := CodePage;
829 CharSetID := CharSets[0].AsInteger;
830 end;
831
832 end.
833