zeoslib  UNKNOWN
 All Files
ZDbcMySql.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { MySQL Database Connectivity Classes }
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 ZDbcMySql;
53 
54 interface
55 
56 {$I ZDbc.inc}
57 
58 uses
59  Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
60  ZCompatibility, ZDbcIntfs, ZDbcConnection, ZPlainMySqlDriver, ZPlainDriver,
61  ZURL, ZDbcLogging, ZTokenizer, ZGenericSqlAnalyser, ZPlainMySqlConstants;
62 
63 type
64 
65  {** Implements MySQL Database Driver. }
66 
67  { TZMySQLDriver }
68  {$WARNINGS OFF}
69  TZMySQLDriver = class(TZAbstractDriver)
70  protected
71  function GetPlainDriver(const Url: TZURL; const InitDriver: Boolean = True): IZPlainDriver; override;
72  public
73  constructor Create; override;
74  function Connect(const Url: TZURL): IZConnection; override;
75  function GetMajorVersion: Integer; override;
76  function GetMinorVersion: Integer; override;
77 
78  function GetTokenizer: IZTokenizer; override;
79  function GetStatementAnalyser: IZStatementAnalyser; override;
80  function GetClientVersion(const Url: string): Integer; override;
81  end;
82  {$WARNINGS ON}
83 
84  {** Represents a MYSQL specific connection interface. }
85  IZMySQLConnection = interface (IZConnection)
86  ['{68E33DD3-4CDC-4BFC-8A28-E9F2EE94E457}']
87 
88  function GetPlainDriver: IZMySQLPlainDriver;
89  function GetConnectionHandle: PZMySQLConnect;
90  end;
91 
92  {** Implements MySQL Database Connection. }
93  TZMySQLConnection = class(TZAbstractConnection, IZMySQLConnection)
94  private
95  FCatalog: string;
96  FHandle: PZMySQLConnect;
97  protected
98  procedure InternalCreate; override;
99  public
100  destructor Destroy; override;
101 
102  function CreateRegularStatement(Info: TStrings): IZStatement; override;
103  function CreatePreparedStatement(const SQL: string; Info: TStrings):
104  IZPreparedStatement; override;
105  function CreateCallableStatement(const SQL: string; Info: TStrings):
106  IZCallableStatement; override;
107 
108  procedure Commit; override;
109  procedure Rollback; override;
110 
111  function PingServer: Integer; override;
112  function EscapeString(Value: RawByteString): RawByteString; override;
113 
114  procedure Open; override;
115  procedure Close; override;
116 
117  procedure SetCatalog(const Catalog: string); override;
118  function GetCatalog: string; override;
119 
120  procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override;
121  procedure SetAutoCommit(Value: Boolean); override;
122  {ADDED by fduenas 15-06-2006}
123  function GetClientVersion: Integer; override;
124  function GetHostVersion: Integer; override;
125  {END ADDED by fduenas 15-06-2006}
126  function GetPlainDriver: IZMySQLPlainDriver;
127  function GetConnectionHandle: PZMySQLConnect;
128  function GetEscapeString(const Value: ZWideString): ZWideString; override;
129  function GetEscapeString(const Value: RawByteString): RawByteString; override;
130  end;
131 
132 
133 var
134  {** The common driver manager object. }
135  MySQLDriver: IZDriver;
136 
137 implementation
138 
139 uses
140  ZMessages, ZSysUtils, ZDbcUtils, ZDbcMySqlStatement, ZMySqlToken,
141  ZDbcMySqlUtils, ZDbcMySqlMetadata, ZMySqlAnalyser, TypInfo, Math,
142  ZEncoding;
143 
144 { TZMySQLDriver }
145 
146 {**
147  Constructs this object with default properties.
148 }
149 constructor TZMySQLDriver.Create;
150 begin
151  inherited Create;
152  AddSupportedProtocol(AddPlainDriverToCache(TZMySQL5PlainDriver.Create(GetTokenizer), 'mysql'));
153  AddSupportedProtocol(AddPlainDriverToCache(TZMySQL41PlainDriver.Create(GetTokenizer)));
154  AddSupportedProtocol(AddPlainDriverToCache(TZMySQL5PlainDriver.Create(GetTokenizer)));
155  AddSupportedProtocol(AddPlainDriverToCache(TZMySQLD41PlainDriver.Create(GetTokenizer)));
156  AddSupportedProtocol(AddPlainDriverToCache(TZMySQLD5PlainDriver.Create(GetTokenizer)));
157  AddSupportedProtocol(AddPlainDriverToCache(TZMariaDB5PlainDriver.Create(GetTokenizer)));
158 end;
159 
160 {**
161  Attempts to make a database connection to the given URL.
162  The driver should return "null" if it realizes it is the wrong kind
163  of driver to connect to the given URL. This will be common, as when
164  the JDBC driver manager is asked to connect to a given URL it passes
165  the URL to each loaded driver in turn.
166 
167  <P>The driver should raise a SQLException if it is the right
168  driver to connect to the given URL, but has trouble connecting to
169  the database.
170 
171  <P>The java.util.Properties argument can be used to passed arbitrary
172  string tag/value pairs as connection arguments.
173  Normally at least "user" and "password" properties should be
174  included in the Properties.
175 
176  @param url the URL of the database to which to connect
177  @param info a list of arbitrary string tag/value pairs as
178  connection arguments. Normally at least a "user" and
179  "password" property should be included.
180  @return a <code>Connection</code> object that represents a
181  connection to the URL
182 }
183 {$WARNINGS OFF}
184 function TZMySQLDriver.Connect(const Url: TZURL): IZConnection;
185 begin
186  Result := TZMySQLConnection.Create(Url);
187 end;
188 {$WARNINGS ON}
189 
190 {**
191  Gets the driver's major version number. Initially this should be 1.
192  @return this driver's major version number
193 }
194 function TZMySQLDriver.GetMajorVersion: Integer;
195 begin
196  Result := 1;
197 end;
198 
199 {**
200  Gets the driver's minor version number. Initially this should be 0.
201  @return this driver's minor version number
202 }
203 function TZMySQLDriver.GetMinorVersion: Integer;
204 begin
205  Result := 1;
206 end;
207 
208 {**
209  Gets a SQL syntax tokenizer.
210  @returns a SQL syntax tokenizer object.
211 }
212 function TZMySQLDriver.GetTokenizer: IZTokenizer;
213 begin
214  Result := TZMySQLTokenizer.Create;
215 end;
216 
217 {**
218  Creates a statement analyser object.
219  @returns a statement analyser object.
220 }
221 function TZMySQLDriver.GetStatementAnalyser: IZStatementAnalyser;
222 begin
223  Result := TZMySQLStatementAnalyser.Create; { thread save! Allways return a new Analyser! }
224 end;
225 
226 {**
227  Gets plain driver for selected protocol.
228  @param Url a database connection URL.
229  @return a selected plaindriver.
230 }
231 function TZMySQLDriver.GetPlainDriver(const Url: TZURL;
232  const InitDriver: Boolean = True): IZPlainDriver;
233 begin
234  // added by tohenk, 2009-10-11
235  // before PlainDriver is initialized, we can perform pre-library loading
236  // requirement check here, e.g. Embedded server argument params
237  Result := inherited GetPlainDriver(URL, False);
238  if Assigned(Result) then
239  begin
240  if Url.Properties.Count >0 then
241  (Result as IZMySQLPlainDriver).SetDriverOptions(Url.Properties);
242  // end added by tohenk, 2009-10-11
243  if InitDriver then Result.Initialize(Url.LibLocation);
244  end
245  else
246  raise Exception.Create('Can''t receive Plaindriver!');
247 end;
248 
249 {**
250  Returns the version of the plain driver library that will be used to open a connection
251  to the given URL.
252  @param url the URL of the database
253  @return the version number of the plain driver library for the give URL
254 }
255 function TZMySQLDriver.GetClientVersion(const Url: string): Integer;
256 var
257  TempURL: TZURL;
258 begin
259  TempURL := TZURL.Create(Url);
260  Result := ConvertMySQLVersionToSQLVersion((GetPlainDriver(TempUrl) as IZMySQLPlainDriver).GetClientVersion);
261  TempUrl.Free
262 end;
263 
264 { TZMySQLConnection }
265 
266 {**
267  Constructs this object and assignes the main properties.
268 }
269 procedure TZMySQLConnection.InternalCreate;
270 begin
271  FMetaData := TZMySQLDatabaseMetadata.Create(Self, Url);
272  if Self.Port = 0 then
273  Self.Port := MYSQL_PORT;
274  AutoCommit := True;
275  TransactIsolationLevel := tiNone;
276  FHandle := nil;
277 
278  { Processes connection properties. }
279  Open;
280 end;
281 
282 {**
283  Destroys this object and cleanups the memory.
284 }
285 destructor TZMySQLConnection.Destroy;
286 begin
287  inherited Destroy;
288 end;
289 
290 {**
291  Opens a connection to database server with specified parameters.
292 }
293 procedure TZMySQLConnection.Open;
294 var
295  LogMessage: string;
296  OldLevel: TZTransactIsolationLevel;
297  OldAutoCommit: Boolean;
298  UIntOpt: UInt;
299  MyBoolOpt: Byte;
300  ClientFlag : Cardinal;
301  SslCa, SslCaPath, SslKey, SslCert, SslCypher: PAnsiChar;
302  myopt: TMySQLOption;
303  sMyOpt: string;
304  my_client_Opt:TMYSQL_CLIENT_OPTIONS;
305  sMy_client_Opt, sMy_client_Char_Set:String;
306  ClientVersion: Integer;
307  SQL: PAnsiChar;
308 label setuint;
309 begin
310  if not Closed then
311  Exit;
312 
313  LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]);
314  FHandle := GetPlainDriver.Init(FHandle);
315  {EgonHugeist: Arrange Client-CodePage/CharacterSet first
316  Now we know if UTFEncoding is neccessary or not}
317  sMy_client_Char_Set := String(GetPlainDriver.GetConnectionCharacterSet(FHandle));
318  ConSettings^.ClientCodePage := GetPlainDriver.ValidateCharEncoding(sMy_client_Char_Set);
319  ZEncoding.SetConvertFunctions(ConSettings);
320  {EgonHugeist:
321  Now we know in which kind of CharacterSet we have to send the next Connection-Properties
322  before we can change to the CharacterSet we want to have here..
323  This sets also all environment-variables to the Codepaged Object.
324  Now the compatibility-functions ZString/ZPlainString working like
325  Database-expected Data has to be!!. }
326 
327  try
328  { Sets a default port number. }
329  if Port = 0 then
330  Port := MYSQL_PORT;
331 
332  { Turn on compression protocol. }
333  if StrToBoolEx(Info.Values['compress']) and
334  (Info.Values['MYSQL_OPT_COMPRESS'] = '') and
335  (Info.IndexOf('MYSQL_OPT_COMPRESS') = -1) then
336  Info.Values['MYSQL_OPT_COMPRESS'] := Info.Values['compress']; //check if user allready did set the value!
337  { Sets connection timeout. }
338  if (StrToIntDef(Info.Values['timeout'], 0) >= 0) and
339  (Info.Values['MYSQL_OPT_CONNECT_TIMEOUT'] = '') then //check if user allready did set the value!
340  Info.Values['MYSQL_OPT_CONNECT_TIMEOUT'] := Info.Values['timeout'];
341 
342  (*Added lines to handle option parameters 21 november 2007 marco cotroneo*)
343  ClientVersion := GetPlainDriver.GetClientVersion;
344  for myopt := low(TMySQLOption) to high(TMySQLOption) do
345  begin
346  sMyOpt:= GetEnumName(typeInfo(TMySQLOption), integer(myOpt));
347  if ClientVersion >= TMySqlOptionMinimumVersion[myopt] then //version checked (:
348  case myopt of
349  {unsigned int options ...}
350  MYSQL_OPT_CONNECT_TIMEOUT,
351  MYSQL_OPT_PROTOCOL,
352  MYSQL_OPT_READ_TIMEOUT,
353  MYSQL_OPT_WRITE_TIMEOUT:
354  if Info.Values[sMyOpt] <> '' then
355  begin
356 setuint: UIntOpt := StrToIntDef(Info.Values[sMyOpt], 0);
357  GetPlainDriver.SetOptions(FHandle, myopt, @UIntOpt);
358  end;
359  MYSQL_OPT_LOCAL_INFILE: {optional empty or unsigned int}
360  if Info.Values[sMyOpt] <> '' then
361  goto setuint
362  else
363  if Info.IndexOf(sMyOpt) > -1 then
364  GetPlainDriver.SetOptions(FHandle, myopt, nil);
365  { no value options }
366  MYSQL_OPT_COMPRESS,
367  MYSQL_OPT_GUESS_CONNECTION,
368  MYSQL_OPT_NAMED_PIPE,
369  MYSQL_OPT_USE_REMOTE_CONNECTION,
370  MYSQL_OPT_USE_EMBEDDED_CONNECTION,
371  MYSQL_OPT_USE_RESULT,
372  MYSQL_OPT_CONNECT_ATTR_RESET:
373  if (Info.Values[sMyOpt] <> '') or (Info.IndexOf(sMyOpt) > -1) then
374  GetPlainDriver.SetOptions(FHandle, myopt, nil);
375  { my_bool * options}
376  MYSQL_REPORT_DATA_TRUNCATION,
377  MYSQL_SECURE_AUTH,
378  MYSQL_OPT_RECONNECT,
379  MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
380  MYSQL_ENABLE_CLEARTEXT_PLUGIN,
381  MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
382  MYSQL_OPT_SSL_ENFORCE:
383  if Info.Values[sMyOpt] <> '' then
384  begin
385  MyBoolOpt := Ord(StrToBoolEx(Info.Values[sMyOpt]));
386  GetPlainDriver.SetOptions(FHandle, myopt, @MyBoolOpt);
387  end;
388  { unsigned char * options }
389  MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT,
390  MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER: ;//skip, processed down below
391  else
392  if Info.Values[sMyOpt] <> '' then
393  GetPlainDriver.SetOptions(FHandle, myopt, PAnsiChar(
394  ConSettings^.ConvFuncs.ZStringToRaw(Info.Values[sMyOpt],
395  ConSettings^.CTRL_CP, ConSettings^.ClientCodePage^.CP)));
396  end;
397  end;
398 
399  { Set ClientFlag }
400  ClientFlag := 0;
401  if Not StrToBoolEx(Info.Values['dbless'])
402  then ClientFlag := trunc(power(2, GetEnumValue( TypeInfo(TMYSQL_CLIENT_OPTIONS),'_CLIENT_CONNECT_WITH_DB')));
403 
404  for my_client_Opt := low(TMYSQL_CLIENT_OPTIONS) to high(TMYSQL_CLIENT_OPTIONS) do
405  begin
406  sMy_client_Opt:= GetEnumName(typeInfo(TMYSQL_CLIENT_OPTIONS), integer(my_client_Opt));
407  if StrToBoolEx(Info.Values[sMy_client_Opt]) then
408  ClientFlag:= ClientFlag or trunc(power(2, GetEnumValue(TypeInfo(TMYSQL_CLIENT_OPTIONS),sMy_client_Opt)));
409  end;
410 
411  { Set SSL properties before connect}
412  SslKey := nil; SslCert := nil; SslCa := nil; SslCaPath := nil; SslCypher := nil;
413  {EgonHugeist: If these Paramters MUST BE UTF8 then leave Param ceUTF8 in the
414  ZPlainString-function like else remove it and it adapts to default codepage}
415  if StrToBoolEx(Info.Values['MYSQL_SSL']) then
416  begin
417  if Info.Values['MYSQL_SSL_KEY'] <> '' then
418  SslKey := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_KEY'], ceUTF8));
419  if Info.Values['MYSQL_SSL_CERT'] <> '' then
420  SslCert := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_CERT'], ceUTF8));
421  if Info.Values['MYSQL_SSL_CA'] <> '' then
422  SslCa := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_CA'], ceUTF8));
423  if Info.Values['MYSQL_SSL_CAPATH'] <> '' then
424  SslCaPath := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_CAPATH'], ceUTF8));
425  if Info.Values['MYSQL_SSL_CYPHER'] <> '' then
426  SslCypher := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_CYPHER'], ceUTF8));
427  GetPlainDriver.SslSet(FHandle, SslKey, SslCert, SslCa, SslCaPath,
428  SslCypher);
429  DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol,
430  'SSL options set');
431  end;
432 
433  { Connect to MySQL database. }
434  if GetPlainDriver.RealConnect(FHandle, PAnsiChar(ZPlainString(HostName)),
435  PAnsiChar(ZPlainString(User)), PAnsiChar(ZPlainString(Password)),
436  PAnsiChar(ZPlainString(Database)), Port, nil,
437  ClientFlag) = nil then
438 
439  begin
440  CheckMySQLError(GetPlainDriver, FHandle, lcConnect, LogMessage);
441  DriverManager.LogError(lcConnect, PlainDriver.GetProtocol, LogMessage,
442  0, SUnknownError);
443  raise EZSQLException.Create(SCanNotConnectToServer);
444  end;
445  DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage);
446 
447  { Fix Bugs in certain Versions where real_conncet resets the Reconnect flag }
448  if (Info.Values['MYSQL_OPT_RECONNECT'] <> '') and
449  ((ClientVersion>=50013) and (ClientVersion<50019)) or
450  ((ClientVersion>=50100) and (ClientVersion<50106)) then
451  begin
452  MyBoolOpt := Ord(StrToBoolEx(Info.Values['MYSQL_OPT_RECONNECT']));
453  GetPlainDriver.SetOptions(FHandle, MYSQL_OPT_RECONNECT, @MyBoolOpt);
454  end;
455  if (FClientCodePage = '') and (sMy_client_Char_Set <> '') then
456  FClientCodePage := sMy_client_Char_Set;
457 
458  if (FClientCodePage <> sMy_client_Char_Set) then
459  begin
460  SQL := PAnsiChar(ZPlainString(Format('SET NAMES %s', [FClientCodePage])));
461  GetPlainDriver.ExecQuery(FHandle, SQL);
462  CheckMySQLError(GetPlainDriver, FHandle, lcExecute, String(SQL));
463  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, String(SQL));
464  end;
465  Self.CheckCharEncoding(FClientCodePage);
466 
467  { Sets transaction isolation level. }
468  OldLevel := TransactIsolationLevel;
469  TransactIsolationLevel := tiNone;
470  SetTransactionIsolation(OldLevel);
471 
472  { Sets an auto commit mode. }
473  OldAutoCommit := AutoCommit;
474  AutoCommit := True;
475  SetAutoCommit(OldAutoCommit);
476  except
477  GetPlainDriver.Close(FHandle);
478  GetPlainDriver.Despose(FHandle);
479  FHandle := nil;
480  raise;
481  end;
482 
483  inherited Open;
484 
485  if FClientCodePage = '' then //workaround for MySQL 4 down
486  begin
487  with CreateStatement.ExecuteQuery('show variables like "character_set_database"') do
488  begin
489  if Next then
490  FClientCodePage := GetString(2);
491  Close;
492  end;
493  ConSettings^.ClientCodePage := GetPlainDriver.ValidateCharEncoding(FClientCodePage);
494  ZEncoding.SetConvertFunctions(ConSettings);
495  end
496 end;
497 
498 {**
499  Ping Current Connection's server, if client was disconnected,
500  the connection is resumed.
501  @return 0 if succesfull or error code if any error occurs
502 }
503 function TZMySQLConnection.PingServer: Integer;
504 const
505  PING_ERROR_ZEOSCONNCLOSED = -1;
506 var
507  Closing: boolean;
508 begin
509  Closing := FHandle = nil;
510  if Closed or Closing then
511  Result := PING_ERROR_ZEOSCONNCLOSED
512  else
513  Result := GetPlainDriver.Ping(FHandle);
514 end;
515 
516 {**
517  Escape a string so it's acceptable for the Connection's server.
518  @param value string that should be escaped
519  @return Escaped string
520 }
521 function TZMySQLConnection.EscapeString(Value: RawByteString): RawByteString;
522 begin
523  Result := PlainDriver.EscapeString(Self.FHandle, Value, ConSettings);
524 end;
525 
526 {**
527  Creates a <code>Statement</code> object for sending
528  SQL statements to the database.
529  SQL statements without parameters are normally
530  executed using Statement objects. If the same SQL statement
531  is executed many times, it is more efficient to use a
532  <code>PreparedStatement</code> object.
533  <P>
534  Result sets created using the returned <code>Statement</code>
535  object will by default have forward-only type and read-only concurrency.
536 
537  @param Info a statement parameters.
538  @return a new Statement object
539 }
540 function TZMySQLConnection.CreateRegularStatement(Info: TStrings):
541  IZStatement;
542 begin
543  if IsClosed then
544  Open;
545  Result := TZMySQLStatement.Create(GetPlainDriver, Self, Info, FHandle);
546 end;
547 
548 {**
549  Creates a <code>PreparedStatement</code> object for sending
550  parameterized SQL statements to the database.
551 
552  A SQL statement with or without IN parameters can be
553  pre-compiled and stored in a PreparedStatement object. This
554  object can then be used to efficiently execute this statement
555  multiple times.
556 
557  <P><B>Note:</B> This method is optimized for handling
558  parametric SQL statements that benefit from precompilation. If
559  the driver supports precompilation,
560  the method <code>prepareStatement</code> will send
561  the statement to the database for precompilation. Some drivers
562  may not support precompilation. In this case, the statement may
563  not be sent to the database until the <code>PreparedStatement</code> is
564  executed. This has no direct effect on users; however, it does
565  affect which method throws certain SQLExceptions.
566 
567  Result sets created using the returned PreparedStatement will have
568  forward-only type and read-only concurrency, by default.
569 
570  @param sql a SQL statement that may contain one or more '?' IN
571  parameter placeholders
572  @param Info a statement parameters.
573  @return a new PreparedStatement object containing the
574  pre-compiled statement
575 }
576 function TZMySQLConnection.CreatePreparedStatement(const SQL: string;
577  Info: TStrings): IZPreparedStatement;
578 begin
579  if IsClosed then
580  Open;
581  if Assigned(Info) then
582  if StrToBoolEx(Info.Values['preferprepared']) then
583  Result := TZMySQLPreparedStatement.Create(GetPlainDriver, Self, SQL, Info)
584  else
585  Result := TZMySQLEmulatedPreparedStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle)
586  else
587  Result := TZMySQLEmulatedPreparedStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle);
588 end;
589 
590 {**
591  Creates a <code>CallableStatement</code> object for calling
592  database stored procedures.
593  The <code>CallableStatement</code> object provides
594  methods for setting up its IN and OUT parameters, and
595  methods for executing the call to a stored procedure.
596 
597  <P><B>Note:</B> This method is optimized for handling stored
598  procedure call statements. Some drivers may send the call
599  statement to the database when the method <code>prepareCall</code>
600  is done; others
601  may wait until the <code>CallableStatement</code> object
602  is executed. This has no
603  direct effect on users; however, it does affect which method
604  throws certain SQLExceptions.
605 
606  Result sets created using the returned CallableStatement will have
607  forward-only type and read-only concurrency, by default.
608 
609  @param sql a SQL statement that may contain one or more '?'
610  parameter placeholders. Typically this statement is a JDBC
611  function call escape string.
612  @param Info a statement parameters.
613  @return a new CallableStatement object containing the
614  pre-compiled SQL statement
615 }
616 function TZMySQLConnection.CreateCallableStatement(const SQL: string; Info: TStrings):
617  IZCallableStatement;
618 begin
619  Result := TZMySQLCallableStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle);
620 end;
621 
622 {**
623  Makes all changes made since the previous
624  commit/rollback permanent and releases any database locks
625  currently held by the Connection. This method should be
626  used only when auto-commit mode has been disabled.
627  @see #setAutoCommit
628 }
629 procedure TZMySQLConnection.Commit;
630 begin
631  if (TransactIsolationLevel <> tiNone) and (AutoCommit <> True)
632  and not Closed then
633  begin
634  If not GEtPlaindriver.Commit(FHandle) then
635  CheckMySQLError(GetPlainDriver, FHandle, lcExecute, 'Native Commit call');
636  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'Native Commit call');
637  end;
638 end;
639 
640 {**
641  Drops all changes made since the previous
642  commit/rollback and releases any database locks currently held
643  by this Connection. This method should be used only when auto-
644  commit has been disabled.
645  @see #setAutoCommit
646 }
647 procedure TZMySQLConnection.Rollback;
648 begin
649  if (TransactIsolationLevel <> tiNone) and (AutoCommit <> True)
650  and not Closed then
651  begin
652  If not GetPlaindriver.Rollback(FHandle) then
653  CheckMySQLError(GetPlainDriver, FHandle, lcExecute, 'Native Rollback call');
654  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'Native Rollback call');
655  end;
656 end;
657 
658 {**
659  Releases a Connection's database and JDBC resources
660  immediately instead of waiting for
661  them to be automatically released.
662 
663  <P><B>Note:</B> A Connection is automatically closed when it is
664  garbage collected. Certain fatal errors also result in a closed
665  Connection.
666 }
667 procedure TZMySQLConnection.Close;
668 var
669  LogMessage: string;
670 begin
671  if ( Closed ) or (not Assigned(PlainDriver)) then
672  Exit;
673 
674  GetPlainDriver.Close(FHandle);
675  GetPlainDriver.Despose(FHandle);
676  FHandle := nil;
677  LogMessage := Format('DISCONNECT FROM "%s"', [Database]);
678  DriverManager.LogMessage(lcDisconnect, GetPlainDriver.GetProtocol, LogMessage);
679  inherited Close;
680 end;
681 
682 {**
683  Gets a selected catalog name.
684  @return a selected catalog name.
685 }
686 function TZMySQLConnection.GetCatalog: string;
687 begin
688  Result := FCatalog;
689 end;
690 
691 {**
692  Sets a new selected catalog name.
693  @param Catalog a selected catalog name.
694 }
695 procedure TZMySQLConnection.SetCatalog(const Catalog: string);
696 begin
697  FCatalog := Catalog;
698 end;
699 
700 {**
701  Sets a new transact isolation level.
702  @param Level a new transact isolation level.
703 }
704 procedure TZMySQLConnection.SetTransactionIsolation(
705  Level: TZTransactIsolationLevel);
706 var
707  SQL: PAnsiChar;
708  testResult: Integer;
709 begin
710  if TransactIsolationLevel <> Level then
711  begin
712  inherited SetTransactionIsolation(Level);
713  testResult := 1;
714  if not Closed then
715  begin
716  case TransactIsolationLevel of
717  tiNone, tiReadUncommitted:
718  begin
719  SQL := 'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED';
720  testResult := GetPlainDriver.ExecQuery(FHandle, SQL);
721  end;
722  tiReadCommitted:
723  begin
724  SQL := 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED';
725  testResult := GetPlainDriver.ExecQuery(FHandle, SQL);
726  end;
727  tiRepeatableRead:
728  begin
729  SQL := 'SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ';
730  testResult := GetPlainDriver.ExecQuery(FHandle, SQL);
731  end;
732  tiSerializable:
733  begin
734  SQL := 'SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE';
735  testResult := GetPlainDriver.ExecQuery(FHandle, SQL);
736  end;
737  else
738  SQL := '';
739  end;
740  if (testResult <> 0) then
741  CheckMySQLError(GetPlainDriver, FHandle, lcExecute, String(SQL));
742  if SQL <> '' then
743  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, String(SQL));
744  end;
745  end;
746 end;
747 
748 {**
749  Sets this connection's auto-commit mode.
750  If a connection is in auto-commit mode, then all its SQL
751  statements will be executed and committed as individual
752  transactions. Otherwise, its SQL statements are grouped into
753  transactions that are terminated by a call to either
754  the method <code>commit</code> or the method <code>rollback</code>.
755  By default, new connections are in auto-commit mode.
756 
757  The commit occurs when the statement completes or the next
758  execute occurs, whichever comes first. In the case of
759  statements returning a ResultSet, the statement completes when
760  the last row of the ResultSet has been retrieved or the
761  ResultSet has been closed. In advanced cases, a single
762  statement may return multiple results as well as output
763  parameter values. In these cases the commit occurs when all results and
764  output parameter values have been retrieved.
765 
766  @param autoCommit true enables auto-commit; false disables auto-commit.
767 }
768 procedure TZMySQLConnection.SetAutoCommit(Value: Boolean);
769 begin
770  if AutoCommit <> Value then
771  begin
772  inherited SetAutoCommit(AutoCommit);
773 
774  if not Closed then
775  begin
776  if not GetPlaindriver.SetAutocommit(FHandle, Value) then
777  CheckMySQLError(GetPlainDriver, FHandle, lcExecute, 'Native SetAutoCommit '+BoolToStrEx(AutoCommit)+'call');
778  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'Native SetAutoCommit '+BoolToStrEx(AutoCommit)+'call');
779  end;
780  end;
781 end;
782 
783 {**
784  Gets client's full version number.
785  The format of the version returned must be XYYYZZZ where
786  X = Major version
787  YYY = Minor version
788  ZZZ = Sub version
789  @return this clients's full version number
790 }
791 function TZMySQLConnection.GetClientVersion: Integer;
792 begin
793  Result := ConvertMySQLVersionToSQLVersion( GetPlainDriver.GetClientVersion );
794 end;
795 
796 {**
797  Gets server's full version number.
798  The format of the returned version must be XYYYZZZ where
799  X = Major version
800  YYY = Minor version
801  ZZZ = Sub version
802  @return this clients's full version number
803 }
804 function TZMySQLConnection.GetHostVersion: Integer;
805 begin
806  Result := ConvertMySQLVersionToSQLVersion( GetPlainDriver.GetServerVersion(FHandle) );
807  CheckMySQLError(GetPlainDriver, FHandle, lcExecute, 'mysql_get_server_version()');
808 end;
809 
810 {**
811  Gets a reference to MySQL connection handle.
812  @return a reference to MySQL connection handle.
813 }
814 function TZMySQLConnection.GetConnectionHandle: PZMySQLConnect;
815 begin
816  Result := FHandle;
817 end;
818 
819 {**
820  Gets a MySQL plain driver interface.
821  @return a MySQL plain driver interface.
822 }
823 function TZMySQLConnection.GetPlainDriver: IZMySQLPlainDriver;
824 begin
825  Result := Self.PlainDriver as IZMySQLPlainDriver;
826 end;
827 
828 {**
829  EgonHugeist:
830  Returns the BinaryString in a Tokenizer-detectable kind
831  If the Tokenizer don't need to predetect it Result := BinaryString
832  @param Value represents the Binary-String
833  @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3)
834  @result the detectable Binary String
835 }
836 function TZMySQLConnection.GetEscapeString(const Value: ZWideString): ZWideString;
837 begin
838  Result := inherited GetEscapeString(GetPlainDriver.EscapeString(FHandle, Value, ConSettings));
839 end;
840 
841 function TZMySQLConnection.GetEscapeString(const Value: RawByteString): RawByteString;
842 begin
843  Result := inherited GetEscapeString(GetPlainDriver.EscapeString(FHandle, Value, ConSettings));
844 end;
845 
846 initialization
847  MySQLDriver := TZMySQLDriver.Create;
848  DriverManager.RegisterDriver(MySQLDriver);
849 finalization
850  if DriverManager <> nil then
851  DriverManager.DeregisterDriver(MySQLDriver);
852  MySQLDriver := nil;
853 end.
854