1 {*********************************************************}
3 { Zeos Database Objects }
4 { Interfaces for Native Plain Drivers }
6 { Originally written by Sergey Seroukhov }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
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. }
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. }
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) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
58 uses ZClasses, ZPlainLoader, ZCompatibility, Types, ZTokenizer;
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;
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;
90 {ADDED by fduenas 15-06-2006}
91 {** Base class of a generic plain driver with TZNativeLibraryLoader-object. }
93 TZAbstractPlainDriver = class(TZCodePagedObject, IZPlainDriver)
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;
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;
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);
133 {END ADDED by fduenas 15-06-2006}
137 uses SysUtils, ZEncoding{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF};
140 {TZAbstractPlainDriver}
142 function TZAbstractPlainDriver.IsAnsiDriver: Boolean;
147 function TZAbstractPlainDriver.GetUnicodeCodePageName: String;
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
157 @result the PZCodePage of the ClientCharacterSet
159 function TZAbstractPlainDriver.ValidateCharEncoding(const CharacterSetName: String;
160 const DoArrange: Boolean = False): PZCodePage;
162 function GetClientCodePageInformations(
163 const ClientCharacterSet: String): PZCodePage;
167 {now check for PlainDriver-Informations...}
168 {$IFDEF FPC} //if the user didn't set it
169 if ClientCharacterSet = '' then
171 for i := Low(FCodePages) to high(FCodePages) do
172 if UpperCase(FCodePages[i].Name) = UpperCase(GetUnicodeCodePageName) then
174 Result := @FCodePages[i];
180 for i := Low(FCodePages) to high(FCodePages) do
181 if UpperCase(FCodePages[i].Name) = UpperCase(ClientCharacterSet) then
183 Result := @FCodePages[i];
186 Result := @ClientCodePageDummy;
189 Result := GetClientCodePageInformations(CharacterSetName);
190 if (DoArrange) and (Result^.ZAlias <> '' ) then
191 ValidateCharEncoding(Result^.ZAlias); //recalls em selves
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
199 @result the PZCodePage of the ClientCharacterSet
201 function TZAbstractPlainDriver.ValidateCharEncoding(const CharacterSetID: Integer;
202 const DoArrange: Boolean = False): PZCodePage;
204 function GetClientCodePageInformations(const ClientCharacterSetID: Word): PZCodePage;
208 {now check for PlainDriver-Informations...}
209 for i := Low(FCodePages) to high(FCodePages) do
210 if FCodePages[i].ID = ClientCharacterSetID then
212 Result := @FCodePages[i];
215 Result := @ClientCodePageDummy;
218 Result := GetClientCodePageInformations(CharacterSetID);
220 if (DoArrange) and (Result^.ZAlias <> '' ) then
221 ValidateCharEncoding(Result^.ZAlias); //recalls em selves
224 function TZAbstractPlainDriver.GetPrepreparedSQL(Handle: Pointer;
225 const SQL: String; ConSettings: PZConSettings; out LogSQL: String): RawByteString;
227 SQLTokens: TZTokenDynArray;
231 if ConSettings.AutoEncode then
233 SQLTokens := FTokenizer.TokenizeBuffer(SQL, [toSkipEOF]); //Disassembles the Query
234 for i := Low(SQLTokens) to high(SQLTokens) do //Assembles the Query
236 case (SQLTokens[i].TokenType) of
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)
243 Result := Result + RawByteString(SQLTokens[i].Value);
249 Result := ZPlainString(SQL, ConSettings);
253 LogSQL := String(Result);
259 function TZAbstractPlainDriver.EscapeString(Handle: Pointer;
260 const Value: ZWideString; ConSettings: PZConSettings): ZWideString;
262 StrFrom: RawByteString;
263 Outbuffer: RawByteString;
265 StrFrom := ZPlainString(Value, ConSettings);
266 Outbuffer := EscapeString(Handle, StrFrom, ConSettings, True);
268 Result := ZDbcString(OutBuffer, ConSettings);
270 Result := ZDbcUnicodeString(Outbuffer, ConSettings.ClientCodePage.CP);
273 function TZAbstractPlainDriver.EscapeString(Handle: Pointer;
274 const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString;
276 Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(Value, #39);
282 function TZAbstractPlainDriver.GetTokenizer: IZTokenizer;
284 Result := FTokenizer;
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);
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;
302 FCodePages[High(FCodePages)].ZAlias := GetUnicodeCodePageName;
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);
313 for i := low(FCodePages) to high(FCodePages) do
314 if OldID = FCodePages[I].ID then
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;
325 FCodePages[I].ZAlias := GetUnicodeCodePageName;
330 function TZAbstractPlainDriver.GetSupportedClientCodePages(
331 const {$IFNDEF UNICODE}AutoEncode,{$ENDIF} IgnoreUnsupported: Boolean;
332 CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray;
336 procedure AddCurrent;
338 SetLength(Result, Length(Result)+1);
339 Result[High(Result)] := FCodePages[i].Name;
343 SetLength(Result, 0);
344 for i := low(FCodePages) to high(FCodePages) do
345 if IgnoreUnsupported then
351 AddCurrent; //result are ?valid? but does that makes sence for all if not CP_UTF8?
353 if ( FCodePages[i].CP = ZDefaultSystemCodePage ) 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?
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
370 if ( FCodePages[i].Encoding = ceUTF8 ) 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
377 {$IFDEF WITH_LCONVENCODING} //Lazarus only
378 if ( IsLConvEncodingCodePage(FCodePages[i].CP) ) then
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
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
394 if ( FCodePages[i].CP = ZDefaultSystemCodePage ) or //to allow a valid cast
395 ( FCodePages[i].Encoding = ceUTF8 ) then //decode the strings to wide
402 constructor TZAbstractPlainDriver.Create;
405 FTokenizer := TZTokenizer.Create;
408 destructor TZAbstractPlainDriver.Destroy;
410 SetLength(FCodePages, 0);
412 if Assigned(FLoader) then
418 procedure TZAbstractPlainDriver.LoadApi;
423 constructor TZAbstractPlainDriver.CreateWithLibrary(const LibName: String);
426 if Assigned(FLoader) then
428 Loader.ClearLocations;
429 Loader.AddLocation(LibName);
433 procedure TZAbstractPlainDriver.Initialize(const Location: String = '');
435 If Assigned(Loader) then
436 if not Loader.Loaded then
438 if Location <> '' then
440 Loader.ClearLocations;
441 Loader.AddLocation(Location);
443 If Loader.LoadNativeLibrary then