ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBAttachment.pas
Revision: 117
Committed: Mon Jan 22 13:58:11 2018 UTC (6 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 29804 byte(s)
Log Message:
Fixes Merged

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