zeoslib  UNKNOWN
 All Files
ZPlainDriver.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Interfaces for Native Plain Drivers }
5 { }
6 { Originally written by Sergey Seroukhov }
7 { }
8 {*********************************************************}
9 
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
12 { }
13 { License Agreement: }
14 { }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
20 { }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
39 { }
40 { }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
45 { }
46 { http://www.sourceforge.net/projects/zeoslib. }
47 { }
48 { }
49 { Zeos Development Group. }
50 {********************************************************@}
51 
52 unit ZPlainDriver;
53 
54 interface
55 
56 {$I ZPlain.inc}
57 
58 uses ZClasses, ZPlainLoader, ZCompatibility, Types, ZTokenizer;
59 
60 type
61 
62  {** Represents a generic interface to plain driver. }
63  IZPlainDriver = interface (IZInterface)
64  ['{2A0CC600-B3C4-43AF-92F5-C22A3BB1BB7D}']
65  function IsAnsiDriver: Boolean;
66  function GetProtocol: string;
67  function GetDescription: string;
68  {EgonHugeist:
69  Why this here? -> No one else then Plaindriver knows which Characterset
70  is supported. Here i've made a intervention in dependency of used Compiler.}
71  function GetSupportedClientCodePages(const {$IFNDEF UNICODE}AutoEncode,{$ENDIF} IgnoreUnsupported: Boolean;
72  CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray;
73  function ValidateCharEncoding(const CharacterSetName: String; const DoArrange: Boolean = False): PZCodePage; overload;
74  function ValidateCharEncoding(const CharacterSetID: Integer; const DoArrange: Boolean = False): PZCodePage; overload;
75  function ZDbcString(const Ansi: RawByteString; ConSettings: PZConSettings): String;
76  function ZPlainString(const AStr: String; ConSettings: PZConSettings): RawByteString; overload;
77  function ZPlainString(const AStr: WideString; ConSettings: PZConSettings): RawByteString; overload;
78  function ZPlainString(const AStr: String; ConSettings: PZConSettings; const ToCP: Word): RawByteString; overload;
79  function ZDbcUnicodeString(const AStr: RawByteString; const FromCP: Word): ZWideString; overload;
80  function GetPrepreparedSQL(Handle: Pointer; const SQL: String;
81  ConSettings: PZConSettings; out LogSQL: String): RawByteString;
82  function EscapeString(Handle: Pointer; const Value: ZWideString;
83  ConSettings: PZConSettings): ZWideString; overload;
84  function EscapeString(Handle: Pointer; const Value: RawByteString;
85  ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; overload;
86  procedure Initialize(const Location: String = '');
87  function Clone: IZPlainDriver;
88  end;
89 
90  {ADDED by fduenas 15-06-2006}
91  {** Base class of a generic plain driver with TZNativeLibraryLoader-object. }
92 
93  TZAbstractPlainDriver = class(TZCodePagedObject, IZPlainDriver)
94  protected
95  FCodePages: array of TZCodePage;
96  FTokenizer: IZTokenizer;
97  FLoader: TZNativeLibraryLoader;
98  procedure LoadApi; virtual;
99  function IsAnsiDriver: Boolean; virtual;
100  function Clone: IZPlainDriver; reintroduce; virtual; abstract;
101  procedure LoadCodePages; virtual; abstract;
102  function GetUnicodeCodePageName: String; virtual;
103  function ValidateCharEncoding(const CharacterSetName: String; const DoArrange: Boolean = False): PZCodePage; overload;
104  function ValidateCharEncoding(const CharacterSetID: Integer; const DoArrange: Boolean = False): PZCodePage; overload;
105  function GetPrepreparedSQL(Handle: Pointer; const SQL: String;
106  ConSettings: PZConSettings; out LogSQL: String): RawByteString; virtual;
107  function EscapeString(Handle: Pointer; const Value: ZWideString;
108  ConSettings: PZConSettings): ZWideString; overload;
109  function EscapeString(Handle: Pointer; const Value: RawByteString;
110  ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; overload; virtual;
111  function GetTokenizer: IZTokenizer;
112  public
113  constructor Create;
114  constructor CreateWithLibrary(const LibName : String);
115  destructor Destroy; override;
116  function GetProtocol: string; virtual; abstract;
117  function GetDescription: string; virtual; abstract;
118  function GetSupportedClientCodePages(const {$IFNDEF UNICODE}AutoEncode,{$ENDIF} IgnoreUnsupported: Boolean;
119  CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray;
120  procedure Initialize(const Location: String = ''); virtual;
121 
122  property Loader: TZNativeLibraryLoader read FLoader;
123  procedure AddCodePage(const Name: String; const ID: Integer;
124  Encoding: TZCharEncoding = ceAnsi; const CP: Word = $ffff;
125  const ZAlias: String = ''; CharWidth: Integer = 1;
126  const ConsistentCP: Boolean = True);
127  procedure ResetCodePage(const OldID: Integer; const Name: String;
128  const ID: Integer; {may be an ordinal value of predefined Types...}
129  Encoding: TZCharEncoding = ceAnsi; const CP: Word = $ffff;
130  const ZAlias: String = ''; CharWidth: Integer = 1;
131  const ConsistentCP: Boolean = True);
132  end;
133  {END ADDED by fduenas 15-06-2006}
134 
135 implementation
136 
137 uses SysUtils, ZEncoding{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF};
138 
139 
140 {TZAbstractPlainDriver}
141 
142 function TZAbstractPlainDriver.IsAnsiDriver: Boolean;
143 begin
144  Result := True;
145 end;
146 
147 function TZAbstractPlainDriver.GetUnicodeCodePageName: String;
148 begin
149  Result := '';
150 end;
151 
152 {**
153  Checks if the given ClientCharacterSet and returns the PZCodePage
154  @param CharacterSetName the Name wich has to be validated
155  @param DoArrange means if the CharacterSet is empty or unsupported then find
156  a supported CodePage
157  @result the PZCodePage of the ClientCharacterSet
158 }
159 function TZAbstractPlainDriver.ValidateCharEncoding(const CharacterSetName: String;
160  const DoArrange: Boolean = False): PZCodePage;
161 
162  function GetClientCodePageInformations(
163  const ClientCharacterSet: String): PZCodePage;
164  var
165  I: Integer;
166  begin
167  {now check for PlainDriver-Informations...}
168  {$IFDEF FPC} //if the user didn't set it
169  if ClientCharacterSet = '' then
170  begin
171  for i := Low(FCodePages) to high(FCodePages) do
172  if UpperCase(FCodePages[i].Name) = UpperCase(GetUnicodeCodePageName) then
173  begin
174  Result := @FCodePages[i];
175  Exit;
176  end;
177  end
178  else
179  {$ENDIF}
180  for i := Low(FCodePages) to high(FCodePages) do
181  if UpperCase(FCodePages[i].Name) = UpperCase(ClientCharacterSet) then
182  begin
183  Result := @FCodePages[i];
184  Exit;
185  end;
186  Result := @ClientCodePageDummy;
187  end;
188 begin
189  Result := GetClientCodePageInformations(CharacterSetName);
190  if (DoArrange) and (Result^.ZAlias <> '' ) then
191  ValidateCharEncoding(Result^.ZAlias); //recalls em selves
192 end;
193 
194 {**
195  Checks if the given ClientCharacterSet and returns the PZCodePage
196  @param CharacterSetID the ID wich has to be validated
197  @param DoArrange means if the CharacterSet is empty or unsupported then find
198  a supported CodePage
199  @result the PZCodePage of the ClientCharacterSet
200 }
201 function TZAbstractPlainDriver.ValidateCharEncoding(const CharacterSetID: Integer;
202  const DoArrange: Boolean = False): PZCodePage;
203 
204  function GetClientCodePageInformations(const ClientCharacterSetID: Word): PZCodePage;
205  var
206  I: Integer;
207  begin
208  {now check for PlainDriver-Informations...}
209  for i := Low(FCodePages) to high(FCodePages) do
210  if FCodePages[i].ID = ClientCharacterSetID then
211  begin
212  Result := @FCodePages[i];
213  Exit;
214  end;
215  Result := @ClientCodePageDummy;
216  end;
217 begin
218  Result := GetClientCodePageInformations(CharacterSetID);
219 
220  if (DoArrange) and (Result^.ZAlias <> '' ) then
221  ValidateCharEncoding(Result^.ZAlias); //recalls em selves
222 end;
223 
224 function TZAbstractPlainDriver.GetPrepreparedSQL(Handle: Pointer;
225  const SQL: String; ConSettings: PZConSettings; out LogSQL: String): RawByteString;
226 var
227  SQLTokens: TZTokenDynArray;
228  i: Integer;
229 begin
230  Result := '';
231  if ConSettings.AutoEncode then
232  begin
233  SQLTokens := FTokenizer.TokenizeBuffer(SQL, [toSkipEOF]); //Disassembles the Query
234  for i := Low(SQLTokens) to high(SQLTokens) do //Assembles the Query
235  begin
236  case (SQLTokens[i].TokenType) of
237  ttEscape:
238  Result := Result + {$IFDEF UNICODE}ZPlainString(SQLTokens[i].Value,
239  ConSettings){$ELSE}SQLTokens[i].Value{$ENDIF};
240  ttQuoted, ttWord, ttQuotedIdentifier, ttKeyword:
241  Result := Result + ZPlainString(SQLTokens[i].Value, ConSettings)
242  else
243  Result := Result + RawByteString(SQLTokens[i].Value);
244  end;
245  end;
246  end
247  else
248  {$IFDEF UNICODE}
249  Result := ZPlainString(SQL, ConSettings);
250  {$ELSE}
251  Result := SQL;
252  {$ENDIF}
253  LogSQL := String(Result);
254 end;
255 
256 {$IFDEF FPC}
257  {$HINTS OFF}
258 {$ENDIF}
259 function TZAbstractPlainDriver.EscapeString(Handle: Pointer;
260  const Value: ZWideString; ConSettings: PZConSettings): ZWideString;
261 var
262  StrFrom: RawByteString;
263  Outbuffer: RawByteString;
264 begin
265  StrFrom := ZPlainString(Value, ConSettings);
266  Outbuffer := EscapeString(Handle, StrFrom, ConSettings, True);
267  {$IFDEF UNICODE}
268  Result := ZDbcString(OutBuffer, ConSettings);
269  {$ELSE}
270  Result := ZDbcUnicodeString(Outbuffer, ConSettings.ClientCodePage.CP);
271  {$ENDIF}
272 end;
273 function TZAbstractPlainDriver.EscapeString(Handle: Pointer;
274  const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString;
275 begin
276  Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(Value, #39);
277 end;
278 {$IFDEF FPC}
279  {$HINTS ON}
280 {$ENDIF}
281 
282 function TZAbstractPlainDriver.GetTokenizer: IZTokenizer;
283 begin
284  Result := FTokenizer;
285 end;
286 
287 procedure TZAbstractPlainDriver.AddCodePage(const Name: String;
288  const ID: Integer; Encoding: TZCharEncoding = ceAnsi;
289  const CP: Word = $ffff; const ZAlias: String = '';
290  CharWidth: Integer = 1; const ConsistentCP: Boolean = True);
291 begin
292  SetLength(FCodePages, Length(FCodePages)+1);
293  FCodePages[High(FCodePages)].Name := Name;
294  FCodePages[High(FCodePages)].ID := ID;
295  FCodePages[High(FCodePages)].Encoding := Encoding;
296  FCodePages[High(FCodePages)].CP := CP;
297  FCodePages[High(FCodePages)].CharWidth := CharWidth;
298  FCodePages[High(FCodePages)].ZAlias := ZAlias;
299  FCodePages[High(FCodePages)].IsStringFieldCPConsistent := ConsistentCP;
300 
301  if CP = $ffff then
302  FCodePages[High(FCodePages)].ZAlias := GetUnicodeCodePageName;
303 end;
304 
305 procedure TZAbstractPlainDriver.ResetCodePage(const OldID: Integer;
306  const Name: String; const ID: Integer; Encoding: TZCharEncoding = ceAnsi;
307  const CP: Word = $ffff;
308  const ZAlias: String = ''; CharWidth: Integer = 1;
309  const ConsistentCP: Boolean = True);
310 var
311  I: Integer;
312 begin
313  for i := low(FCodePages) to high(FCodePages) do
314  if OldID = FCodePages[I].ID then
315  begin
316  FCodePages[I].ID := ID;
317  FCodePages[I].Name := Name;
318  FCodePages[I].Encoding := Encoding;
319  FCodePages[I].CP := CP;
320  FCodePages[I].ZAlias := ZAlias;
321  FCodePages[I].CharWidth := CharWidth;
322  FCodePages[I].IsStringFieldCPConsistent := ConsistentCP;
323 
324  if CP = $ffff then
325  FCodePages[I].ZAlias := GetUnicodeCodePageName;
326  Break;
327  end;
328 end;
329 
330 function TZAbstractPlainDriver.GetSupportedClientCodePages(
331  const {$IFNDEF UNICODE}AutoEncode,{$ENDIF} IgnoreUnsupported: Boolean;
332  CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray;
333 var
334  I: Integer;
335 
336  procedure AddCurrent;
337  begin
338  SetLength(Result, Length(Result)+1);
339  Result[High(Result)] := FCodePages[i].Name;
340  end;
341 
342 begin
343  SetLength(Result, 0);
344  for i := low(FCodePages) to high(FCodePages) do
345  if IgnoreUnsupported then
346  AddCurrent
347  else
348  case CtrlsCPType of
349  cGET_ACP:
350  {$IFDEF UNICODE}
351  AddCurrent; //result are ?valid? but does that makes sence for all if not CP_UTF8?
352  {$ELSE}
353  if ( FCodePages[i].CP = ZDefaultSystemCodePage ) then
354  AddCurrent
355  else
356  if AutoEncode then
357  {$IF defined(MSWINDOWS) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER) }
358  AddCurrent //result are ?valid? but does that makes sence for all if not CP_UTF8?
359  {$ELSE}
360  {$IFDEF WITH_LCONVENCODING} //Lazarus only
361  if ( IsLConvEncodingCodePage(FCodePages[i].CP) ) or
362  ( FCodePages[i].Encoding = ceUTF8 ) then
363  AddCurrent //allways valid because result is allways UTF8 which lazarus expects
364  {$ENDIF}
365  {$IFEND}
366  else Continue;
367  {$ENDIF}
368  {$IFNDEF UNICODE}
369  cCP_UTF8:
370  if ( FCodePages[i].Encoding = ceUTF8 ) then
371  AddCurrent
372  else
373  if AutoEncode then
374  {$IF defined(MSWINDOWS) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER) }
375  AddCurrent //All charsets can be converted to UTF8 if a valid WideString-Manager does exists
376  {$ELSE}
377  {$IFDEF WITH_LCONVENCODING} //Lazarus only
378  if ( IsLConvEncodingCodePage(FCodePages[i].CP) ) then
379  AddCurrent
380  {$ENDIF}
381  {$IFEND}
382  else Continue;
383  {$ENDIF}
384  else
385  {$IF defined(MSWINDOWS) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER) or defined(UNICODE)}
386  AddCurrent; //all remaining charset can be converted to wide if a valid WideString-Manager does exists
387  {$ELSE}
388  {$IFDEF WITH_LCONVENCODING} //Lazarus only
389  if ( IsLConvEncodingCodePage(FCodePages[i].CP) ) or //Lazarus can convert to UTF8 then we convert to wide (double En/Decoding!)
390  ( FCodePages[i].Encoding = ceUTF8 ) or //decode the strings to wide
391  ( FCodePages[i].CP = ZDefaultSystemCodePage ) then //to allow a valid cast
392  AddCurrent; //all these charset can be converted to wide
393  {$ELSE}
394  if ( FCodePages[i].CP = ZDefaultSystemCodePage ) or //to allow a valid cast
395  ( FCodePages[i].Encoding = ceUTF8 ) then //decode the strings to wide
396  AddCurrent;
397  {$ENDIF}
398  {$IFEND}
399  end;
400 end;
401 
402 constructor TZAbstractPlainDriver.Create;
403 begin
404  inherited Create;
405  FTokenizer := TZTokenizer.Create;
406 end;
407 
408 destructor TZAbstractPlainDriver.Destroy;
409 begin
410  SetLength(FCodePages, 0);
411  FTokenizer := nil;
412  if Assigned(FLoader) then
413  FreeAndNil(FLoader);
414  inherited Destroy;
415 end;
416 
417 
418 procedure TZAbstractPlainDriver.LoadApi;
419 begin
420 
421 end;
422 
423 constructor TZAbstractPlainDriver.CreateWithLibrary(const LibName: String);
424 begin
425  Inherited Create;
426  if Assigned(FLoader) then
427  begin
428  Loader.ClearLocations;
429  Loader.AddLocation(LibName);
430  end;
431 end;
432 
433 procedure TZAbstractPlainDriver.Initialize(const Location: String = '');
434 begin
435  If Assigned(Loader) then
436  if not Loader.Loaded then
437  begin
438  if Location <> '' then
439  begin
440  Loader.ClearLocations;
441  Loader.AddLocation(Location);
442  end;
443  If Loader.LoadNativeLibrary then
444  LoadApi;
445  end;
446 end;
447 
448 end.
449