Changeset 7 for trunk/Common
- Timestamp:
- Dec 25, 2010, 9:53:55 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Common/USqlDatabase.pas
r2 r7 2 2 3 3 {$mode Delphi}{$H+} 4 // Upraveno: 30.5.2010 4 5 // Modified: 2010-12-24 5 6 6 7 interface 7 8 8 9 uses 9 SysUtils, Classes, Dialogs, mysql50, TypInfo; 10 SysUtils, Classes, Dialogs, mysql50, TypInfo, 11 SpecializedDictionary, SpecializedList; 10 12 11 13 type 12 EQueryError = Exception;14 EQueryError = class(Exception); 13 15 14 16 TClientCapabilities = (_CLIENT_LONG_PASSWORD, _CLIENT_FOUND_ROWS, … … 19 21 TSetClientCapabilities = set of TClientCapabilities; 20 22 21 T AssociativeArray = class(TStringList)23 TDbRows = class(TListObject) 22 24 private 23 function GetValues(Index: string): string; 24 function GetValuesAtIndex(Index: Integer): string; 25 procedure SetValues(Index: string; const Value: string); 25 function GetData(Index: Integer): TDictionaryStringString; 26 procedure SetData(Index: Integer; const Value: TDictionaryStringString); 26 27 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; 28 property Data[Index: Integer]: TDictionaryStringString read GetData write SetData; default; 41 29 destructor Destroy; override; 42 30 end; … … 51 39 function GetLastErrorMessage: string; 52 40 function GetLastErrorNumber: Integer; 53 function CheckError: Boolean;54 41 function GetCharset: string; 55 procedure Set Schema(const Value: string);42 procedure SetDatabase(const Value: string); 56 43 public 57 44 Hostname: string; … … 65 52 procedure CreateTable(Name: string); 66 53 procedure CreateColumn(Table, ColumnName: string; ColumnType: TTypeKind); 67 function Query(Data: string): TDbRows;68 function Select(ATable: string; Filter: string = '*'; Condition: string = '1'): TDbRows;54 procedure Query(DbRows: TDbRows; Data: string); 55 procedure Select(DbRows: TDbRows; ATable: string; Filter: string = '*'; Condition: string = '1'); 69 56 procedure Delete(ATable: string; Condition: string = '1'); 70 procedure Insert(ATable: string; Data: T AssociativeArray);71 procedure Update(ATable: string; Data: T AssociativeArray; Condition: string = '1');72 procedure Replace(ATable: string; Data: T AssociativeArray);57 procedure Insert(ATable: string; Data: TDictionaryStringString); 58 procedure Update(ATable: string; Data: TDictionaryStringString; Condition: string = '1'); 59 procedure Replace(ATable: string; Data: TDictionaryStringString); 73 60 procedure Connect; 74 61 procedure Disconnect; … … 80 67 destructor Destroy; override; 81 68 property Charset: string read GetCharset; 82 property Schema: string read FDatabase write SetSchema;69 property Database: string read FDatabase write SetDatabase; 83 70 end; 84 71 85 72 function MySQLFloatToStr(F: Real): string; 86 73 function MySQLStrToFloat(S: string): Real; 74 function SQLToDateTime(Value: string): TDateTime; 75 function DateTimeToSQL(Value: TDateTime): string; 87 76 88 77 implementation 89 78 90 uses DateUtils; 79 uses 80 DateUtils, Math; 81 82 resourcestring 83 SDatabaseQueryError = 'Database query error: "%s"'; 91 84 92 85 const … … 105 98 CLIENT_TRANSACTIONS = 8192; // Client knows about transactions 106 99 107 { TDataModule2 }108 109 100 function MySQLFloatToStr(F: Real): string; 110 101 var … … 112 103 begin 113 104 S := FloatToStr(F); 114 if Pos(',', S) > 0 then S[Pos(',', S)] := '.';105 if Pos(',', S) > 0 then S[Pos(',', S)] := '.'; 115 106 Result := S; 116 107 end; … … 118 109 function MySQLStrToFloat(S: string): Real; 119 110 begin 120 if Pos('.', S) > 0 then S[Pos('.',S)] := ',';111 if Pos('.', S) > 0 then S[Pos('.', S)] := ','; 121 112 Result := StrToFloat(S); 122 113 end; 114 115 function StrToStr(Value: string): string; 116 begin 117 Result := Value; 118 end; 119 120 function SQLToDateTime(Value: string): TDateTime; 121 var 122 Parts: TListString; 123 DateParts: TListString; 124 TimeParts: TListString; 125 begin 126 try 127 Parts := TListString.Create; 128 DateParts := TListString.Create; 129 TimeParts := TListString.Create; 130 131 Parts.Explode(Value, ' ', StrToStr); 132 DateParts.Explode(Parts[0], '-', StrToStr); 133 Result := EncodeDate(StrToInt(DateParts[0]), StrToInt(DateParts[1]), 134 StrToInt(DateParts[2])); 135 if Parts.Count > 1 then begin 136 TimeParts.Explode(Parts[1], ':', StrToStr); 137 Result := Result + EncodeTime(StrToInt(TimeParts[0]), StrToInt(TimeParts[1]), 138 StrToInt(TimeParts[2]), 0); 139 end; 140 finally 141 DateParts.Free; 142 TimeParts.Free; 143 Parts.Free; 144 end; 145 end; 146 147 function DateTimeToSQL(Value: TDateTime): string; 148 begin 149 Result := FormatDateTime('yyyy-mm-dd hh.nn.ss', Value); 150 end; 151 152 { TSqlDatabase } 123 153 124 154 procedure TSqlDatabase.Connect; … … 132 162 // FSession.charset := 'latin2'; 133 163 NewSession := mysql_real_connect(FSession, PChar(HostName), PChar(UserName), 134 PChar(Password), PChar( Schema), 3306, nil, CLIENT_LONG_PASSWORD + CLIENT_CONNECT_WITH_DB);164 PChar(Password), PChar(Database), 3306, nil, CLIENT_LONG_PASSWORD + CLIENT_CONNECT_WITH_DB); 135 165 if Assigned(NewSession) then begin 136 166 FConnected := True; 137 167 FSession := NewSession; 138 168 end else FConnected := False; 139 CheckError; 140 Rows := Query('SET NAMES ' + Encoding); 141 Rows.Free; 142 end; 143 144 procedure TSqlDatabase.Insert(ATable: string; Data: TAssociativeArray); 169 170 if LastErrorNumber <> 0 then 171 raise EQueryError.Create(Format(SDatabaseQueryError, [LastErrorMessage])); 172 173 try 174 Rows := TDbRows.Create; 175 Query(Rows, 'SET NAMES ' + Encoding); 176 finally 177 Rows.Free; 178 end; 179 end; 180 181 procedure TSqlDatabase.Insert(ATable: string; Data: TDictionaryStringString); 145 182 var 146 183 DbNames: string; … … 154 191 DbValues := ''; 155 192 for I := 0 to Data.Count - 1 do begin 156 Value := Data. ValuesAtIndex[I];193 Value := Data.Items[I].Value; 157 194 StringReplace(Value, '"', '\"', [rfReplaceAll]); 158 195 if Value = 'NOW()' then DbValues := DbValues + ',' + Value 159 196 else DbValues := DbValues + ',"' + Value + '"'; 160 DbNames := DbNames + ',`' + Data. Names[I] + '`';197 DbNames := DbNames + ',`' + Data.Keys[I] + '`'; 161 198 end; 162 199 System.Delete(DbNames, 1, 1); 163 200 System.Delete(DbValues, 1, 1); 164 DbResult := Query('INSERT INTO `' + Table + '` (' + DbNames + ') VALUES (' + DbValues + ')'); 165 DbResult.Free; 166 end; 167 168 function TSqlDatabase.Query(Data: string): TDbRows; 201 try 202 DbResult := TDbRows.Create; 203 Query(DbResult, 'INSERT INTO `' + Table + '` (' + DbNames + ') VALUES (' + DbValues + ')'); 204 finally 205 DbResult.Free; 206 end; 207 end; 208 209 procedure TSqlDatabase.Query(DbRows: TDbRows; Data: string); 169 210 var 170 211 I, II: Integer; … … 172 213 DbRow: MYSQL_ROW; 173 214 begin 215 DbRows.Clear; 174 216 //DebugLog('SqlDatabase query: '+Data); 175 217 RepeatLastAction := False; 176 218 LastQuery := Data; 177 //if not Connected then NastaveniPripojeni.ShowModal;178 Result := TDbRows.Create;179 //repeat180 219 mysql_query(FSession, PChar(Data)); 181 //until not182 CheckError;183 //if not CheckError then184 begin 185 186 187 Result.Count := mysql_num_rows(DbResult);188 for I := 0 to Result.Count - 1 do begin189 190 Result[I] := TAssociativeArray.Create;191 with Result[I] do begin192 193 Add(mysql_fetch_field_direct(DbResult, II)^.Name +194 NameValueSeparator +PChar((DbRow + II)^));220 if LastErrorNumber <> 0 then begin 221 raise EQueryError.Create(Format(SDatabaseQueryError, [LastErrorMessage])); 222 end; 223 224 DbResult := mysql_store_result(FSession); 225 if Assigned(DbResult) then begin 226 DbRows.Count := mysql_num_rows(DbResult); 227 for I := 0 to DbRows.Count - 1 do begin 228 DbRow := mysql_fetch_row(DbResult); 229 DbRows[I] := TDictionaryStringString.Create; 230 with DbRows[I] do begin 231 for II := 0 to mysql_num_fields(DbResult) - 1 do begin 232 Add(mysql_fetch_field_direct(DbResult, II)^.Name, 233 PChar((DbRow + II)^)); 195 234 end; 196 235 end; 197 236 end; 198 end;199 237 end; 200 238 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 *) 208 end; 209 210 procedure TSqlDatabase.Replace(ATable: string; Data: TAssociativeArray); 239 end; 240 241 procedure TSqlDatabase.Replace(ATable: string; Data: TDictionaryStringString); 211 242 var 212 243 DbNames: string; … … 220 251 DbValues := ''; 221 252 for I := 0 to Data.Count - 1 do begin 222 Value := Data. ValuesAtIndex[I];253 Value := Data.Items[I].Value; 223 254 StringReplace(Value, '"', '\"', [rfReplaceAll]); 224 255 if Value = 'NOW()' then DbValues := DbValues + ',' + Value 225 256 else DbValues := DbValues + ',"' + Value + '"'; 226 DbNames := DbNames + ',`' + Data. Names[I] + '`';257 DbNames := DbNames + ',`' + Data.Keys[I] + '`'; 227 258 end; 228 259 System.Delete(DbNames, 1, 1); 229 260 System.Delete(DbValues, 1, 1); 230 DbResult := Query('REPLACE INTO `' + Table + '` (' + DbNames + ') VALUES (' + DbValues + ')'); 231 DbResult.Free; 232 end; 233 234 function TSqlDatabase.Select(ATable: string; Filter: string = '*'; Condition: string = '1'): TDbRows; 261 try 262 DbResult := TDbRows.Create; 263 Query(DbResult, 'REPLACE INTO `' + Table + '` (' + DbNames + ') VALUES (' + DbValues + ')'); 264 finally 265 DbResult.Free; 266 end; 267 end; 268 269 procedure TSqlDatabase.Select(DbRows: TDbRows; ATable: string; Filter: string = '*'; Condition: string = '1'); 235 270 begin 236 271 Table := ATable; 237 Result := Query('SELECT ' + Filter + ' FROM `' + Table + '` WHERE '+Condition);238 end; 239 240 procedure TSqlDatabase.Update(ATable: string; Data: T AssociativeArray; Condition: string = '1');272 Query(DbRows, 'SELECT ' + Filter + ' FROM `' + Table + '` WHERE ' + Condition); 273 end; 274 275 procedure TSqlDatabase.Update(ATable: string; Data: TDictionaryStringString; Condition: string = '1'); 241 276 var 242 277 DbValues: string; … … 248 283 DbValues := ''; 249 284 for I := 0 to Data.Count - 1 do begin 250 Value := Data. ValuesAtIndex[I];285 Value := Data.Items[I].Value; 251 286 StringReplace(Value, '"', '\"', [rfReplaceAll]); 252 287 if Value = 'NOW()' then DbValues := DbValues + ',' + Value 253 else DbValues := DbValues + ',' + Data. Names[I] + '=' + '"' + Value + '"';288 else DbValues := DbValues + ',' + Data.Keys[I] + '=' + '"' + Value + '"'; 254 289 end; 255 290 System.Delete(DbValues, 1, 1); 256 DbResult := Query('UPDATE `' + Table + '` SET (' + DbValues + ') WHERE ' + Condition); 257 DbResult.Free; 291 try 292 DbResult := TDbRows.Create; 293 Query(DbResult, 'UPDATE `' + Table + '` SET (' + DbValues + ') WHERE ' + Condition); 294 finally 295 DbResult.Free; 296 end; 258 297 end; 259 298 … … 263 302 end; 264 303 265 { TAssocArray }266 267 procedure TAssociativeArray.AddKeyValue(Key, Value: string);268 begin269 Add(Key + NameValueSeparator + Value);270 end;271 272 constructor TAssociativeArray.Create;273 begin274 NameValueSeparator := '|';275 end;276 277 destructor TAssociativeArray.Destroy;278 begin279 inherited;280 end;281 282 function TAssociativeArray.GetAllValues: string;283 var284 I: Integer;285 begin286 Result := '';287 for I := 0 to Count - 1 do begin288 Result := Result + Names[I] + '=' + ValuesAtIndex[I] + ',';289 end;290 end;291 292 function TAssociativeArray.GetValues(Index: string): string;293 begin294 Result := inherited Values[Index];295 end;296 297 function TAssociativeArray.GetValuesAtIndex(Index: Integer): string;298 begin299 Result := inherited Values[Names[Index]];300 end;301 302 304 procedure TSqlDatabase.Delete(ATable: string; Condition: string = '1'); 303 305 var … … 305 307 begin 306 308 Table := ATable; 307 DbResult := Query('DELETE FROM `' + Table + '` WHERE ' + Condition); 308 DbResult.Free; 309 try 310 DbResult := TDbRows.Create; 311 Query(DbResult, 'DELETE FROM `' + Table + '` WHERE ' + Condition); 312 finally 313 DbResult.Free; 314 end; 309 315 end; 310 316 … … 327 333 end; 328 334 329 procedure TAssociativeArray.SetValues(Index: string; const Value: string);330 begin331 inherited Values[Index] := Value;332 end;333 334 { TDbRows }335 336 destructor TDbRows.Destroy;337 var338 I: Integer;339 begin340 for I := 0 to Count - 1 do341 Data[I].Free;342 inherited;343 end;344 345 function TDbRows.GetData(Index: Integer): TAssociativeArray;346 begin347 Result := Items[Index];348 end;349 350 procedure TDbRows.SetData(Index: Integer; const Value: TAssociativeArray);351 begin352 Items[Index] := Value;353 end;354 355 335 function TSqlDatabase.LastInsertId: Integer; 356 336 begin … … 368 348 end; 369 349 370 function TSqlDatabase.CheckError: Boolean;371 begin372 Result := LastErrorNumber <> 0;373 if Result then374 raise EQueryError.Create('Database query error: "' + LastErrorMessage + '"');375 end;376 377 350 procedure TSqlDatabase.CreateDatabase; 378 351 var 379 352 TempDatabase: string; 380 begin 381 TempDatabase := Schema; 382 Schema := 'mysql'; 353 DbRows: TDbRows; 354 begin 355 TempDatabase := Database; 356 Database := 'mysql'; 383 357 Connect; 384 Query('CREATE DATABASE ' + TempDatabase); 358 try 359 DbRows := TDbRows.Create; 360 Query(DbRows, 'CREATE DATABASE ' + TempDatabase); 361 finally 362 DbRows.Free; 363 end; 385 364 Disconnect; 386 Schema:= TempDatabase;365 Database := TempDatabase; 387 366 end; 388 367 389 368 procedure TSqlDatabase.CreateTable(Name: string); 390 begin 391 Query('CREATE TABLE `' + Name + '`' + 392 ' (`Id` INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (`Id`));'); 369 var 370 DbRows: TDbRows; 371 begin 372 try 373 DbRows := TDbRows.Create; 374 Query(DbRows, 'CREATE TABLE `' + Name + '`' + 375 ' (`Id` INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (`Id`));'); 376 finally 377 DbRows.Free; 378 end; 393 379 end; 394 380 … … 398 384 ColTypes: array[0..17] of string = ('', 'INT', 'CHAR', 'INT', 'DOUBLE', 399 385 'VARCHAR(255)', 'SET', 'INT', '', '', 'TEXT', 'TEXT', '', '', '', '', '', ''); 400 begin 401 Query('ALTER TABLE `' + Table + '` ADD `' + ColumnName + '` ' + 402 ColTypes[Integer(ColumnType)] + ' NOT NULL'); 386 var 387 DbRows: TDbRows; 388 begin 389 try 390 DbRows := TDbRows.Create; 391 Query(DbRows, 'ALTER TABLE `' + Table + '` ADD `' + ColumnName + '` ' + 392 ColTypes[Integer(ColumnType)] + ' NOT NULL'); 393 finally 394 DbRows.Free; 395 end; 403 396 end; 404 397 … … 413 406 end; 414 407 415 procedure TSqlDatabase.Set Schema(const Value: string);408 procedure TSqlDatabase.SetDatabase(const Value: string); 416 409 begin 417 410 FDatabase := Value; … … 419 412 end; 420 413 414 { TDbRows } 415 416 destructor TDbRows.Destroy; 417 begin 418 inherited; 419 end; 420 421 function TDbRows.GetData(Index: Integer): TDictionaryStringString; 422 begin 423 Result := TDictionaryStringString(Items[Index]); 424 end; 425 426 procedure TDbRows.SetData(Index: Integer; const Value: TDictionaryStringString); 427 begin 428 Items[Index] := Value; 429 end; 430 421 431 end. 422 432
Note:
See TracChangeset
for help on using the changeset viewer.