mysqlconn.inc 38 KB

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