mysqlconn.inc 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  1. {$mode objfpc}{$H+}
  2. interface
  3. uses
  4. Classes, SysUtils,bufdataset,sqldb,db,dynlibs,ctypes,
  5. {$IFDEF mysql55}
  6. mysql55dyn;
  7. {$ELSE}
  8. {$IFDEF mysql51}
  9. mysql51dyn;
  10. {$ELSE}
  11. {$IfDef mysql50}
  12. mysql50dyn;
  13. {$ELSE}
  14. {$IfDef mysql41}
  15. mysql41dyn;
  16. {$ELSE}
  17. {$IFDEF mysql4} // temporary backwards compatibility for Lazarus
  18. mysql40dyn;
  19. {$ELSE}
  20. mysql40dyn;
  21. {$EndIf}
  22. {$EndIf}
  23. {$EndIf}
  24. {$endif}
  25. {$endif}
  26. Const
  27. {$IFDEF mysql55}
  28. MySQLVersion = '5.5';
  29. {$else}
  30. {$IFDEF mysql51}
  31. MySQLVersion = '5.1';
  32. {$else}
  33. {$IfDef mysql50}
  34. MySQLVersion = '5.0';
  35. {$ELSE}
  36. {$IfDef mysql41}
  37. MySQLVersion = '4.1';
  38. {$ELSE}
  39. {$IFDEF mysql4} // temporary backwards compatibility for Lazarus
  40. MySQLVersion = '4.0';
  41. {$ELSE}
  42. MySQLVersion = '4.0';
  43. {$EndIf}
  44. {$EndIf}
  45. {$EndIf}
  46. {$endif}
  47. {$endif}
  48. Type
  49. TTransactionName = Class(TSQLHandle)
  50. protected
  51. end;
  52. { TCursorName }
  53. TCursorName = Class(TSQLCursor)
  54. protected
  55. FRes: PMYSQL_RES; { Record pointer }
  56. FNeedData : Boolean;
  57. FStatement : String;
  58. Row : MYSQL_ROW;
  59. Lengths : pculong; { Lengths of the columns of the current row }
  60. RowsAffected : QWord;
  61. LastInsertID : QWord;
  62. ParamBinding : TParamBinding;
  63. ParamReplaceString : String;
  64. MapDSRowToMSQLRow : array of integer;
  65. end;
  66. { TConnectionName }
  67. TConnectionName = class (TSQLConnection)
  68. private
  69. FHostInfo: String;
  70. FServerInfo: String;
  71. FMySQL : PMySQL;
  72. function GetClientInfo: string;
  73. function GetServerStatus: String;
  74. procedure ConnectMySQL(var HMySQL : PMySQL;H,U,P : pchar);
  75. procedure ExecuteDirectMySQL(const query : string);
  76. function EscapeString(const Str : string) : string;
  77. protected
  78. function StrToStatementType(s : string) : TStatementType; override;
  79. Procedure ConnectToServer; virtual;
  80. Procedure SelectDatabase; virtual;
  81. function MySQLDataType(AField: PMYSQL_FIELD; var NewType: TFieldType; var NewSize: Integer): Boolean;
  82. function MySQLWriteData(AField: PMYSQL_FIELD; FieldDef: TFieldDef; Source, Dest: PChar; Len: integer; out CreateBlob : boolean): Boolean;
  83. // SQLConnection methods
  84. procedure DoInternalConnect; override;
  85. procedure DoInternalDisconnect; override;
  86. function GetHandle : pointer; override;
  87. function GetAsSQLText(Field : TField) : string; overload; override;
  88. function GetAsSQLText(Param : TParam) : string; overload; override;
  89. Function AllocateCursorHandle : TSQLCursor; override;
  90. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  91. Function AllocateTransactionHandle : TSQLHandle; override;
  92. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
  93. procedure UnPrepareStatement(cursor:TSQLCursor); override;
  94. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  95. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction;AParams : TParams); override;
  96. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); override;
  97. function Fetch(cursor : TSQLCursor) : boolean; override;
  98. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  99. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor;ATransaction : TSQLTransaction); override;
  100. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  101. function Commit(trans : TSQLHandle) : boolean; override;
  102. function RollBack(trans : TSQLHandle) : boolean; override;
  103. function StartdbTransaction(trans : TSQLHandle; AParams : string) : boolean; override;
  104. procedure CommitRetaining(trans : TSQLHandle); override;
  105. procedure RollBackRetaining(trans : TSQLHandle); override;
  106. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
  107. procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); override;
  108. function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
  109. Public
  110. constructor Create(AOwner : TComponent); override;
  111. procedure GetFieldNames(const TableName : string; List : TStrings); override;
  112. procedure GetTableNames(List : TStrings; SystemTables : Boolean = false); override;
  113. procedure CreateDB; override;
  114. procedure DropDB; override;
  115. Property ServerInfo : String Read FServerInfo;
  116. Property HostInfo : String Read FHostInfo;
  117. property ClientInfo: string read GetClientInfo;
  118. property ServerStatus : String read GetServerStatus;
  119. published
  120. property DatabaseName;
  121. property HostName;
  122. property KeepConnection;
  123. property LoginPrompt;
  124. property Params;
  125. property Port stored false;
  126. property OnLogin;
  127. end;
  128. { TMySQLConnectionDef }
  129. TMySQLConnectionDef = Class(TConnectionDef)
  130. Class Function TypeName : String; override;
  131. Class Function ConnectionClass : TSQLConnectionClass; override;
  132. Class Function Description : String; override;
  133. end;
  134. EMySQLError = Class(Exception);
  135. {$ifdef mysql55}
  136. TMySQL55Connection = Class(TConnectionName);
  137. TMySQL55ConnectionDef = Class(TMySQLConnectionDef);
  138. TMySQL55Transaction = Class(TTransactionName);
  139. TMySQL55Cursor = Class(TCursorName);
  140. {$else}
  141. {$IfDef mysql51}
  142. TMySQL51Connection = Class(TConnectionName);
  143. TMySQL51ConnectionDef = Class(TMySQLConnectionDef);
  144. TMySQL51Transaction = Class(TTransactionName);
  145. TMySQL51Cursor = Class(TCursorName);
  146. {$ELSE}
  147. {$IfDef mysql50}
  148. TMySQL50Connection = Class(TConnectionName);
  149. TMySQL50ConnectionDef = Class(TMySQLConnectionDef);
  150. TMySQL50Transaction = Class(TTransactionName);
  151. TMySQL50Cursor = Class(TCursorName);
  152. {$ELSE}
  153. {$IfDef mysql41}
  154. TMySQL41Connection = Class(TConnectionName);
  155. TMySQL41ConnectionDef = Class(TMySQLConnectionDef);
  156. TMySQL41Transaction = Class(TTransactionName);
  157. TMySQL41Cursor = Class(TCursorName);
  158. {$ELSE}
  159. {$IFDEF mysql4} // temporary backwards compatibility for Lazarus
  160. TMySQLConnection = Class(TConnectionName);
  161. TMySQL40ConnectionDef = Class(TMySQLConnectionDef);
  162. TMySQLTransaction = Class(TTransactionName);
  163. TMySQLCursor = Class(TCursorName);
  164. {$ELSE}
  165. TMySQL40Connection = Class(TConnectionName);
  166. TMySQL40ConnectionDef = Class(TMySQLConnectionDef);
  167. TMySQL40Transaction = Class(TTransactionName);
  168. TMySQL40Cursor = Class(TCursorName);
  169. {$EndIf}
  170. {$EndIf}
  171. {$endif}
  172. {$EndIf}
  173. {$ENDIF}
  174. implementation
  175. uses
  176. dbconst,
  177. strutils,
  178. dateutils,
  179. FmtBCD;
  180. const
  181. Mysql_Option_Names : array[mysql_option] of string = ('MYSQL_OPT_CONNECT_TIMEOUT','MYSQL_OPT_COMPRESS',
  182. 'MYSQL_OPT_NAMED_PIPE','MYSQL_INIT_COMMAND',
  183. 'MYSQL_READ_DEFAULT_FILE','MYSQL_READ_DEFAULT_GROUP',
  184. 'MYSQL_SET_CHARSET_DIR','MYSQL_SET_CHARSET_NAME',
  185. 'MYSQL_OPT_LOCAL_INFILE','MYSQL_OPT_PROTOCOL',
  186. 'MYSQL_SHARED_MEMORY_BASE_NAME','MYSQL_OPT_READ_TIMEOUT',
  187. 'MYSQL_OPT_WRITE_TIMEOUT','MYSQL_OPT_USE_RESULT',
  188. 'MYSQL_OPT_USE_REMOTE_CONNECTION','MYSQL_OPT_USE_EMBEDDED_CONNECTION',
  189. 'MYSQL_OPT_GUESS_CONNECTION','MYSQL_SET_CLIENT_IP',
  190. 'MYSQL_SECURE_AUTH'
  191. {$IFDEF MYSQL50_UP}
  192. ,'MYSQL_REPORT_DATA_TRUNCATION', 'MYSQL_OPT_RECONNECT'
  193. {$IFDEF mysql51_UP}
  194. ,'MYSQL_OPT_SSL_VERIFY_SERVER_CERT'
  195. {$IFDEF mysql55}
  196. ,'MYSQL_PLUGIN_DIR', 'MYSQL_DEFAULT_AUTH'
  197. {$ENDIF}
  198. {$ENDIF}
  199. {$ENDIF}
  200. );
  201. Resourcestring
  202. SErrServerConnectFailed = 'Server connect failed.';
  203. SErrDatabaseSelectFailed = 'failed to select database: %s';
  204. SErrDatabaseCreate = 'Failed to create database: %s';
  205. SErrDatabaseDrop = 'Failed to drop database: %s';
  206. SErrNoData = 'No data for record';
  207. SErrExecuting = 'Error executing query: %s';
  208. SErrFetchingdata = 'Error fetching row data: %s';
  209. SErrGettingResult = 'Error getting result set: %s';
  210. SErrNoQueryResult = 'No result from query.';
  211. SErrVersionMismatch = '%s can not work with the installed MySQL client version: Expected (%s), got (%s).';
  212. SErrSettingParameter = 'Error setting parameter "%s"';
  213. Procedure MySQLError(R : PMySQL;Msg: String;Comp : TComponent);
  214. Var
  215. MySQLMsg : String;
  216. begin
  217. If (R<>Nil) then
  218. begin
  219. MySQLMsg:=Strpas(mysql_error(R));
  220. DatabaseErrorFmt(Msg,[MySQLMsg],Comp);
  221. end
  222. else
  223. DatabaseError(Msg,Comp);
  224. end;
  225. function MysqlOption(const OptionName: string; out AMysql_Option: mysql_option) : boolean;
  226. var AMysql_Option_i: mysql_option;
  227. begin
  228. result := false;
  229. for AMysql_Option_i:=low(AMysql_Option) to high(AMysql_Option) do
  230. if sametext(Mysql_Option_Names[AMysql_Option_i],OptionName) then
  231. begin
  232. result := true;
  233. AMysql_Option:=AMysql_Option_i;
  234. break;
  235. end;
  236. end;
  237. { TConnectionName }
  238. function TConnectionName.StrToStatementType(s : string) : TStatementType;
  239. begin
  240. s:=Lowercase(s);
  241. if (s='analyze') or (s='check') or (s='checksum') or (s='optimize') or (s='repair') or (s='show') then
  242. exit(stSelect)
  243. else if s='call' then
  244. exit(stExecProcedure)
  245. else
  246. Result := inherited StrToStatementType(s);
  247. end;
  248. function TConnectionName.GetClientInfo: string;
  249. begin
  250. // To make it possible to call this if there's no connection yet
  251. InitialiseMysql;
  252. Try
  253. Result:=strpas(mysql_get_client_info());
  254. Finally
  255. ReleaseMysql;
  256. end;
  257. end;
  258. function TConnectionName.GetServerStatus: String;
  259. begin
  260. CheckConnected;
  261. Result := mysql_stat(FMYSQL);
  262. end;
  263. procedure TConnectionName.ConnectMySQL(var HMySQL : PMySQL;H,U,P : pchar);
  264. Var
  265. APort : Cardinal;
  266. i,e: integer;
  267. AMysql_Option: mysql_option;
  268. OptStr: string;
  269. OptInt: cuint;
  270. Opt: pointer;
  271. begin
  272. HMySQL := mysql_init(HMySQL);
  273. APort:=Abs(StrToIntDef(Params.Values['Port'],0));
  274. for i := 0 to Params.Count-1 do
  275. begin
  276. if MysqlOption(params.Names[i],AMysql_Option) then
  277. begin
  278. OptStr:=params.ValueFromIndex[i];
  279. val(OptStr,OptInt,e);
  280. if e=0 then
  281. Opt := @OptInt
  282. else
  283. Opt := pchar(OptStr);
  284. if mysql_options(HMySQL,AMysql_Option,Opt) <> 0 then
  285. MySQLError(HMySQL,Format(SErrSettingParameter,[params.Names[i]]),Self);
  286. end;
  287. end;
  288. HMySQL:=mysql_real_connect(HMySQL,PChar(H),PChar(U),Pchar(P),Nil,APort,Nil,CLIENT_MULTI_RESULTS); //CLIENT_MULTI_RESULTS is required by CALL SQL statement(executes stored procedure), that produces result sets
  289. If (HMySQL=Nil) then
  290. MySQLError(Nil,SErrServerConnectFailed,Self);
  291. // MySQL _Server_ version 4.1 and later
  292. // major_version*10000 + minor_version *100 + sub_version
  293. if (trim(CharSet) <> '') and (4*10000 + 1*100 <= mysql_get_server_version(HMySQL)) then
  294. begin
  295. // Only available for mysql 5.0.7 and later...
  296. // if (mysql_set_character_set(HMySQL, PChar(CharSet)) <> 0) then
  297. if mysql_query(FMySQL,PChar('SET CHARACTER SET ''' + EscapeString(CharSet) +''''))<>0 then
  298. MySQLError(HMySQL,SErrExecuting,Self);
  299. end;
  300. end;
  301. function TConnectionName.GetAsSQLText(Field : TField) : string;
  302. var esc_str : pchar;
  303. begin
  304. if (not assigned(field)) or field.IsNull then Result := 'Null'
  305. else if field.DataType = ftString then
  306. Result := '''' + EscapeString(field.AsString) + ''''
  307. else Result := inherited GetAsSqlText(field);
  308. end;
  309. function TConnectionName.GetAsSQLText(Param: TParam) : string;
  310. var esc_str : pchar;
  311. begin
  312. if (not assigned(param)) or param.IsNull then Result := 'Null'
  313. else if param.DataType in [ftString,ftFixedChar,ftBlob,ftMemo,ftBytes,ftVarBytes] then
  314. Result := '''' + EscapeString(Param.AsString) + ''''
  315. else Result := inherited GetAsSqlText(Param);
  316. end;
  317. procedure TConnectionName.ConnectToServer;
  318. Var
  319. H,U,P : String;
  320. begin
  321. H:=HostName;
  322. U:=UserName;
  323. P:=Password;
  324. ConnectMySQL(FMySQL,pchar(H),pchar(U),pchar(P));
  325. FServerInfo := strpas(mysql_get_server_info(FMYSQL));
  326. FHostInfo := strpas(mysql_get_host_info(FMYSQL));
  327. end;
  328. procedure TConnectionName.SelectDatabase;
  329. begin
  330. if mysql_select_db(FMySQL,pchar(DatabaseName))<>0 then
  331. MySQLError(FMySQL,SErrDatabaseSelectFailed,Self);
  332. end;
  333. procedure TConnectionName.CreateDB;
  334. begin
  335. ExecuteDirectMySQL('CREATE DATABASE ' +DatabaseName);
  336. end;
  337. procedure TConnectionName.DropDB;
  338. begin
  339. ExecuteDirectMySQL('DROP DATABASE ' +DatabaseName);
  340. end;
  341. procedure TConnectionName.ExecuteDirectMySQL(const query : string);
  342. var H,U,P : String;
  343. AMySQL : PMySQL;
  344. begin
  345. CheckDisConnected;
  346. InitialiseMysql;
  347. try
  348. H:=HostName;
  349. U:=UserName;
  350. P:=Password;
  351. AMySQL := nil;
  352. ConnectMySQL(AMySQL,pchar(H),pchar(U),pchar(P));
  353. try
  354. if mysql_query(AMySQL,pchar(query))<>0 then
  355. MySQLError(AMySQL,SErrExecuting,Self);
  356. finally
  357. mysql_close(AMySQL);
  358. end;
  359. finally
  360. ReleaseMysql;
  361. end;
  362. end;
  363. function TConnectionName.EscapeString(const Str: string): string;
  364. var Len : integer;
  365. begin
  366. SetLength(result,length(str)*2+1);
  367. Len := mysql_real_escape_string(FMySQL,pchar(Result),pchar(Str),length(Str));
  368. SetLength(result,Len);
  369. end;
  370. procedure TConnectionName.DoInternalConnect;
  371. var
  372. FullVersion,
  373. ClientVerStr: string;
  374. begin
  375. InitialiseMysql;
  376. Fullversion:=strpas(mysql_get_client_info());
  377. ClientVerStr := copy(FullVersion,1,3);
  378. If (ClientVerStr<>MySQLVersion) then
  379. Raise EInOutError.CreateFmt(SErrVersionMisMatch,[ClassName,MySQLVersion,FullVersion]);
  380. inherited DoInternalConnect;
  381. ConnectToServer;
  382. SelectDatabase;
  383. end;
  384. procedure TConnectionName.DoInternalDisconnect;
  385. begin
  386. inherited DoInternalDisconnect;
  387. mysql_close(FMySQL);
  388. FMySQL:=Nil;
  389. ReleaseMysql;
  390. end;
  391. function TConnectionName.GetHandle: pointer;
  392. begin
  393. Result:=FMySQL;
  394. end;
  395. function TConnectionName.AllocateCursorHandle: TSQLCursor;
  396. begin
  397. {$IfDef mysql55}
  398. Result:=TMySQL55Cursor.Create;
  399. {$ELSE}
  400. {$IfDef mysql51}
  401. Result:=TMySQL51Cursor.Create;
  402. {$ELSE}
  403. {$IfDef mysql50}
  404. Result:=TMySQL50Cursor.Create;
  405. {$ELSE}
  406. {$IfDef mysql41}
  407. Result:=TMySQL41Cursor.Create;
  408. {$ELSE}
  409. {$IFDEF mysql4} // temporary backwards compatibility for Lazarus
  410. Result:=TMySQLCursor.Create;
  411. {$ELSE}
  412. Result:=TMySQL40Cursor.Create;
  413. {$EndIf}
  414. {$EndIf}
  415. {$EndIf}
  416. {$EndIf}
  417. {$endif}
  418. end;
  419. Procedure TConnectionName.DeAllocateCursorHandle(var cursor : TSQLCursor);
  420. begin
  421. FreeAndNil(cursor);
  422. end;
  423. function TConnectionName.AllocateTransactionHandle: TSQLHandle;
  424. begin
  425. // Result:=TTransactionName.Create;
  426. Result := nil;
  427. end;
  428. procedure TConnectionName.PrepareStatement(cursor: TSQLCursor;
  429. ATransaction: TSQLTransaction; buf: string;AParams : TParams);
  430. begin
  431. // if assigned(AParams) and (AParams.count > 0) then
  432. // DatabaseError('Parameters (not) yet supported for the MySQL SqlDB connection.',self);
  433. With Cursor as TCursorName do
  434. begin
  435. FStatement:=Buf;
  436. if assigned(AParams) and (AParams.count > 0) then
  437. FStatement := AParams.ParseSQL(FStatement,false,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psSimulated,paramBinding,ParamReplaceString);
  438. if FStatementType in [stSelect,stExecProcedure] then
  439. FNeedData:=True;
  440. end
  441. end;
  442. procedure TConnectionName.UnPrepareStatement(cursor: TSQLCursor);
  443. Var
  444. C : TCursorName;
  445. begin
  446. C:=Cursor as TCursorName;
  447. if assigned(C.FRes) then //ExecSQL with dataset returned
  448. begin
  449. mysql_free_result(C.FRes);
  450. C.FRes:=nil;
  451. end;
  452. end;
  453. procedure TConnectionName.FreeFldBuffers(cursor: TSQLCursor);
  454. Var
  455. C : TCursorName;
  456. begin
  457. C:=Cursor as TCursorName;
  458. if c.FStatementType in [stSelect,stExecProcedure] then
  459. c.FNeedData:=False;
  460. if assigned(C.FRes) then
  461. begin
  462. mysql_free_result(C.FRes);
  463. C.FRes:=Nil;
  464. end;
  465. SetLength(c.MapDSRowToMSQLRow,0);
  466. inherited;
  467. end;
  468. procedure TConnectionName.Execute(cursor: TSQLCursor;
  469. atransaction: tSQLtransaction;AParams : TParams);
  470. Var
  471. C : TCursorName;
  472. i : integer;
  473. ParamNames,ParamValues : array of string;
  474. Res: PMYSQL_RES;
  475. begin
  476. C:=Cursor as TCursorName;
  477. If (C.FRes=Nil) then
  478. begin
  479. if Assigned(AParams) and (AParams.count > 0) then
  480. begin
  481. setlength(ParamNames,AParams.Count);
  482. setlength(ParamValues,AParams.Count);
  483. for i := 0 to AParams.count -1 do
  484. begin
  485. ParamNames[AParams.count-i-1] := C.ParamReplaceString+inttostr(AParams[i].Index+1);
  486. ParamValues[AParams.count-i-1] := GetAsSQLText(AParams[i]);
  487. end;
  488. // paramreplacestring kan een probleem geven bij postgres als hij niet meer gewoon $ is?
  489. C.FStatement := stringsreplace(C.FStatement,ParamNames,ParamValues,[rfReplaceAll]);
  490. end;
  491. if mysql_query(FMySQL,Pchar(C.FStatement))<>0 then
  492. MySQLError(FMYSQL,SErrExecuting,Self)
  493. else
  494. begin
  495. C.RowsAffected := mysql_affected_rows(FMYSQL);
  496. C.LastInsertID := mysql_insert_id(FMYSQL);
  497. if C.FNeedData then
  498. repeat
  499. Res:=mysql_store_result(FMySQL); //returns a null pointer if the statement didn't return a result set
  500. if Res<>nil then
  501. begin
  502. mysql_free_result(C.FRes);
  503. C.FRes:=Res;
  504. end;
  505. until mysql_next_result(FMySQL)<>0;
  506. end;
  507. end;
  508. end;
  509. function TConnectionName.MySQLDataType(AField: PMYSQL_FIELD; var NewType: TFieldType; var NewSize: Integer): Boolean;
  510. var ASize, ADecimals: integer;
  511. begin
  512. Result := True;
  513. ASize := AField^.length;
  514. NewSize := 0;
  515. case AField^.ftype of
  516. FIELD_TYPE_LONGLONG:
  517. begin
  518. NewType := ftLargeint;
  519. end;
  520. FIELD_TYPE_TINY, FIELD_TYPE_SHORT, FIELD_TYPE_YEAR:
  521. begin
  522. NewType := ftSmallint;
  523. end;
  524. FIELD_TYPE_LONG, FIELD_TYPE_INT24:
  525. begin
  526. if AField^.flags and AUTO_INCREMENT_FLAG <> 0 then
  527. NewType := ftAutoInc
  528. else
  529. NewType := ftInteger;
  530. end;
  531. {$ifdef mysql50_up}
  532. FIELD_TYPE_NEWDECIMAL,
  533. {$endif}
  534. FIELD_TYPE_DECIMAL:
  535. begin
  536. ADecimals:=AField^.decimals;
  537. if (ADecimals < 5) and (ASize-2-ADecimals < 15) then //ASize is display size i.e. with sign and decimal point
  538. NewType := ftBCD
  539. else if (ADecimals = 0) and (ASize < 20) then
  540. NewType := ftLargeInt
  541. else
  542. NewType := ftFmtBCD;
  543. NewSize := ADecimals;
  544. end;
  545. FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE:
  546. begin
  547. NewType := ftFloat;
  548. end;
  549. FIELD_TYPE_TIMESTAMP, FIELD_TYPE_DATETIME:
  550. begin
  551. NewType := ftDateTime;
  552. end;
  553. FIELD_TYPE_DATE:
  554. begin
  555. NewType := ftDate;
  556. end;
  557. FIELD_TYPE_TIME:
  558. begin
  559. NewType := ftTime;
  560. end;
  561. FIELD_TYPE_VAR_STRING, FIELD_TYPE_STRING, FIELD_TYPE_ENUM, FIELD_TYPE_SET:
  562. begin
  563. // Since mysql server version 5.0.3 string-fields with a length of more
  564. // then 256 characters are suported
  565. if ASize>dsMaxStringSize then
  566. NewType := ftMemo
  567. else
  568. begin
  569. if AField^.ftype = FIELD_TYPE_STRING then
  570. NewType := ftFixedChar
  571. else
  572. NewType := ftString;
  573. {$IFDEF MYSQL50_UP}
  574. if AField^.charsetnr = 63 then //BINARY vs. CHAR, VARBINARY vs. VARCHAR
  575. if NewType = ftFixedChar then
  576. NewType := ftBytes
  577. else
  578. NewType := ftVarBytes;
  579. {$ENDIF}
  580. NewSize := ASize;
  581. end;
  582. end;
  583. FIELD_TYPE_BLOB:
  584. begin
  585. {$IFDEF MYSQL50_UP}
  586. if AField^.charsetnr = 63 then //character set is binary
  587. NewType := ftBlob
  588. else
  589. NewType := ftMemo;
  590. {$ELSE}
  591. NewType := ftBlob;
  592. {$ENDIF}
  593. end;
  594. {$IFDEF MYSQL50_UP}
  595. FIELD_TYPE_BIT:
  596. NewType := ftLargeInt;
  597. {$ENDIF}
  598. else
  599. Result := False;
  600. end;
  601. end;
  602. procedure TConnectionName.AddFieldDefs(cursor: TSQLCursor;
  603. FieldDefs: TfieldDefs);
  604. var
  605. C : TCursorName;
  606. I, TF, FC: Integer;
  607. field: PMYSQL_FIELD;
  608. DFT: TFieldType;
  609. DFS: Integer;
  610. begin
  611. // Writeln('MySQL: Adding fielddefs');
  612. C:=(Cursor as TCursorName);
  613. If (C.FRes=Nil) then
  614. begin
  615. // Writeln('res is nil');
  616. MySQLError(FMySQL,SErrNoQueryResult,Self);
  617. end;
  618. // Writeln('MySQL: have result');
  619. FC:=mysql_num_fields(C.FRes);
  620. SetLength(c.MapDSRowToMSQLRow,FC);
  621. TF := 1;
  622. For I:= 0 to FC-1 do
  623. begin
  624. field := mysql_fetch_field_direct(C.FRES, I);
  625. // Writeln('MySQL: creating fielddef ',I+1);
  626. if MySQLDataType(field, DFT, DFS) then
  627. begin
  628. TFieldDef.Create(FieldDefs, FieldDefs.MakeNameUnique(field^.name), DFT, DFS,
  629. (field^.flags and (AUTO_INCREMENT_FLAG or NOT_NULL_FLAG {$IFDEF MYSQL50_UP}or NO_DEFAULT_VALUE_FLAG{$ENDIF})) = (NOT_NULL_FLAG {$IFDEF MYSQL50_UP}or NO_DEFAULT_VALUE_FLAG{$ENDIF}),
  630. TF);
  631. c.MapDSRowToMSQLRow[TF-1] := I;
  632. inc(TF);
  633. end
  634. end;
  635. // Writeln('MySQL: Finished adding fielddefs');
  636. end;
  637. function TConnectionName.Fetch(cursor: TSQLCursor): boolean;
  638. Var
  639. C : TCursorName;
  640. begin
  641. C:=Cursor as TCursorName;
  642. C.Row:=MySQL_Fetch_row(C.FRes);
  643. Result:=(C.Row<>Nil);
  644. if Result then
  645. C.Lengths := mysql_fetch_lengths(C.FRes)
  646. else
  647. C.Lengths := nil;
  648. end;
  649. function TConnectionName.LoadField(cursor : TSQLCursor;
  650. FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean;
  651. var
  652. field: PMYSQL_FIELD;
  653. C : TCursorName;
  654. i : integer;
  655. begin
  656. // Writeln('LoadFieldsFromBuffer');
  657. C:=Cursor as TCursorName;
  658. if (C.Row=nil) or (C.Lengths=nil) then
  659. begin
  660. // Writeln('LoadFieldsFromBuffer: row=nil');
  661. MySQLError(FMySQL,SErrFetchingData,Self);
  662. end;
  663. i := c.MapDSRowToMSQLRow[FieldDef.FieldNo-1];
  664. field := mysql_fetch_field_direct(C.FRES, i);
  665. Result := MySQLWriteData(field, FieldDef, C.Row[i], Buffer, C.Lengths[i], CreateBlob);
  666. end;
  667. procedure TConnectionName.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  668. ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  669. var
  670. C : TCursorName;
  671. i : integer;
  672. len : longint;
  673. begin
  674. C:=Cursor as TCursorName;
  675. if (C.Row=nil) or (C.Lengths=nil) then
  676. MySQLError(FMySQL,SErrFetchingData,Self);
  677. i := c.MapDSRowToMSQLRow[FieldDef.FieldNo-1];
  678. len := C.Lengths[i];
  679. ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, len);
  680. Move(C.Row[i]^, ABlobBuf^.BlobBuffer^.Buffer^, len);
  681. ABlobBuf^.BlobBuffer^.Size := len;
  682. end;
  683. function InternalStrToFloat(S: string): Extended;
  684. var
  685. I: Integer;
  686. Tmp: string;
  687. begin
  688. Tmp := '';
  689. for I := 1 to Length(S) do
  690. begin
  691. if not (S[I] in ['0'..'9', '+', '-', 'E', 'e']) then
  692. Tmp := Tmp + DecimalSeparator
  693. else
  694. Tmp := Tmp + S[I];
  695. end;
  696. Result := StrToFloat(Tmp);
  697. end;
  698. function InternalStrToCurrency(S: string): Extended;
  699. var
  700. I: Integer;
  701. Tmp: string;
  702. begin
  703. Tmp := '';
  704. for I := 1 to Length(S) do
  705. begin
  706. if not (S[I] in ['0'..'9', '+', '-', 'E', 'e']) then
  707. Tmp := Tmp + DecimalSeparator
  708. else
  709. Tmp := Tmp + S[I];
  710. end;
  711. Result := StrToCurr(Tmp);
  712. end;
  713. function InternalStrToDate(S: string): TDateTime;
  714. var
  715. EY, EM, ED: Word;
  716. begin
  717. EY := StrToInt(Copy(S,1,4));
  718. EM := StrToInt(Copy(S,6,2));
  719. ED := StrToInt(Copy(S,9,2));
  720. if (EY = 0) or (EM = 0) or (ED = 0) then
  721. Result:=0
  722. else
  723. Result:=EncodeDate(EY, EM, ED);
  724. end;
  725. function InternalStrToDateTime(S: string): TDateTime;
  726. var
  727. EY, EM, ED: Word;
  728. EH, EN, ES: Word;
  729. begin
  730. EY := StrToInt(Copy(S, 1, 4));
  731. EM := StrToInt(Copy(S, 6, 2));
  732. ED := StrToInt(Copy(S, 9, 2));
  733. EH := StrToInt(Copy(S, 12, 2));
  734. EN := StrToInt(Copy(S, 15, 2));
  735. ES := StrToInt(Copy(S, 18, 2));
  736. if (EY = 0) or (EM = 0) or (ED = 0) then
  737. Result := 0
  738. else
  739. Result := EncodeDate(EY, EM, ED);
  740. Result := ComposeDateTime(Result,EncodeTime(EH, EN, ES, 0));
  741. end;
  742. function InternalStrToTime(S: string): TDateTime;
  743. var
  744. EH, EM, ES: Word;
  745. p: integer;
  746. begin
  747. p := 1;
  748. EH := StrToInt(ExtractSubstr(S, p, [':'])); //hours can be 2 or 3 digits
  749. EM := StrToInt(ExtractSubstr(S, p, [':']));
  750. ES := StrToInt(ExtractSubstr(S, p, ['.']));
  751. Result := EncodeTimeInterval(EH, EM, ES, 0);
  752. end;
  753. function InternalStrToTimeStamp(S: string): TDateTime;
  754. var
  755. EY, EM, ED: Word;
  756. EH, EN, ES: Word;
  757. begin
  758. {$IFNDEF mysql40}
  759. EY := StrToInt(Copy(S, 1, 4));
  760. EM := StrToInt(Copy(S, 6, 2));
  761. ED := StrToInt(Copy(S, 9, 2));
  762. EH := StrToInt(Copy(S, 12, 2));
  763. EN := StrToInt(Copy(S, 15, 2));
  764. ES := StrToInt(Copy(S, 18, 2));
  765. {$ELSE}
  766. EY := StrToInt(Copy(S, 1, 4));
  767. EM := StrToInt(Copy(S, 5, 2));
  768. ED := StrToInt(Copy(S, 7, 2));
  769. EH := StrToInt(Copy(S, 9, 2));
  770. EN := StrToInt(Copy(S, 11, 2));
  771. ES := StrToInt(Copy(S, 13, 2));
  772. {$ENDIF}
  773. if (EY = 0) or (EM = 0) or (ED = 0) then
  774. Result := 0
  775. else
  776. Result := EncodeDate(EY, EM, ED);
  777. Result := Result + EncodeTime(EH, EN, ES, 0);
  778. end;
  779. function TConnectionName.MySQLWriteData(AField: PMYSQL_FIELD; FieldDef: TFieldDef; Source, Dest: PChar; Len: integer; out CreateBlob : boolean): Boolean;
  780. var
  781. VI: Integer;
  782. VL: LargeInt;
  783. VS: Smallint;
  784. VF: Double;
  785. VC: Currency;
  786. VD: TDateTime;
  787. VB: TBCD;
  788. Src : String;
  789. begin
  790. Result := False;
  791. CreateBlob := False;
  792. if Source = Nil then // If the pointer is NULL, the field is NULL
  793. exit;
  794. SetString(Src, Source, Len);
  795. case AField^.ftype of
  796. FIELD_TYPE_TINY, FIELD_TYPE_SHORT, FIELD_TYPE_YEAR:
  797. begin
  798. if (Src<>'') then
  799. VS := StrToInt(Src)
  800. else
  801. VS := 0;
  802. Move(VS, Dest^, SizeOf(smallint));
  803. end;
  804. FIELD_TYPE_LONG, FIELD_TYPE_INT24:
  805. begin
  806. if (Src<>'') then
  807. VI := StrToInt(Src)
  808. else
  809. VI := 0;
  810. Move(VI, Dest^, SizeOf(Integer));
  811. end;
  812. FIELD_TYPE_LONGLONG:
  813. begin
  814. if (Src<>'') then
  815. VL := StrToInt64(Src)
  816. else
  817. VL := 0;
  818. Move(VL, Dest^, SizeOf(LargeInt));
  819. end;
  820. {$ifdef mysql50_up}
  821. FIELD_TYPE_NEWDECIMAL,
  822. {$endif}
  823. FIELD_TYPE_DECIMAL, FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE:
  824. case FieldDef.DataType of
  825. ftBCD:
  826. begin
  827. VC := InternalStrToCurrency(Src);
  828. Move(VC, Dest^, SizeOf(Currency));
  829. end;
  830. ftFmtBCD:
  831. begin
  832. VB := StrToBCD(Src, FSQLFormatSettings);
  833. Move(VB, Dest^, SizeOf(TBCD));
  834. end
  835. else
  836. begin
  837. if Src <> '' then
  838. VF := InternalStrToFloat(Src)
  839. else
  840. VF := 0;
  841. Move(VF, Dest^, SizeOf(Double));
  842. end;
  843. end;
  844. FIELD_TYPE_TIMESTAMP:
  845. begin
  846. if Src <> '' then
  847. VD := InternalStrToTimeStamp(Src)
  848. else
  849. VD := 0;
  850. Move(VD, Dest^, SizeOf(TDateTime));
  851. end;
  852. FIELD_TYPE_DATETIME:
  853. begin
  854. if Src <> '' then
  855. VD := InternalStrToDateTime(Src)
  856. else
  857. VD := 0;
  858. Move(VD, Dest^, SizeOf(TDateTime));
  859. end;
  860. FIELD_TYPE_DATE:
  861. begin
  862. if Src <> '' then
  863. VD := InternalStrToDate(Src)
  864. else
  865. VD := 0;
  866. Move(VD, Dest^, SizeOf(TDateTime));
  867. end;
  868. FIELD_TYPE_TIME:
  869. begin
  870. if Src <> '' then
  871. VD := InternalStrToTime(Src)
  872. else
  873. VD := 0;
  874. Move(VD, Dest^, SizeOf(TDateTime));
  875. end;
  876. FIELD_TYPE_VAR_STRING, FIELD_TYPE_STRING, FIELD_TYPE_ENUM, FIELD_TYPE_SET:
  877. begin
  878. { Write('Moving string of size ',asize,' : ');
  879. P:=Source;
  880. If (P<>nil) then
  881. While P[0]<>#0 do
  882. begin
  883. Write(p[0]);
  884. inc(p);
  885. end;
  886. Writeln;
  887. }
  888. if Len > FieldDef.Size then
  889. Len := FieldDef.Size;
  890. case FieldDef.DataType of
  891. // String-fields which can contain more then dsMaxStringSize characters
  892. // are mapped to ftBlob fields, while their mysql-datatype is FIELD_TYPE_BLOB
  893. ftBlob, ftMemo:
  894. CreateBlob := True;
  895. ftVarBytes:
  896. begin
  897. PWord(Dest)^ := Len;
  898. Move(Source^, (Dest+sizeof(Word))^, Len);
  899. end;
  900. ftBytes:
  901. Move(Source^, Dest^, Len);
  902. else // ftString, ftFixedChar
  903. begin
  904. Move(Source^, Dest^, Len);
  905. (Dest+Len)^ := #0;
  906. end;
  907. end;
  908. end;
  909. FIELD_TYPE_BLOB:
  910. CreateBlob := True;
  911. {$IFDEF MYSQL50_UP}
  912. FIELD_TYPE_BIT:
  913. begin
  914. VL := 0;
  915. for VI := 0 to Len-1 do
  916. VL := VL * 256 + PByte(Source+VI)^;
  917. move(VL, Dest^, sizeof(LargeInt));
  918. end;
  919. {$ENDIF}
  920. end;
  921. Result := True;
  922. end;
  923. procedure TConnectionName.UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string);
  924. var qry : TSQLQuery;
  925. begin
  926. if not assigned(Transaction) then
  927. DatabaseError(SErrConnTransactionnSet);
  928. qry := tsqlquery.Create(nil);
  929. qry.transaction := Transaction;
  930. qry.database := Self;
  931. with qry do
  932. begin
  933. ParseSQL := False;
  934. sql.clear;
  935. sql.add('show index from ' + TableName);
  936. open;
  937. end;
  938. while not qry.eof do with IndexDefs.AddIndexDef do
  939. begin
  940. Name := trim(qry.fieldbyname('Key_name').asstring);
  941. Fields := trim(qry.fieldbyname('Column_name').asstring);
  942. If Name = 'PRIMARY' then options := options + [ixPrimary];
  943. If qry.fieldbyname('Non_unique').asinteger = 0 then options := options + [ixUnique];
  944. qry.next;
  945. while (name = trim(qry.fieldbyname('Key_name').asstring)) and (not qry.eof) do
  946. begin
  947. Fields := Fields + ';' + trim(qry.fieldbyname('Column_name').asstring);
  948. qry.next;
  949. end;
  950. end;
  951. qry.close;
  952. qry.free;
  953. end;
  954. function TConnectionName.RowsAffected(cursor: TSQLCursor): TRowsCount;
  955. begin
  956. if assigned(cursor) then
  957. // Compile this without range-checking. RowsAffected can be -1, although
  958. // it's an unsigned integer. (small joke from the mysql-guys)
  959. // Without range-checking this goes ok. If Range is turned on, this results
  960. // in range-check errors.
  961. Result := (cursor as TCursorName).RowsAffected
  962. else
  963. Result := -1;
  964. end;
  965. constructor TConnectionName.Create(AOwner: TComponent);
  966. const SingleBackQoutes: TQuoteChars = ('`','`');
  967. begin
  968. inherited Create(AOwner);
  969. FConnOptions := FConnOptions + [sqEscapeRepeat] + [sqEscapeSlash];
  970. FieldNameQuoteChars:=SingleBackQoutes;
  971. FMySQL := Nil;
  972. end;
  973. procedure TConnectionName.GetFieldNames(const TableName: string; List: TStrings);
  974. begin
  975. GetDBInfo(stColumns,TableName,'field',List);
  976. end;
  977. procedure TConnectionName.GetTableNames(List: TStrings; SystemTables: Boolean);
  978. begin
  979. GetDBInfo(stTables,'','tables_in_'+DatabaseName,List)
  980. end;
  981. function TConnectionName.GetTransactionHandle(trans: TSQLHandle): pointer;
  982. begin
  983. Result:=Nil;
  984. end;
  985. function TConnectionName.Commit(trans: TSQLHandle): boolean;
  986. begin
  987. // Do nothing.
  988. end;
  989. function TConnectionName.RollBack(trans: TSQLHandle): boolean;
  990. begin
  991. // Do nothing
  992. end;
  993. function TConnectionName.StartdbTransaction(trans: TSQLHandle; AParams : string): boolean;
  994. begin
  995. // Do nothing
  996. end;
  997. procedure TConnectionName.CommitRetaining(trans: TSQLHandle);
  998. begin
  999. // Do nothing
  1000. end;
  1001. procedure TConnectionName.RollBackRetaining(trans: TSQLHandle);
  1002. begin
  1003. // Do nothing
  1004. end;
  1005. function TConnectionName.GetSchemaInfoSQL(SchemaType: TSchemaType;
  1006. SchemaObjectName, SchemaPattern: string): string;
  1007. begin
  1008. case SchemaType of
  1009. stTables : result := 'show tables';
  1010. stColumns : result := 'show columns from ' + EscapeString(SchemaObjectName);
  1011. else
  1012. DatabaseError(SMetadataUnavailable)
  1013. end; {case}
  1014. end;
  1015. { TMySQLConnectionDef }
  1016. class function TMySQLConnectionDef.TypeName: String;
  1017. begin
  1018. Result:='MySQL '+MySQLVersion;
  1019. end;
  1020. class function TMySQLConnectionDef.ConnectionClass: TSQLConnectionClass;
  1021. begin
  1022. {$IfDef mysql55}
  1023. Result:=TMySQL55Connection;
  1024. {$ELSE}
  1025. {$IfDef mysql51}
  1026. Result:=TMySQL51Connection;
  1027. {$ELSE}
  1028. {$IfDef mysql50}
  1029. Result:=TMySQL50Connection;
  1030. {$ELSE}
  1031. {$IfDef mysql41}
  1032. Result:=TMySQL41Connection;
  1033. {$ELSE}
  1034. {$IFDEF mysql4} // temporary backwards compatibility for Lazarus
  1035. Result:=TMySQLConnection;
  1036. {$ELSE}
  1037. Result:=TMySQL40Connection;
  1038. {$EndIf}
  1039. {$EndIf}
  1040. {$EndIf}
  1041. {$endif}
  1042. {$endif}
  1043. end;
  1044. class function TMySQLConnectionDef.Description: String;
  1045. begin
  1046. Result:='Connect to a MySQL '+MySQLVersion+'database directly via the client library';
  1047. end;
  1048. {$IfDef mysql55}
  1049. initialization
  1050. RegisterConnection(TMySQL55ConnectionDef);
  1051. finalization
  1052. UnRegisterConnection(TMySQL55ConnectionDef);
  1053. {$else}
  1054. {$IfDef mysql51}
  1055. initialization
  1056. RegisterConnection(TMySQL51ConnectionDef);
  1057. finalization
  1058. UnRegisterConnection(TMySQL51ConnectionDef);
  1059. {$ELSE}
  1060. {$IfDef mysql50}
  1061. initialization
  1062. RegisterConnection(TMySQL50ConnectionDef);
  1063. finalization
  1064. UnRegisterConnection(TMySQL50ConnectionDef);
  1065. {$ELSE}
  1066. {$IfDef mysql41}
  1067. initialization
  1068. RegisterConnection(TMySQL41ConnectionDef);
  1069. finalization
  1070. UnRegisterConnection(TMySQL41ConnectionDef);
  1071. {$ELSE}
  1072. {$IFDEF mysql4} // temporary backwards compatibility for Lazarus
  1073. initialization
  1074. RegisterConnection(TMySQL40ConnectionDef);
  1075. finalization
  1076. UnRegisterConnection(TMySQL40ConnectionDef);
  1077. {$ELSE}
  1078. initialization
  1079. RegisterConnection(TMySQL40ConnectionDef);
  1080. finalization
  1081. UnRegisterConnection(TMySQL40ConnectionDef);
  1082. {$EndIf}
  1083. {$EndIf}
  1084. {$EndIf}
  1085. {$ENDIF}
  1086. {$endif}
  1087. end.