source: branches/DirectWeb/USqlDatabase.pas

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