source: branches/web2/USqlDatabase.pas

Last change on this file was 1, checked in by george, 16 years ago

Prvotní import všeho

  • Property svn:executable set to *
File size: 11.6 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
87implementation
88
89uses DateUtils, Math;
90
91const
92 CLIENT_LONG_PASSWORD = 1; // new more secure passwords
93 CLIENT_FOUND_ROWS = 2; // Found instead of affected rows
94 CLIENT_LONG_FLAG = 4; // Get all column flags
95 CLIENT_CONNECT_WITH_DB = 8; // One can specify db on connect
96 CLIENT_NO_SCHEMA = 16; // Don't allow database.table.column
97 CLIENT_COMPRESS = 32; // Can use compression protcol
98 CLIENT_ODBC = 64; // Odbc client
99 CLIENT_LOCAL_FILES = 128; // Can use LOAD DATA LOCAL
100 CLIENT_IGNORE_SPACE = 256; // Ignore spaces before '('
101 CLIENT_INTERACTIVE = 1024; // This is an interactive client
102 CLIENT_SSL = 2048; // Switch to SSL after handshake
103 CLIENT_IGNORE_SIGPIPE = 4096; // IGNORE sigpipes
104 CLIENT_TRANSACTIONS = 8192; // Client knows about transactions
105
106{ TDataModule2 }
107
108function MySQLFloatToStr(F: Real): string;
109var
110 S: string;
111begin
112 S := FloatToStr(F);
113 if Pos(',',S) > 0 then S[Pos(',',S)] := '.';
114 Result := S;
115end;
116
117function MySQLStrToFloat(S: string): Real;
118begin
119 if Pos('.',S) > 0 then S[Pos('.',S)] := ',';
120 Result := StrToFloat(S);
121end;
122
123procedure TSqlDatabase.Connect;
124var
125 NewSession: PMYSQL;
126 Rows: TDbRows;
127begin
128 RepeatLastAction := False;
129// mySQLClient1.Connect;
130 FSession := mysql_init(FSession);
131// FSession.charset := 'latin2';
132 NewSession := mysql_real_connect(FSession, PChar(HostName), PChar(UserName),
133 PChar(Password), PChar(Database), 3306, nil, CLIENT_LONG_PASSWORD + CLIENT_CONNECT_WITH_DB);
134 if Assigned(NewSession) then begin
135 FConnected := True;
136 FSession := NewSession;
137 end else FConnected := False;
138 CheckError;
139 Rows := Query('SET NAMES cp1250');
140 Rows.Free;
141end;
142
143procedure TSqlDatabase.Insert(ATable: string; Data: TAssocArray);
144var
145 DbNames: string;
146 DbValues: string;
147 I: Integer;
148 Value: string;
149begin
150 Table := ATable;
151 DbNames := '';
152 DbValues := '';
153 for I := 0 to Data.Count-1 do begin
154 Value := Data.ValuesAtIndex[I];
155 StringReplace(Value, '"', '\"', [rfReplaceAll]);
156 if Value = 'NOW()' then DbValues := DbValues + ',' + Value
157 else DbValues := DbValues + ',"' + Value + '"';
158 DbNames := DbNames + ',`' + Data.Names[I] + '`';
159 end;
160 System.Delete(DbNames, 1, 1);
161 System.Delete(DbValues, 1, 1);
162 Query('INSERT INTO `' + Table + '` (' + DbNames + ') VALUES (' + DbValues + ')');
163end;
164
165function TSqlDatabase.Query(Data: string): TDbRows;
166var
167 I, II: Integer;
168 DbResult: PMYSQL_RES;
169 DbRow: MYSQL_ROW;
170type
171 PMYSQL_ROW2 = ^TMYSQL_ROW2; // return data as array of strings
172 TMYSQL_ROW2 = array[0..MaxInt div SizeOf(pChar) - 1] of pChar;
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] := TAssocArray.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 + NameValueSeparator + PMYSQL_ROW2(DbRow)^[II]);
194 end;
195 end;
196 end;
197 end;
198 end;
199 mysql_free_result(DbResult);
200 (*
201 if Assigned(DatabaseIntegrity) then
202 with DatabaseIntegrity do if not Checking then begin
203 Check;
204 DebugLog('Database integrity: Unreferenced='+IntToStr(Unreferenced)+' BadReferences='+IntToStr(BadReferences));
205 end;
206 *)
207end;
208
209procedure TSqlDatabase.Replace(ATable: string; Data: TAssocArray);
210var
211 DbNames: string;
212 DbValues: string;
213 Value: string;
214 I: Integer;
215begin
216 Table := ATable;
217 DbNames := '';
218 DbValues := '';
219 for I := 0 to Data.Count-1 do begin
220 Value := Data.ValuesAtIndex[I];
221 StringReplace(Value, '"', '\"', [rfReplaceAll]);
222 if Value = 'NOW()' then DbValues := DbValues + ',' + Value
223 else DbValues := DbValues + ',"' + Value + '"';
224 DbNames := DbNames + ',`' + Data.Names[I] + '`';
225 end;
226 System.Delete(DbNames, 1, 1);
227 System.Delete(DbValues, 1, 1);
228 Query('REPLACE INTO `' + Table + '` (' + DbNames + ') VALUES (' + DbValues + ')');
229end;
230
231function TSqlDatabase.Select(ATable: string; Filter: string = '*'; Condition: string = '1'): TDbRows;
232begin
233 Table := ATable;
234 Result := Query('SELECT ' + Filter + ' FROM `' + Table + '` WHERE '+Condition);
235end;
236
237procedure TSqlDatabase.Update(ATable: string; Data: TAssocArray; Condition: string = '1');
238var
239 DbValues: string;
240 Value: string;
241 I: Integer;
242begin
243 Table := ATable;
244 DbValues := '';
245 for I := 0 to Data.Count-1 do begin
246 Value := Data.ValuesAtIndex[I];
247 StringReplace(Value, '"', '\"', [rfReplaceAll]);
248 if Value = 'NOW()' then DbValues := DbValues + ',' + Value
249 else DbValues := DbValues + ',' + Data.Names[I] + '=' + '"' + Value + '"';
250 end;
251 System.Delete(DbValues, 1, 1);
252 Query('UPDATE `' + Table + '` SET (' + DbValues + ') WHERE ' + Condition);
253end;
254
255procedure TSqlDatabase.mySQLClient1ConnectError(Sender: TObject; Msg: String);
256begin
257// LastError := Msg + '('+IntToStr(mySQLClient1.LastErrorNumber)+')';
258end;
259
260{ TAssocArray }
261
262procedure TAssocArray.AddKeyValue(Key, Value: string);
263begin
264 Add(Key + NameValueSeparator + Value);
265end;
266
267constructor TAssocArray.Create;
268begin
269 NameValueSeparator := '|';
270end;
271
272destructor TAssocArray.Destroy;
273begin
274 inherited;
275end;
276
277function TAssocArray.GetAllValues: string;
278var
279 I: Integer;
280begin
281 Result := '';
282 for I := 0 to Count-1 do begin
283 Result := Result + Names[I] + '=' + ValuesAtIndex[I] + ',';
284 end;
285end;
286
287function TAssocArray.GetValues(Index: string): string;
288begin
289 Result := inherited Values[Index];
290end;
291
292function TAssocArray.GetValuesAtIndex(Index: Integer): string;
293begin
294 Result := inherited Values[Names[Index]];
295end;
296
297procedure TSqlDatabase.Delete(ATable: string; Condition: string = '1');
298begin
299 Table := ATable;
300 Query('DELETE FROM `' + Table + '` WHERE ' + Condition);
301end;
302
303function TSqlDatabase.GetConnected: Boolean;
304begin
305 Result := FConnected;
306end;
307
308procedure TSqlDatabase.Disconnect;
309begin
310 mysql_close(FSession);
311 FConnected := False;
312end;
313
314constructor TSqlDatabase.Create;
315begin
316 inherited;
317 FSession := nil;
318end;
319
320procedure TAssocArray.SetValues(Index: string; const Value: string);
321begin
322 inherited Values[Index] := Value;
323end;
324
325{ TDbRows }
326
327destructor TDbRows.Destroy;
328var
329 I: Integer;
330begin
331 for I := 0 to Count - 1 do Data[I].Free;
332 inherited;
333end;
334
335function TDbRows.GetData(Index: Integer): TAssocArray;
336begin
337 Result := Items[Index];
338end;
339
340procedure TDbRows.SetData(Index: Integer; const Value: TAssocArray);
341begin
342 Items[Index] := Value;
343end;
344
345function TSqlDatabase.LastInsertId: Integer;
346begin
347 Result := mysql_insert_id(FSession);
348end;
349
350function TSqlDatabase.GetLastErrorMessage: string;
351begin
352 Result := mysql_error(FSession);
353end;
354
355function TSqlDatabase.GetLastErrorNumber: Integer;
356begin
357 Result := mysql_errno(FSession);
358end;
359
360function TSqlDatabase.CheckError: Boolean;
361begin
362 Result := LastErrorNumber <> 0;
363 if Result and Assigned(OnError) then OnError(Self);
364end;
365
366procedure TSqlDatabase.CreateDatabase;
367var
368 TempDatabase: string;
369begin
370 TempDatabase := Database;
371 Database := 'mysql';
372 Connect;
373 Query('CREATE DATABASE ' + TempDatabase);
374 Disconnect;
375 Database := TempDatabase;
376end;
377
378procedure TSqlDatabase.CreateTable(Name: string);
379begin
380 Query('CREATE TABLE `' + Name + '`' +
381 ' (`id` INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`));');
382end;
383
384procedure TSqlDatabase.CreateColumn(ATable, ColumnName: string;
385 ColumnType: TTypeKind);
386const
387 ColTypes: array[0..17] of string = ('', 'INT', 'CHAR', 'INT', 'DOUBLE',
388 'VARCHAR(255)', 'SET', 'INT', '', '', 'TEXT', 'TEXT', '', '', '', '', '', '');
389begin
390 Query('ALTER TABLE `' + Table + '` ADD `' + ColumnName + '` ' +
391 ColTypes[Integer(ColumnType)] + ' NOT NULL');
392end;
393
394destructor TSqlDatabase.Destroy;
395begin
396 if Connected then Disconnect;
397end;
398
399function TSqlDatabase.GetCharset: string;
400begin
401 Result := mysql_character_set_name(FSession);
402end;
403
404procedure TSqlDatabase.SetDatabase(const Value: string);
405begin
406 FDatabase := Value;
407 if FConnected then mysql_select_db(FSession, PChar(FDatabase));
408end;
409
410end.
411
412
Note: See TracBrowser for help on using the repository browser.