mysqlconn.inc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. {$mode objfpc}{$H+}
  2. {$MACRO on}
  3. interface
  4. uses
  5. Classes, SysUtils,bufdataset,sqldb,db,dynlibs,
  6. {$IfDef mysql50}
  7. mysql50dyn;
  8. {$DEFINE TConnectionName:=TMySQL50Connection}
  9. {$DEFINE TMySQLConnectionDef:=TMySQL50ConnectionDef}
  10. {$DEFINE TTransactionName:=TMySQL50Transaction}
  11. {$DEFINE TCursorName:=TMySQL50Cursor}
  12. {$ELSE}
  13. {$IfDef mysql41}
  14. mysql41dyn;
  15. {$DEFINE TConnectionName:=TMySQL41Connection}
  16. {$DEFINE TMySQLConnectionDef:=TMySQL41ConnectionDef}
  17. {$DEFINE TTransactionName:=TMySQL41Transaction}
  18. {$DEFINE TCursorName:=TMySQL41Cursor}
  19. {$ELSE}
  20. {$IFDEF mysql4} // temporary backwards compatibility for Lazarus
  21. mysql40dyn;
  22. {$DEFINE TConnectionName:=TMySQLConnection}
  23. {$DEFINE TMySQLConnectionDef:=TMySQL40ConnectionDef}
  24. {$DEFINE TTransactionName:=TMySQLTransaction}
  25. {$DEFINE TCursorName:=TMySQLCursor}
  26. {$ELSE}
  27. mysql40dyn;
  28. {$DEFINE TConnectionName:=TMySQL40Connection}
  29. {$DEFINE TMySQLConnectionDef:=TMySQL40ConnectionDef}
  30. {$DEFINE TTransactionName:=TMySQL40Transaction}
  31. {$DEFINE TCursorName:=TMySQL40Cursor}
  32. {$EndIf}
  33. {$EndIf}
  34. {$EndIf}
  35. Const
  36. {$IfDef mysql50}
  37. MySQLVersion = '5.0';
  38. {$ELSE}
  39. {$IfDef mysql41}
  40. MySQLVersion = '4.1';
  41. {$ELSE}
  42. {$IFDEF mysql4} // temporary backwards compatibility for Lazarus
  43. MySQLVersion = '4.0';
  44. {$ELSE}
  45. MySQLVersion = '4.0';
  46. {$EndIf}
  47. {$EndIf}
  48. {$EndIf}
  49. Type
  50. TTransactionName = Class(TSQLHandle)
  51. protected
  52. end;
  53. { TCursorName }
  54. TCursorName = Class(TSQLCursor)
  55. protected
  56. FRes: PMYSQL_RES; { Record pointer }
  57. FNeedData : Boolean;
  58. FStatement : String;
  59. Row : MYSQL_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. protected
  77. function StrToStatementType(s : string) : TStatementType; override;
  78. Procedure ConnectToServer; virtual;
  79. Procedure SelectDatabase; virtual;
  80. function MySQLDataType(AType: enum_field_types; ASize, ADecimals: Integer; var NewType: TFieldType; var NewSize: Integer): Boolean;
  81. function MySQLWriteData(AType: enum_field_types;ASize: Integer; AFieldType: TFieldType; Source, Dest: PChar; out CreateBlob : boolean): Boolean;
  82. // SQLConnection methods
  83. procedure DoInternalConnect; override;
  84. procedure DoInternalDisconnect; override;
  85. function GetHandle : pointer; override;
  86. function GetAsSQLText(Field : TField) : string; overload; override;
  87. function GetAsSQLText(Param : TParam) : string; overload; override;
  88. Function AllocateCursorHandle : TSQLCursor; override;
  89. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  90. Function AllocateTransactionHandle : TSQLHandle; override;
  91. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
  92. procedure UnPrepareStatement(cursor:TSQLCursor); override;
  93. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  94. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction;AParams : TParams); override;
  95. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); override;
  96. function Fetch(cursor : TSQLCursor) : boolean; override;
  97. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  98. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor;ATransaction : TSQLTransaction); override;
  99. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  100. function Commit(trans : TSQLHandle) : boolean; override;
  101. function RollBack(trans : TSQLHandle) : boolean; override;
  102. function StartdbTransaction(trans : TSQLHandle; AParams : string) : boolean; override;
  103. procedure CommitRetaining(trans : TSQLHandle); override;
  104. procedure RollBackRetaining(trans : TSQLHandle); override;
  105. procedure UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string); override;
  106. function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
  107. Public
  108. constructor Create(AOwner : TComponent); override;
  109. procedure CreateDB; override;
  110. procedure DropDB; override;
  111. Property ServerInfo : String Read FServerInfo;
  112. Property HostInfo : String Read FHostInfo;
  113. property ClientInfo: string read GetClientInfo;
  114. property ServerStatus : String read GetServerStatus;
  115. published
  116. property DatabaseName;
  117. property HostName;
  118. property KeepConnection;
  119. property LoginPrompt;
  120. property Params;
  121. property OnLogin;
  122. end;
  123. { TMySQLConnectionDef }
  124. TMySQLConnectionDef = Class(TConnectionDef)
  125. Class Function TypeName : String; override;
  126. Class Function ConnectionClass : TSQLConnectionClass; override;
  127. Class Function Description : String; override;
  128. end;
  129. EMySQLError = Class(Exception);
  130. implementation
  131. uses dbconst,ctypes;
  132. { TConnectionName }
  133. Resourcestring
  134. SErrServerConnectFailed = 'Server connect failed.';
  135. SErrDatabaseSelectFailed = 'failed to select database: %s';
  136. SErrDatabaseCreate = 'Failed to create database: %s';
  137. SErrDatabaseDrop = 'Failed to drop database: %s';
  138. SErrNoData = 'No data for record';
  139. SErrExecuting = 'Error executing query: %s';
  140. SErrFetchingdata = 'Error fetching row data: %s';
  141. SErrGettingResult = 'Error getting result set: %s';
  142. SErrNoQueryResult = 'No result from query.';
  143. SErrNotversion50 = 'TMySQL50Connection can not work with the installed MySQL client version (%s).';
  144. SErrNotversion41 = 'TMySQL41Connection can not work with the installed MySQL client version (%s).';
  145. SErrNotversion40 = 'TMySQL40Connection can not work with the installed MySQL client version (%s).';
  146. Procedure MySQlError(R : PMySQL;Msg: String;Comp : TComponent);
  147. Var
  148. MySQLMsg : String;
  149. begin
  150. If (R<>Nil) then
  151. begin
  152. MySQLMsg:=Strpas(mysql_error(R));
  153. DatabaseErrorFmt(Msg,[MySQLMsg],Comp);
  154. end
  155. else
  156. DatabaseError(Msg,Comp);
  157. end;
  158. function TConnectionName.StrToStatementType(s : string) : TStatementType;
  159. begin
  160. S:=Lowercase(s);
  161. if s = 'show' then exit(stSelect);
  162. result := inherited StrToStatementType(s);
  163. end;
  164. function TConnectionName.GetClientInfo: string;
  165. begin
  166. // To make it possible to call this if there's no connection yet
  167. InitialiseMysql;
  168. Try
  169. Result:=strpas(mysql_get_client_info());
  170. Finally
  171. ReleaseMysql;
  172. end;
  173. end;
  174. function TConnectionName.GetServerStatus: String;
  175. begin
  176. CheckConnected;
  177. Result := mysql_stat(FMYSQL);
  178. end;
  179. procedure TConnectionName.ConnectMySQL(var HMySQL : PMySQL;H,U,P : pchar);
  180. Var
  181. Port : Cardinal;
  182. begin
  183. HMySQL := mysql_init(HMySQL);
  184. Port:=Abs(StrToIntDef(Params.Values['Port'],0));
  185. HMySQL:=mysql_real_connect(HMySQL,PChar(H),PChar(U),Pchar(P),Nil,Port,Nil,0);
  186. If (HMySQL=Nil) then
  187. MySQlError(Nil,SErrServerConnectFailed,Self);
  188. end;
  189. function TConnectionName.GetAsSQLText(Field : TField) : string;
  190. var esc_str : pchar;
  191. begin
  192. if (not assigned(field)) or field.IsNull then Result := 'Null'
  193. else if field.DataType = ftString then
  194. begin
  195. Getmem(esc_str,sizeof(field.asstring)*2+1);
  196. mysql_real_escape_string(FMySQL,esc_str,pchar(field.asstring),length(field.asstring));
  197. Result := '''' + esc_str + '''';
  198. Freemem(esc_str);
  199. end
  200. else Result := inherited GetAsSqlText(field);
  201. end;
  202. function TConnectionName.GetAsSQLText(Param: TParam) : string;
  203. var esc_str : pchar;
  204. begin
  205. if (not assigned(param)) or param.IsNull then Result := 'Null'
  206. else if param.DataType in [ftString,ftBlob] then
  207. begin
  208. Getmem(esc_str,length(param.asstring)*2+1);
  209. mysql_real_escape_string(FMySQL,esc_str,pchar(param.asstring),length(param.asstring));
  210. Result := '''' + esc_str + '''';
  211. Freemem(esc_str);
  212. end
  213. else Result := inherited GetAsSqlText(Param);
  214. end;
  215. procedure TConnectionName.ConnectToServer;
  216. Var
  217. H,U,P : String;
  218. begin
  219. H:=HostName;
  220. U:=UserName;
  221. P:=Password;
  222. ConnectMySQL(FMySQL,pchar(H),pchar(U),pchar(P));
  223. FServerInfo := strpas(mysql_get_server_info(FMYSQL));
  224. FHostInfo := strpas(mysql_get_host_info(FMYSQL));
  225. end;
  226. procedure TConnectionName.SelectDatabase;
  227. begin
  228. if mysql_select_db(FMySQL,pchar(DatabaseName))<>0 then
  229. MySQLError(FMySQL,SErrDatabaseSelectFailed,Self);
  230. end;
  231. procedure TConnectionName.CreateDB;
  232. begin
  233. ExecuteDirectMySQL('CREATE DATABASE ' +DatabaseName);
  234. end;
  235. procedure TConnectionName.DropDB;
  236. begin
  237. ExecuteDirectMySQL('DROP DATABASE ' +DatabaseName);
  238. end;
  239. procedure TConnectionName.ExecuteDirectMySQL(const query : string);
  240. var H,U,P : String;
  241. AMySQL : PMySQL;
  242. begin
  243. CheckDisConnected;
  244. InitialiseMysql;
  245. H:=HostName;
  246. U:=UserName;
  247. P:=Password;
  248. AMySQL := nil;
  249. ConnectMySQL(AMySQL,pchar(H),pchar(U),pchar(P));
  250. if mysql_query(AMySQL,pchar(query))<>0 then
  251. MySQLError(AMySQL,Format(SErrExecuting,[StrPas(mysql_error(AMySQL))]),Self);
  252. mysql_close(AMySQL);
  253. ReleaseMysql;
  254. end;
  255. procedure TConnectionName.DoInternalConnect;
  256. begin
  257. InitialiseMysql;
  258. {$IFDEF mysql50}
  259. if copy(strpas(mysql_get_client_info()),1,3)<>'5.0' then
  260. Raise EInOutError.CreateFmt(SErrNotversion50,[strpas(mysql_get_client_info())]);
  261. {$ELSE}
  262. {$IFDEF mysql41}
  263. if copy(strpas(mysql_get_client_info()),1,3)<>'4.1' then
  264. Raise EInOutError.CreateFmt(SErrNotversion41,[strpas(mysql_get_client_info())]);
  265. {$ELSE}
  266. if copy(strpas(mysql_get_client_info()),1,3)<>'4.0' then
  267. Raise EInOutError.CreateFmt(SErrNotversion40,[strpas(mysql_get_client_info())]);
  268. {$ENDIF}
  269. {$ENDIF}
  270. inherited DoInternalConnect;
  271. ConnectToServer;
  272. SelectDatabase;
  273. end;
  274. procedure TConnectionName.DoInternalDisconnect;
  275. begin
  276. inherited DoInternalDisconnect;
  277. mysql_close(FMySQL);
  278. FMySQL:=Nil;
  279. ReleaseMysql;
  280. end;
  281. function TConnectionName.GetHandle: pointer;
  282. begin
  283. Result:=FMySQL;
  284. end;
  285. function TConnectionName.AllocateCursorHandle: TSQLCursor;
  286. begin
  287. Result:=TCursorName.Create;
  288. end;
  289. Procedure TConnectionName.DeAllocateCursorHandle(var cursor : TSQLCursor);
  290. begin
  291. FreeAndNil(cursor);
  292. end;
  293. function TConnectionName.AllocateTransactionHandle: TSQLHandle;
  294. begin
  295. // Result:=TTransactionName.Create;
  296. Result := nil;
  297. end;
  298. procedure TConnectionName.PrepareStatement(cursor: TSQLCursor;
  299. ATransaction: TSQLTransaction; buf: string;AParams : TParams);
  300. begin
  301. // if assigned(AParams) and (AParams.count > 0) then
  302. // DatabaseError('Parameters (not) yet supported for the MySQL SqlDB connection.',self);
  303. With Cursor as TCursorName do
  304. begin
  305. FStatement:=Buf;
  306. if assigned(AParams) and (AParams.count > 0) then
  307. FStatement := AParams.ParseSQL(FStatement,false,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psSimulated,paramBinding,ParamReplaceString);
  308. if FStatementType=stSelect then
  309. FNeedData:=True;
  310. end
  311. end;
  312. procedure TConnectionName.UnPrepareStatement(cursor: TSQLCursor);
  313. begin
  314. // do nothing
  315. end;
  316. procedure TConnectionName.FreeFldBuffers(cursor: TSQLCursor);
  317. Var
  318. C : TCursorName;
  319. begin
  320. C:=Cursor as TCursorName;
  321. if c.FStatementType=stSelect then
  322. c.FNeedData:=False;
  323. If (C.FRes<>Nil) then
  324. begin
  325. Mysql_free_result(C.FRes);
  326. C.FRes:=Nil;
  327. end;
  328. SetLength(c.MapDSRowToMSQLRow,0);
  329. inherited;
  330. end;
  331. procedure TConnectionName.Execute(cursor: TSQLCursor;
  332. atransaction: tSQLtransaction;AParams : TParams);
  333. Var
  334. C : TCursorName;
  335. i : integer;
  336. ParamNames,ParamValues : array of string;
  337. begin
  338. C:=Cursor as TCursorName;
  339. If (C.FRes=Nil) then
  340. begin
  341. if Assigned(AParams) and (AParams.count > 0) then
  342. begin
  343. setlength(ParamNames,AParams.Count);
  344. setlength(ParamValues,AParams.Count);
  345. for i := 0 to AParams.count -1 do
  346. begin
  347. ParamNames[AParams.count-i-1] := C.ParamReplaceString+inttostr(AParams[i].Index+1);
  348. ParamValues[AParams.count-i-1] := GetAsSQLText(AParams[i]);
  349. end;
  350. // paramreplacestring kan een probleem geven bij postgres als hij niet meer gewoon $ is?
  351. C.FStatement := stringsreplace(C.FStatement,ParamNames,ParamValues,[rfReplaceAll]);
  352. end;
  353. if mysql_query(FMySQL,Pchar(C.FStatement))<>0 then
  354. MySQLError(FMYSQL,Format(SErrExecuting,[StrPas(mysql_error(FMySQL))]),Self)
  355. else
  356. begin
  357. C.RowsAffected := mysql_affected_rows(FMYSQL);
  358. C.LastInsertID := mysql_insert_id(FMYSQL);
  359. if C.FNeedData then
  360. C.FRes:=mysql_store_result(FMySQL);
  361. end;
  362. end;
  363. end;
  364. function TConnectionName.MySQLDataType(AType: enum_field_types; ASize, ADecimals: Integer;
  365. var NewType: TFieldType; var NewSize: Integer): Boolean;
  366. begin
  367. Result := True;
  368. case AType of
  369. FIELD_TYPE_LONGLONG:
  370. begin
  371. NewType := ftLargeint;
  372. NewSize := 0;
  373. end;
  374. FIELD_TYPE_TINY, FIELD_TYPE_SHORT, FIELD_TYPE_LONG,
  375. FIELD_TYPE_INT24:
  376. begin
  377. NewType := ftInteger;
  378. NewSize := 0;
  379. end;
  380. {$ifdef mysql50}
  381. FIELD_TYPE_NEWDECIMAL,
  382. {$endif}
  383. FIELD_TYPE_DECIMAL: if ADecimals < 5 then
  384. begin
  385. NewType := ftBCD;
  386. NewSize := ADecimals;
  387. end
  388. else
  389. begin
  390. NewType := ftFloat;
  391. NewSize := 0;
  392. end;
  393. FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE:
  394. begin
  395. NewType := ftFloat;
  396. NewSize := 0;
  397. end;
  398. FIELD_TYPE_TIMESTAMP, FIELD_TYPE_DATETIME:
  399. begin
  400. NewType := ftDateTime;
  401. NewSize := 0;
  402. end;
  403. FIELD_TYPE_DATE:
  404. begin
  405. NewType := ftDate;
  406. NewSize := 0;
  407. end;
  408. FIELD_TYPE_TIME:
  409. begin
  410. NewType := ftTime;
  411. NewSize := 0;
  412. end;
  413. FIELD_TYPE_VAR_STRING, FIELD_TYPE_STRING, FIELD_TYPE_ENUM, FIELD_TYPE_SET:
  414. begin
  415. NewType := ftString;
  416. NewSize := ASize;
  417. end;
  418. FIELD_TYPE_BLOB:
  419. begin
  420. NewType := ftBlob;
  421. NewSize := 0;
  422. end
  423. else
  424. Result := False;
  425. end;
  426. end;
  427. procedure TConnectionName.AddFieldDefs(cursor: TSQLCursor;
  428. FieldDefs: TfieldDefs);
  429. var
  430. C : TCursorName;
  431. I, TF, FC: Integer;
  432. field: PMYSQL_FIELD;
  433. DFT: TFieldType;
  434. DFS: Integer;
  435. begin
  436. // Writeln('MySQL: Adding fielddefs');
  437. C:=(Cursor as TCursorName);
  438. If (C.FRes=Nil) then
  439. begin
  440. // Writeln('res is nil');
  441. MySQLError(FMySQL,SErrNoQueryResult,Self);
  442. end;
  443. // Writeln('MySQL: have result');
  444. FC:=mysql_num_fields(C.FRes);
  445. SetLength(c.MapDSRowToMSQLRow,FC);
  446. TF := 1;
  447. For I:= 0 to FC-1 do
  448. begin
  449. field := mysql_fetch_field_direct(C.FRES, I);
  450. // Writeln('MySQL: creating fielddef ',I+1);
  451. if MySQLDataType(field^.ftype, field^.length, field^.decimals, DFT, DFS) then
  452. begin
  453. TFieldDef.Create(FieldDefs, field^.name, DFT, DFS, False, TF);
  454. c.MapDSRowToMSQLRow[TF-1] := I;
  455. inc(TF);
  456. end
  457. end;
  458. // Writeln('MySQL: Finished adding fielddefs');
  459. end;
  460. function TConnectionName.Fetch(cursor: TSQLCursor): boolean;
  461. Var
  462. C : TCursorName;
  463. begin
  464. C:=Cursor as TCursorName;
  465. C.Row:=MySQL_Fetch_row(C.FRes);
  466. Result:=(C.Row<>Nil);
  467. end;
  468. function TConnectionName.LoadField(cursor : TSQLCursor;
  469. FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean;
  470. var
  471. field: PMYSQL_FIELD;
  472. row : MYSQL_ROW;
  473. C : TCursorName;
  474. begin
  475. // Writeln('LoadFieldsFromBuffer');
  476. C:=Cursor as TCursorName;
  477. if C.Row=nil then
  478. begin
  479. // Writeln('LoadFieldsFromBuffer: row=nil');
  480. MySQLError(FMySQL,SErrFetchingData,Self);
  481. end;
  482. Row:=C.Row;
  483. inc(Row,c.MapDSRowToMSQLRow[FieldDef.FieldNo-1]);
  484. field := mysql_fetch_field_direct(C.FRES, c.MapDSRowToMSQLRow[FieldDef.FieldNo-1]);
  485. Result := MySQLWriteData(field^.ftype, field^.length, FieldDef.DataType, Row^, Buffer, CreateBlob);
  486. end;
  487. procedure TConnectionName.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  488. ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  489. var
  490. row : MYSQL_ROW;
  491. C : TCursorName;
  492. li : longint;
  493. Lengths : pculong;
  494. begin
  495. C:=Cursor as TCursorName;
  496. if C.Row=nil then
  497. MySQLError(FMySQL,SErrFetchingData,Self);
  498. Row:=C.Row;
  499. inc(Row,c.MapDSRowToMSQLRow[FieldDef.FieldNo-1]);
  500. Lengths := mysql_fetch_lengths(c.FRes);
  501. li := Lengths[c.MapDSRowToMSQLRow[FieldDef.FieldNo-1]];
  502. ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer,li);
  503. Move(pchar(row^)^, ABlobBuf^.BlobBuffer^.Buffer^, li);
  504. ABlobBuf^.BlobBuffer^.Size := li;
  505. end;
  506. function InternalStrToFloat(S: string): Extended;
  507. var
  508. I: Integer;
  509. Tmp: string;
  510. begin
  511. Tmp := '';
  512. for I := 1 to Length(S) do
  513. begin
  514. if not (S[I] in ['0'..'9', '+', '-', 'E', 'e']) then
  515. Tmp := Tmp + DecimalSeparator
  516. else
  517. Tmp := Tmp + S[I];
  518. end;
  519. Result := StrToFloat(Tmp);
  520. end;
  521. function InternalStrToCurrency(S: string): Extended;
  522. var
  523. I: Integer;
  524. Tmp: string;
  525. begin
  526. Tmp := '';
  527. for I := 1 to Length(S) do
  528. begin
  529. if not (S[I] in ['0'..'9', '+', '-', 'E', 'e']) then
  530. Tmp := Tmp + DecimalSeparator
  531. else
  532. Tmp := Tmp + S[I];
  533. end;
  534. Result := StrToCurr(Tmp);
  535. end;
  536. function InternalStrToDate(S: string): TDateTime;
  537. var
  538. EY, EM, ED: Word;
  539. begin
  540. EY := StrToInt(Copy(S,1,4));
  541. EM := StrToInt(Copy(S,6,2));
  542. ED := StrToInt(Copy(S,9,2));
  543. if (EY = 0) or (EM = 0) or (ED = 0) then
  544. Result:=0
  545. else
  546. Result:=EncodeDate(EY, EM, ED);
  547. end;
  548. function InternalStrToDateTime(S: string): TDateTime;
  549. var
  550. EY, EM, ED: Word;
  551. EH, EN, ES: Word;
  552. begin
  553. EY := StrToInt(Copy(S, 1, 4));
  554. EM := StrToInt(Copy(S, 6, 2));
  555. ED := StrToInt(Copy(S, 9, 2));
  556. EH := StrToInt(Copy(S, 12, 2));
  557. EN := StrToInt(Copy(S, 15, 2));
  558. ES := StrToInt(Copy(S, 18, 2));
  559. if (EY = 0) or (EM = 0) or (ED = 0) then
  560. Result := 0
  561. else
  562. Result := EncodeDate(EY, EM, ED);
  563. Result := Result + EncodeTime(EH, EN, ES, 0);
  564. end;
  565. function InternalStrToTime(S: string): TDateTime;
  566. var
  567. EH, EM, ES: Word;
  568. begin
  569. EH := StrToInt(Copy(S, 1, 2));
  570. EM := StrToInt(Copy(S, 4, 2));
  571. ES := StrToInt(Copy(S, 7, 2));
  572. Result := EncodeTime(EH, EM, ES, 0);
  573. end;
  574. function InternalStrToTimeStamp(S: string): TDateTime;
  575. var
  576. EY, EM, ED: Word;
  577. EH, EN, ES: Word;
  578. begin
  579. {$IFNDEF mysql40}
  580. EY := StrToInt(Copy(S, 1, 4));
  581. EM := StrToInt(Copy(S, 6, 2));
  582. ED := StrToInt(Copy(S, 9, 2));
  583. EH := StrToInt(Copy(S, 12, 2));
  584. EN := StrToInt(Copy(S, 15, 2));
  585. ES := StrToInt(Copy(S, 18, 2));
  586. {$ELSE}
  587. EY := StrToInt(Copy(S, 1, 4));
  588. EM := StrToInt(Copy(S, 5, 2));
  589. ED := StrToInt(Copy(S, 7, 2));
  590. EH := StrToInt(Copy(S, 9, 2));
  591. EN := StrToInt(Copy(S, 11, 2));
  592. ES := StrToInt(Copy(S, 13, 2));
  593. {$ENDIF}
  594. if (EY = 0) or (EM = 0) or (ED = 0) then
  595. Result := 0
  596. else
  597. Result := EncodeDate(EY, EM, ED);
  598. Result := Result + EncodeTime(EH, EN, ES, 0);;
  599. end;
  600. function TConnectionName.MySQLWriteData(AType: enum_field_types;ASize: Integer; AFieldType: TFieldType; Source, Dest: PChar; out CreateBlob : boolean): Boolean;
  601. var
  602. VI: Integer;
  603. VF: Double;
  604. VC: Currency;
  605. VD: TDateTime;
  606. Src : String;
  607. begin
  608. Result := False;
  609. CreateBlob := False;
  610. if Source = Nil then
  611. exit;
  612. Src:=StrPas(Source);
  613. case AType of
  614. FIELD_TYPE_TINY, FIELD_TYPE_SHORT, FIELD_TYPE_LONG,
  615. FIELD_TYPE_INT24:
  616. begin
  617. if (Src<>'') then
  618. VI := StrToInt(Src)
  619. else
  620. VI := 0;
  621. Move(VI, Dest^, SizeOf(Integer));
  622. end;
  623. FIELD_TYPE_LONGLONG:
  624. begin
  625. if (Src<>'') then
  626. VI := StrToInt64(Src)
  627. else
  628. VI := 0;
  629. Move(VI, Dest^, SizeOf(LargeInt));
  630. end;
  631. {$ifdef mysql50}
  632. FIELD_TYPE_NEWDECIMAL,
  633. {$endif}
  634. FIELD_TYPE_DECIMAL, FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE:
  635. if AFieldType = ftBCD then
  636. begin
  637. VC := InternalStrToCurrency(Src);
  638. Move(VC, Dest^, SizeOf(Currency));
  639. end
  640. else
  641. begin
  642. if Src <> '' then
  643. VF := InternalStrToFloat(Src)
  644. else
  645. VF := 0;
  646. Move(VF, Dest^, SizeOf(Double));
  647. end;
  648. FIELD_TYPE_TIMESTAMP:
  649. begin
  650. if Src <> '' then
  651. VD := InternalStrToTimeStamp(Src)
  652. else
  653. VD := 0;
  654. Move(VD, Dest^, SizeOf(TDateTime));
  655. end;
  656. FIELD_TYPE_DATETIME:
  657. begin
  658. if Src <> '' then
  659. VD := InternalStrToDateTime(Src)
  660. else
  661. VD := 0;
  662. Move(VD, Dest^, SizeOf(TDateTime));
  663. end;
  664. FIELD_TYPE_DATE:
  665. begin
  666. if Src <> '' then
  667. VD := InternalStrToDate(Src)
  668. else
  669. VD := 0;
  670. Move(VD, Dest^, SizeOf(TDateTime));
  671. end;
  672. FIELD_TYPE_TIME:
  673. begin
  674. if Src <> '' then
  675. VD := InternalStrToTime(Src)
  676. else
  677. VD := 0;
  678. Move(VD, Dest^, SizeOf(TDateTime));
  679. end;
  680. FIELD_TYPE_VAR_STRING, FIELD_TYPE_STRING, FIELD_TYPE_ENUM, FIELD_TYPE_SET:
  681. begin
  682. { Write('Moving string of size ',asize,' : ');
  683. P:=Source;
  684. If (P<>nil) then
  685. While P[0]<>#0 do
  686. begin
  687. Write(p[0]);
  688. inc(p);
  689. end;
  690. Writeln;
  691. } if Src<> '' then
  692. Move(Source^, Dest^, ASize)
  693. else
  694. Dest^ := #0;
  695. end;
  696. FIELD_TYPE_BLOB:
  697. CreateBlob := True;
  698. end;
  699. Result := True;
  700. end;
  701. procedure TConnectionName.UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string);
  702. var qry : TSQLQuery;
  703. begin
  704. if not assigned(Transaction) then
  705. DatabaseError(SErrConnTransactionnSet);
  706. qry := tsqlquery.Create(nil);
  707. qry.transaction := Transaction;
  708. qry.database := Self;
  709. with qry do
  710. begin
  711. ReadOnly := True;
  712. sql.clear;
  713. sql.add('show index from ' + TableName);
  714. open;
  715. end;
  716. IndexDefs.Clear;
  717. while not qry.eof do with IndexDefs.AddIndexDef do
  718. begin
  719. Name := trim(qry.fieldbyname('Key_name').asstring);
  720. Fields := trim(qry.fieldbyname('Column_name').asstring);
  721. If Name = 'PRIMARY' then options := options + [ixPrimary];
  722. If qry.fieldbyname('Non_unique').asinteger = 0 then options := options + [ixUnique];
  723. qry.next;
  724. while (name = trim(qry.fieldbyname('Key_name').asstring)) and (not qry.eof) do
  725. begin
  726. Fields := Fields + ';' + trim(qry.fieldbyname('Column_name').asstring);
  727. qry.next;
  728. end;
  729. end;
  730. qry.close;
  731. qry.free;
  732. end;
  733. function TConnectionName.RowsAffected(cursor: TSQLCursor): TRowsCount;
  734. begin
  735. if assigned(cursor) then
  736. Result := (cursor as TCursorName).RowsAffected
  737. else
  738. Result := -1;
  739. end;
  740. constructor TConnectionName.Create(AOwner: TComponent);
  741. begin
  742. inherited Create(AOwner);
  743. FConnOptions := FConnOptions + [sqEscapeRepeat] + [sqEscapeSlash];
  744. FMySQL := Nil;
  745. end;
  746. function TConnectionName.GetTransactionHandle(trans: TSQLHandle): pointer;
  747. begin
  748. Result:=Nil;
  749. end;
  750. function TConnectionName.Commit(trans: TSQLHandle): boolean;
  751. begin
  752. // Do nothing.
  753. end;
  754. function TConnectionName.RollBack(trans: TSQLHandle): boolean;
  755. begin
  756. // Do nothing
  757. end;
  758. function TConnectionName.StartdbTransaction(trans: TSQLHandle; AParams : string): boolean;
  759. begin
  760. // Do nothing
  761. end;
  762. procedure TConnectionName.CommitRetaining(trans: TSQLHandle);
  763. begin
  764. // Do nothing
  765. end;
  766. procedure TConnectionName.RollBackRetaining(trans: TSQLHandle);
  767. begin
  768. // Do nothing
  769. end;
  770. { TMySQLConnectionDef }
  771. class function TMySQLConnectionDef.TypeName: String;
  772. begin
  773. Result:='MySQL '+MySQLVersion;
  774. end;
  775. class function TMySQLConnectionDef.ConnectionClass: TSQLConnectionClass;
  776. begin
  777. Result:=TConnectionName;
  778. end;
  779. class function TMySQLConnectionDef.Description: String;
  780. begin
  781. Result:='Connect to a MySQL '+MySQLVersion+'database directly via the client library';
  782. end;
  783. initialization
  784. RegisterConnection(TMySQLConnectionDef);
  785. finalization
  786. UnRegisterConnection(TMySQLConnectionDef);
  787. end.