mysqlconn.inc 24 KB

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