source: client/Delphi/USqlDatabase.pas

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