Ignore:
Timestamp:
Dec 25, 2010, 9:53:55 PM (14 years ago)
Author:
george
Message:
  • Updated: USqlDatabase library.
  • Added: Dependency to TemplateGenerics package.
  • Modified: Rest of czech strings translated to english.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Common/USqlDatabase.pas

    r2 r7  
    22
    33{$mode Delphi}{$H+}
    4 // Upraveno: 30.5.2010
     4
     5// Modified: 2010-12-24
    56
    67interface
    78
    89uses
    9   SysUtils, Classes, Dialogs, mysql50, TypInfo;
     10  SysUtils, Classes, Dialogs, mysql50, TypInfo,
     11  SpecializedDictionary, SpecializedList;
    1012
    1113type
    12   EQueryError = Exception;
     14  EQueryError = class(Exception);
    1315
    1416  TClientCapabilities = (_CLIENT_LONG_PASSWORD, _CLIENT_FOUND_ROWS,
     
    1921  TSetClientCapabilities = set of TClientCapabilities;
    2022
    21   TAssociativeArray = class(TStringList)
     23  TDbRows = class(TListObject)
    2224  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);
    2627  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;
    4129    destructor Destroy; override;
    4230  end;
     
    5139    function GetLastErrorMessage: string;
    5240    function GetLastErrorNumber: Integer;
    53     function CheckError: Boolean;
    5441    function GetCharset: string;
    55     procedure SetSchema(const Value: string);
     42    procedure SetDatabase(const Value: string);
    5643  public
    5744    Hostname: string;
     
    6552    procedure CreateTable(Name: string);
    6653    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');
    6956    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);
     57    procedure Insert(ATable: string; Data: TDictionaryStringString);
     58    procedure Update(ATable: string; Data: TDictionaryStringString; Condition: string = '1');
     59    procedure Replace(ATable: string; Data: TDictionaryStringString);
    7360    procedure Connect;
    7461    procedure Disconnect;
     
    8067    destructor Destroy; override;
    8168    property Charset: string read GetCharset;
    82     property Schema: string read FDatabase write SetSchema;
     69    property Database: string read FDatabase write SetDatabase;
    8370  end;
    8471
    8572  function MySQLFloatToStr(F: Real): string;
    8673  function MySQLStrToFloat(S: string): Real;
     74  function SQLToDateTime(Value: string): TDateTime;
     75  function DateTimeToSQL(Value: TDateTime): string;
    8776
    8877implementation
    8978
    90 uses DateUtils;
     79uses
     80  DateUtils, Math;
     81
     82resourcestring
     83  SDatabaseQueryError = 'Database query error: "%s"';
    9184
    9285const
     
    10598  CLIENT_TRANSACTIONS = 8192;    // Client knows about transactions
    10699
    107 { TDataModule2 }
    108 
    109100function MySQLFloatToStr(F: Real): string;
    110101var
     
    112103begin
    113104  S := FloatToStr(F);
    114   if Pos(',', S) > 0 then S[Pos(',',S)] := '.';
     105  if Pos(',', S) > 0 then S[Pos(',', S)] := '.';
    115106  Result := S;
    116107end;
     
    118109function MySQLStrToFloat(S: string): Real;
    119110begin
    120   if Pos('.', S) > 0 then  S[Pos('.',S)] := ',';
     111  if Pos('.', S) > 0 then S[Pos('.', S)] := ',';
    121112  Result := StrToFloat(S);
    122113end;
     114
     115function StrToStr(Value: string): string;
     116begin
     117  Result := Value;
     118end;
     119
     120function SQLToDateTime(Value: string): TDateTime;
     121var
     122  Parts: TListString;
     123  DateParts: TListString;
     124  TimeParts: TListString;
     125begin
     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;
     145end;
     146
     147function DateTimeToSQL(Value: TDateTime): string;
     148begin
     149  Result := FormatDateTime('yyyy-mm-dd hh.nn.ss', Value);
     150end;
     151
     152{ TSqlDatabase }
    123153
    124154procedure TSqlDatabase.Connect;
     
    132162//  FSession.charset := 'latin2';
    133163  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);
    135165  if Assigned(NewSession) then begin
    136166    FConnected := True;
    137167    FSession := NewSession;
    138168  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;
     179end;
     180
     181procedure TSqlDatabase.Insert(ATable: string; Data: TDictionaryStringString);
    145182var
    146183  DbNames: string;
     
    154191  DbValues := '';
    155192  for I := 0 to Data.Count - 1 do begin
    156     Value := Data.ValuesAtIndex[I];
     193    Value := Data.Items[I].Value;
    157194    StringReplace(Value, '"', '\"', [rfReplaceAll]);
    158195    if Value = 'NOW()' then DbValues := DbValues + ',' + Value
    159196    else DbValues := DbValues + ',"' + Value + '"';
    160     DbNames := DbNames + ',`' + Data.Names[I] + '`';
     197    DbNames := DbNames + ',`' + Data.Keys[I] + '`';
    161198  end;
    162199  System.Delete(DbNames, 1, 1);
    163200  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;
     207end;
     208
     209procedure TSqlDatabase.Query(DbRows: TDbRows; Data: string);
    169210var
    170211  I, II: Integer;
     
    172213  DbRow: MYSQL_ROW;
    173214begin
     215  DbRows.Clear;
    174216  //DebugLog('SqlDatabase query: '+Data);
    175217  RepeatLastAction := False;
    176218  LastQuery := Data;
    177   //if not Connected then NastaveniPripojeni.ShowModal;
    178   Result := TDbRows.Create;
    179   //repeat
    180219  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)^));
     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)^));
    195234          end;
    196235        end;
    197236      end;
    198     end;
    199237  end;
    200238  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);
     239end;
     240
     241procedure TSqlDatabase.Replace(ATable: string; Data: TDictionaryStringString);
    211242var
    212243  DbNames: string;
     
    220251  DbValues := '';
    221252  for I := 0 to Data.Count - 1 do begin
    222     Value := Data.ValuesAtIndex[I];
     253    Value := Data.Items[I].Value;
    223254    StringReplace(Value, '"', '\"', [rfReplaceAll]);
    224255    if Value = 'NOW()' then DbValues := DbValues + ',' + Value
    225256    else DbValues := DbValues + ',"' + Value + '"';
    226     DbNames := DbNames + ',`' + Data.Names[I] + '`';
     257    DbNames := DbNames + ',`' + Data.Keys[I] + '`';
    227258  end;
    228259  System.Delete(DbNames, 1, 1);
    229260  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;
     267end;
     268
     269procedure TSqlDatabase.Select(DbRows: TDbRows; ATable: string; Filter: string = '*'; Condition: string = '1');
    235270begin
    236271  Table := ATable;
    237   Result := Query('SELECT ' + Filter + ' FROM `' + Table + '` WHERE '+Condition);
    238 end;
    239 
    240 procedure TSqlDatabase.Update(ATable: string; Data: TAssociativeArray; Condition: string = '1');
     272  Query(DbRows, 'SELECT ' + Filter + ' FROM `' + Table + '` WHERE ' + Condition);
     273end;
     274
     275procedure TSqlDatabase.Update(ATable: string; Data: TDictionaryStringString; Condition: string = '1');
    241276var
    242277  DbValues: string;
     
    248283  DbValues := '';
    249284  for I := 0 to Data.Count - 1 do begin
    250     Value := Data.ValuesAtIndex[I];
     285    Value := Data.Items[I].Value;
    251286    StringReplace(Value, '"', '\"', [rfReplaceAll]);
    252287    if Value = 'NOW()' then DbValues := DbValues + ',' + Value
    253     else DbValues := DbValues + ',' + Data.Names[I] + '=' + '"' + Value + '"';
     288    else DbValues := DbValues + ',' + Data.Keys[I] + '=' + '"' + Value + '"';
    254289  end;
    255290  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;
    258297end;
    259298
     
    263302end;
    264303
    265 { TAssocArray }
    266 
    267 procedure TAssociativeArray.AddKeyValue(Key, Value: string);
    268 begin
    269   Add(Key + NameValueSeparator + Value);
    270 end;
    271 
    272 constructor TAssociativeArray.Create;
    273 begin
    274   NameValueSeparator := '|';
    275 end;
    276 
    277 destructor TAssociativeArray.Destroy;
    278 begin
    279   inherited;
    280 end;
    281 
    282 function TAssociativeArray.GetAllValues: string;
    283 var
    284   I: Integer;
    285 begin
    286   Result := '';
    287   for I := 0 to Count - 1 do begin
    288     Result := Result + Names[I] + '=' + ValuesAtIndex[I] + ',';
    289   end;
    290 end;
    291 
    292 function TAssociativeArray.GetValues(Index: string): string;
    293 begin
    294   Result := inherited Values[Index];
    295 end;
    296 
    297 function TAssociativeArray.GetValuesAtIndex(Index: Integer): string;
    298 begin
    299   Result := inherited Values[Names[Index]];
    300 end;
    301 
    302304procedure TSqlDatabase.Delete(ATable: string; Condition: string = '1');
    303305var
     
    305307begin
    306308  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;
    309315end;
    310316
     
    327333end;
    328334
    329 procedure TAssociativeArray.SetValues(Index: string; const Value: string);
    330 begin
    331   inherited Values[Index] := Value;
    332 end;
    333 
    334 { TDbRows }
    335 
    336 destructor TDbRows.Destroy;
    337 var
    338   I: Integer;
    339 begin
    340   for I := 0 to Count - 1 do
    341     Data[I].Free;
    342   inherited;
    343 end;
    344 
    345 function TDbRows.GetData(Index: Integer): TAssociativeArray;
    346 begin
    347   Result := Items[Index];
    348 end;
    349 
    350 procedure TDbRows.SetData(Index: Integer; const Value: TAssociativeArray);
    351 begin
    352   Items[Index] := Value;
    353 end;
    354 
    355335function TSqlDatabase.LastInsertId: Integer;
    356336begin
     
    368348end;
    369349
    370 function TSqlDatabase.CheckError: Boolean;
    371 begin
    372   Result := LastErrorNumber <> 0;
    373   if Result then
    374     raise EQueryError.Create('Database query error: "' + LastErrorMessage + '"');
    375 end;
    376 
    377350procedure TSqlDatabase.CreateDatabase;
    378351var
    379352  TempDatabase: string;
    380 begin
    381   TempDatabase := Schema;
    382   Schema := 'mysql';
     353  DbRows: TDbRows;
     354begin
     355  TempDatabase := Database;
     356  Database := 'mysql';
    383357  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;
    385364  Disconnect;
    386   Schema := TempDatabase;
     365  Database := TempDatabase;
    387366end;
    388367
    389368procedure TSqlDatabase.CreateTable(Name: string);
    390 begin
    391   Query('CREATE TABLE `' + Name + '`' +
    392   ' (`Id` INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (`Id`));');
     369var
     370  DbRows: TDbRows;
     371begin
     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;
    393379end;
    394380
     
    398384  ColTypes: array[0..17] of string = ('', 'INT', 'CHAR', 'INT', 'DOUBLE',
    399385  'VARCHAR(255)', 'SET', 'INT', '', '', 'TEXT', 'TEXT', '', '', '', '', '', '');
    400 begin
    401   Query('ALTER TABLE `' + Table + '` ADD `' + ColumnName + '` ' +
    402     ColTypes[Integer(ColumnType)] + ' NOT NULL');
     386var
     387  DbRows: TDbRows;
     388begin
     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;
    403396end;
    404397
     
    413406end;
    414407
    415 procedure TSqlDatabase.SetSchema(const Value: string);
     408procedure TSqlDatabase.SetDatabase(const Value: string);
    416409begin
    417410  FDatabase := Value;
     
    419412end;
    420413
     414{ TDbRows }
     415
     416destructor TDbRows.Destroy;
     417begin
     418  inherited;
     419end;
     420
     421function TDbRows.GetData(Index: Integer): TDictionaryStringString;
     422begin
     423  Result := TDictionaryStringString(Items[Index]);
     424end;
     425
     426procedure TDbRows.SetData(Index: Integer; const Value: TDictionaryStringString);
     427begin
     428  Items[Index] := Value;
     429end;
     430
    421431end.
    422432
Note: See TracChangeset for help on using the changeset viewer.