source: branches/lazarus/USqlDatabase.pas

Last change on this file was 61, checked in by george, 15 years ago
  • Přidáno: Další chybějící soubory s vývojové větve ve Free Pascalu.
  • Property svn:executable set to *
File size: 11.5 KB
Line 
1unit USqlDatabase;
2
3{$mode delphi}{$H+}
4
5interface
6
7uses
8 SysUtils, Classes, mysql50, TypInfo;
9
10type
11 TClientCapabilities = (_CLIENT_LONG_PASSWORD, _CLIENT_FOUND_ROWS,
12 _CLIENT_LONG_FLAG, _CLIENT_CONNECT_WITH_DB, _CLIENT_NO_SCHEMA,
13 _CLIENT_COMPRESS, _CLIENT_ODBC, _CLIENT_LOCAL_FILES, _CLIENT_IGNORE_SPACE,
14 _CLIENT_INTERACTIVE, _CLIENT_SSL, _CLIENT_IGNORE_SIGPIPE, _CLIENT_TRANSACTIONS);
15
16 TSetClientCapabilities = set of TClientCapabilities;
17
18 TAssocArray = class(TStringList)
19 private
20 function GetValues(Index: string): string;
21 function GetValuesAtIndex(Index: Integer): string;
22 procedure SetValues(Index: string; const Value: string);
23 public
24 constructor Create;
25 destructor Destroy; override;
26 function GetAllValues: string;
27 procedure AddKeyValue(Key, Value: string);
28 property ValuesAtIndex[Index: Integer]: string read GetValuesAtIndex;
29 property Values[Index: string]: string read GetValues write SetValues; default;
30 end;
31
32 TDbRows = class(TList)
33 private
34 function GetData(Index: Integer): TAssocArray;
35 procedure SetData(Index: Integer; const Value: TAssocArray);
36 public
37 property Data[Index: Integer]: TAssocArray read GetData write SetData; default;
38 destructor Destroy; override;
39 end;
40
41 TSqlDatabase = class
42 procedure mySQLClient1ConnectError(Sender: TObject; Msg: String);
43 private
44 FSession: PMYSQL;
45 FConnected: Boolean;
46 FOnError: TNotifyEvent;
47 FDatabase: string;
48 function GetConnected: Boolean;
49 function GetLastErrorMessage: string;
50 function GetLastErrorNumber: Integer;
51 function CheckError: Boolean;
52 function GetCharset: string;
53 procedure SetDatabase(const Value: string);
54 { Private declarations }
55 public
56 Hostname: string;
57 UserName: string;
58 Password: string;
59 Table: string;
60 RepeatLastAction: Boolean;
61 LastQuery: string;
62 procedure CreateDatabase;
63 procedure CreateTable(Name: string);
64 procedure CreateColumn(ATable, ColumnName: string; ColumnType: TTypeKind);
65 function Query(Data: string): TDbRows;
66 function Select(ATable: string; Filter: string = '*'; Condition: string = '1'): TDbRows;
67 procedure Delete(ATable: string; Condition: string = '1');
68 procedure Insert(ATable: string; Data: TAssocArray);
69 procedure Update(ATable: string; Data: TAssocArray; Condition: string = '1');
70 procedure Replace(ATable: string; Data: TAssocArray);
71 procedure Connect;
72 procedure Disconnect;
73 function LastInsertId: Integer;
74 property LastErrorMessage: string read GetLastErrorMessage;
75 property LastErrorNumber: Integer read GetLastErrorNumber;
76 property Connected: Boolean read GetConnected;
77 property OnError: TNotifyEvent read FOnError write FOnError;
78 constructor Create;
79 destructor Destroy; override;
80 property Charset: string read GetCharset;
81 property Database: string read FDatabase write SetDatabase;
82 end;
83
84 function MySQLFloatToStr(F: Real): string;
85 function MySQLStrToFloat(S: string): Real;
86 function MySQLDateToDateTime(Date: string): TDateTime;
87
88implementation
89
90uses DateUtils, Math;
91
92const
93 CLIENT_LONG_PASSWORD = 1; // new more secure passwords
94 CLIENT_FOUND_ROWS = 2; // Found instead of affected rows
95 CLIENT_LONG_FLAG = 4; // Get all column flags
96 CLIENT_CONNECT_WITH_DB = 8; // One can specify db on connect
97 CLIENT_NO_SCHEMA = 16; // Don't allow database.table.column
98 CLIENT_COMPRESS = 32; // Can use compression protcol
99 CLIENT_ODBC = 64; // Odbc client
100 CLIENT_LOCAL_FILES = 128; // Can use LOAD DATA LOCAL
101 CLIENT_IGNORE_SPACE = 256; // Ignore spaces before '('
102 CLIENT_INTERACTIVE = 1024; // This is an interactive client
103 CLIENT_SSL = 2048; // Switch to SSL after handshake
104 CLIENT_IGNORE_SIGPIPE = 4096; // IGNORE sigpipes
105 CLIENT_TRANSACTIONS = 8192; // Client knows about transactions
106
107{ TDataModule2 }
108
109function MySQLDateToDateTime(Date: string): TDateTime;
110begin
111 R
112 Result := 0;
113end;
114
115function MySQLFloatToStr(F: Real): string;
116var
117 S: string;
118begin
119 S := FloatToStr(F);
120 if Pos(',',S) > 0 then S[Pos(',',S)] := '.';
121 Result := S;
122end;
123
124function MySQLStrToFloat(S: string): Real;
125begin
126 if Pos('.', S) > 0 then S[Pos('.', S)] := ',';
127 Result := StrToFloat(S);
128end;
129
130procedure TSqlDatabase.Connect;
131var
132 NewSession: PMYSQL;
133 Rows: TDbRows;
134begin
135 RepeatLastAction := False;
136// mySQLClient1.Connect;
137 FSession := mysql_init(FSession);
138// FSession.charset := 'latin2';
139 NewSession := mysql_real_connect(FSession, PChar(HostName), PChar(UserName),
140 PChar(Password), PChar(Database), 3306, nil, CLIENT_LONG_PASSWORD + CLIENT_CONNECT_WITH_DB);
141 if Assigned(NewSession) then begin
142 FConnected := True;
143 FSession := NewSession;
144 end else FConnected := False;
145 CheckError;
146 Rows := Query('SET NAMES cp1250');
147 Rows.Free;
148end;
149
150procedure TSqlDatabase.Insert(ATable: string; Data: TAssocArray);
151var
152 DbNames: string;
153 DbValues: string;
154 I: Integer;
155 Value: string;
156 DbRows: TDbRows;
157begin
158 Table := ATable;
159 DbNames := '';
160 DbValues := '';
161 for I := 0 to Data.Count-1 do begin
162 Value := Data.ValuesAtIndex[I];
163 StringReplace(Value, '"', '\"', [rfReplaceAll]);
164 if Value = 'NOW()' then DbValues := DbValues + ',' + Value
165 else DbValues := DbValues + ',"' + Value + '"';
166 DbNames := DbNames + ',`' + Data.Names[I] + '`';
167 end;
168 System.Delete(DbNames, 1, 1);
169 System.Delete(DbValues, 1, 1);
170 DbRows := Query('INSERT INTO `' + Table + '` (' + DbNames + ') VALUES (' + DbValues + ')');
171 DbRows.Free;
172end;
173
174function TSqlDatabase.Query(Data: string): TDbRows;
175var
176 I, II: Integer;
177 DbResult: PMYSQL_RES;
178 DbRow: MYSQL_ROW;
179type
180 PMYSQL_ROW2 = ^TMYSQL_ROW2; // return data as array of strings
181 TMYSQL_ROW2 = array[0..MaxInt div SizeOf(pChar) - 1] of pChar;
182begin
183 //DebugLog('SqlDatabase query: '+Data);
184 RepeatLastAction := False;
185 LastQuery := Data;
186 //if not Connected then NastaveniPripojeni.ShowModal;
187 Result := TDbRows.Create;
188 //repeat
189 mysql_query(FSession, PChar(Data));
190 //until not
191 CheckError;
192 //if not CheckError then
193 begin
194 DbResult := mysql_store_result(FSession);
195 if Assigned(DbResult) then begin
196 Result.Count := mysql_num_rows(DbResult);
197 for I := 0 to Result.Count-1 do begin
198 DbRow := mysql_fetch_row(DbResult);
199 Result[I] := TAssocArray.Create;
200 with Result[I] do begin
201 for II := 0 to mysql_num_fields(DbResult)-1 do begin
202 Add(mysql_fetch_field_direct(DbResult, II)^.name + NameValueSeparator + PMYSQL_ROW2(DbRow)^[II]);
203 end;
204 end;
205 end;
206 end;
207 end;
208 mysql_free_result(DbResult);
209 (*
210 if Assigned(DatabaseIntegrity) then
211 with DatabaseIntegrity do if not Checking then begin
212 Check;
213 DebugLog('Database integrity: Unreferenced='+IntToStr(Unreferenced)+' BadReferences='+IntToStr(BadReferences));
214 end;
215 *)
216end;
217
218procedure TSqlDatabase.Replace(ATable: string; Data: TAssocArray);
219var
220 DbNames: string;
221 DbValues: string;
222 Value: string;
223 I: Integer;
224 DbRows: TDbRows;
225begin
226 Table := ATable;
227 DbNames := '';
228 DbValues := '';
229 for I := 0 to Data.Count-1 do begin
230 Value := Data.ValuesAtIndex[I];
231 StringReplace(Value, '"', '\"', [rfReplaceAll]);
232 if Value = 'NOW()' then DbValues := DbValues + ',' + Value
233 else DbValues := DbValues + ',"' + Value + '"';
234 DbNames := DbNames + ',`' + Data.Names[I] + '`';
235 end;
236 System.Delete(DbNames, 1, 1);
237 System.Delete(DbValues, 1, 1);
238 DbRows := Query('REPLACE INTO `' + Table + '` (' + DbNames + ') VALUES (' + DbValues + ')');
239 DbRows.Free;
240end;
241
242function TSqlDatabase.Select(ATable: string; Filter: string = '*'; Condition: string = '1'): TDbRows;
243begin
244 Table := ATable;
245 Result := Query('SELECT ' + Filter + ' FROM `' + Table + '` WHERE '+Condition);
246end;
247
248procedure TSqlDatabase.Update(ATable: string; Data: TAssocArray; Condition: string = '1');
249var
250 DbValues: string;
251 Value: string;
252 I: Integer;
253 DbRows: TDbRows;
254begin
255 Table := ATable;
256 DbValues := '';
257 for I := 0 to Data.Count-1 do begin
258 Value := Data.ValuesAtIndex[I];
259 StringReplace(Value, '"', '\"', [rfReplaceAll]);
260 if Value = 'NOW()' then DbValues := DbValues + ',' + Value
261 else DbValues := DbValues + ',' + Data.Names[I] + '=' + '"' + Value + '"';
262 end;
263 System.Delete(DbValues, 1, 1);
264 DbRows := Query('UPDATE `' + Table + '` SET (' + DbValues + ') WHERE ' + Condition);
265 DBRows.Free;
266end;
267
268procedure TSqlDatabase.mySQLClient1ConnectError(Sender: TObject; Msg: String);
269begin
270// LastError := Msg + '('+IntToStr(mySQLClient1.LastErrorNumber)+')';
271end;
272
273{ TAssocArray }
274
275procedure TAssocArray.AddKeyValue(Key, Value: string);
276begin
277 Add(Key + NameValueSeparator + Value);
278end;
279
280constructor TAssocArray.Create;
281begin
282 NameValueSeparator := '|';
283end;
284
285destructor TAssocArray.Destroy;
286begin
287 inherited;
288end;
289
290function TAssocArray.GetAllValues: string;
291var
292 I: Integer;
293begin
294 Result := '';
295 for I := 0 to Count-1 do begin
296 Result := Result + Names[I] + '=' + ValuesAtIndex[I] + ',';
297 end;
298end;
299
300function TAssocArray.GetValues(Index: string): string;
301begin
302 Result := inherited Values[Index];
303end;
304
305function TAssocArray.GetValuesAtIndex(Index: Integer): string;
306begin
307 Result := inherited Values[Names[Index]];
308end;
309
310procedure TSqlDatabase.Delete(ATable: string; Condition: string = '1');
311var
312 DbRows: TDbRows;
313begin
314 Table := ATable;
315 DbRows := Query('DELETE FROM `' + Table + '` WHERE ' + Condition);
316 DbRows.Free;
317end;
318
319function TSqlDatabase.GetConnected: Boolean;
320begin
321 Result := FConnected;
322end;
323
324procedure TSqlDatabase.Disconnect;
325begin
326 mysql_close(FSession);
327 FConnected := False;
328end;
329
330constructor TSqlDatabase.Create;
331begin
332 inherited;
333 FSession := nil;
334end;
335
336procedure TAssocArray.SetValues(Index: string; const Value: string);
337begin
338 inherited Values[Index] := Value;
339end;
340
341{ TDbRows }
342
343destructor TDbRows.Destroy;
344var
345 I: Integer;
346begin
347 for I := 0 to Count - 1 do Data[I].Free;
348 inherited;
349end;
350
351function TDbRows.GetData(Index: Integer): TAssocArray;
352begin
353 Result := Items[Index];
354end;
355
356procedure TDbRows.SetData(Index: Integer; const Value: TAssocArray);
357begin
358 Items[Index] := Value;
359end;
360
361function TSqlDatabase.LastInsertId: Integer;
362begin
363 Result := mysql_insert_id(FSession);
364end;
365
366function TSqlDatabase.GetLastErrorMessage: string;
367begin
368 Result := mysql_error(FSession);
369end;
370
371function TSqlDatabase.GetLastErrorNumber: Integer;
372begin
373 Result := mysql_errno(FSession);
374end;
375
376function TSqlDatabase.CheckError: Boolean;
377begin
378 Result := LastErrorNumber <> 0;
379 if Result and Assigned(OnError) then OnError(Self);
380end;
381
382procedure TSqlDatabase.CreateDatabase;
383var
384 TempDatabase: string;
385begin
386 TempDatabase := Database;
387 Database := 'mysql';
388 Connect;
389 Query('CREATE DATABASE ' + TempDatabase);
390 Disconnect;
391 Database := TempDatabase;
392end;
393
394procedure TSqlDatabase.CreateTable(Name: string);
395begin
396 Query('CREATE TABLE `' + Name + '`' +
397 ' (`id` INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`));');
398end;
399
400procedure TSqlDatabase.CreateColumn(ATable, ColumnName: string;
401 ColumnType: TTypeKind);
402const
403 ColTypes: array[0..17] of string = ('', 'INT', 'CHAR', 'INT', 'DOUBLE',
404 'VARCHAR(255)', 'SET', 'INT', '', '', 'TEXT', 'TEXT', '', '', '', '', '', '');
405begin
406 Query('ALTER TABLE `' + Table + '` ADD `' + ColumnName + '` ' +
407 ColTypes[Integer(ColumnType)] + ' NOT NULL');
408end;
409
410destructor TSqlDatabase.Destroy;
411begin
412 if Connected then Disconnect;
413end;
414
415function TSqlDatabase.GetCharset: string;
416begin
417 Result := mysql_character_set_name(FSession);
418end;
419
420procedure TSqlDatabase.SetDatabase(const Value: string);
421begin
422 FDatabase := Value;
423 if FConnected then mysql_select_db(FSession, PChar(FDatabase));
424end;
425
426end.
427
428
Note: See TracBrowser for help on using the repository browser.