source: branches/web/Common/USqlDatabase.pas

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