ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBDatabaseInfo.pas
(Generate patch)

Comparing ibx/trunk/runtime/IBDatabaseInfo.pas (file contents):
Revision 33 by tony, Sat Jul 18 12:30:52 2015 UTC vs.
Revision 143 by tony, Fri Feb 23 12:11:21 2018 UTC

# Line 25 | Line 25
25   {    IBX For Lazarus (Firebird Express)                                  }
26   {    Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
27   {    Portions created by MWA Software are copyright McCallum Whyman      }
28 < {    Associates Ltd 2011                                                 }
28 > {    Associates Ltd 2011 - 2018                                               }
29   {                                                                        }
30   {************************************************************************}
31  
# Line 36 | Line 36 | unit IBDatabaseInfo;
36   interface
37  
38   uses
39 <  SysUtils, Classes, IBHeader, IBExternals, IB, IBDatabase;
39 >  SysUtils, Classes, IB, IBExternals, IBDatabase;
40  
41   type
42  
43 +  { TIBDatabaseInfo }
44 +
45    TIBDatabaseInfo = class(TComponent)
46 +  private
47 +    function GetDateDBCreated: TDateTime;
48 +    function GetEncrypted: boolean;
49 +    function GetEncryptionKeyName: string;
50 +    function GetPagesFree: Long;
51 +    function GetPagesUsed: Long;
52 +    function GetTransactionCount: Long;
53    protected
45    FIBLoaded: Boolean;
54      FDatabase: TIBDatabase;
55      FUserNames   : TStringList;
56      FBackoutCount: TStringList;
# Line 53 | Line 61 | type
61      FReadIdxCount: TStringList;
62      FReadSeqCount: TStringList;
63      FUpdateCount: TStringList;
64 +    procedure CheckDatabase;
65      function GetAllocation: Long;
66      function GetBaseLevel: Long;
67      function GetDBFileName: String;
# Line 82 | Line 91 | type
91      function GetReadIdxCount: TStringList;
92      function GetReadSeqCount: TStringList;
93      function GetUpdateCount: TStringList;
94 <    function GetOperationCounts(DBInfoCommand: Integer; FOperation: TStringList): TStringList;
94 >    function GetOperationCounts(DBInfoCommand: Integer; var FOperation: TStringList): TStringList;
95      function GetReadOnly: Long;
96      function GetStringDatabaseInfo(DatabaseInfoCommand: Integer): String;
97      function GetDBSQLDialect: Long;
98    public
99      constructor Create(AOwner: TComponent); override;
100      destructor Destroy; override;
92    function Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
101      function GetLongDatabaseInfo(DatabaseInfoCommand: Integer): Long;
102 +    function GetDatabasePage(PageNo: integer): string;
103      property Allocation: Long read GetAllocation;
104      property BaseLevel: Long read GetBaseLevel;
105 +    property DateDBCreated: TDateTime read GetDateDBCreated;
106      property DBFileName: String read GetDBFileName;
107      property DBSiteName: String read GetDBSiteName;
108      property DBImplementationNo: Long read GetDBImplementationNo;
109      property DBImplementationClass: Long read GetDBImplementationClass;
110 +    property Encrypted: boolean read GetEncrypted;
111 +    property EncryptionKeyName: string read GetEncryptionKeyName;
112      property NoReserve: Long read GetNoReserve;
113      property ODSMinorVersion: Long read GetODSMinorVersion;
114      property ODSMajorVersion: Long read GetODSMajorVersion;
# Line 112 | Line 124 | type
124      property Marks: Long read GetMarks;
125      property Reads: Long read GetReads;
126      property Writes: Long read GetWrites;
127 +    property TransactionCount: Long read GetTransactionCount;
128      property BackoutCount: TStringList read GetBackoutCount;
129      property DeleteCount: TStringList read GetDeleteCount;
130      property ExpungeCount: TStringList read GetExpungeCount;
# Line 121 | Line 134 | type
134      property ReadSeqCount: TStringList read GetReadSeqCount;
135      property UpdateCount: TStringList read GetUpdateCount;
136      property DBSQLDialect : Long read GetDBSQLDialect;
137 +    property PagesUsed: Long read GetPagesUsed;
138 +    property PagesFree: Long read GetPagesFree;
139      property ReadOnly: Long read GetReadOnly;
140    published
141      property Database: TIBDatabase read FDatabase write FDatabase;
# Line 129 | Line 144 | type
144   implementation
145  
146   uses
147 <  IBIntf;
147 >  FBMessages;
148  
149   { TIBDatabaseInfo }
150  
151   constructor TIBDatabaseInfo.Create(AOwner: TComponent);
152   begin
153    inherited Create(AOwner);
139  FIBLoaded := False;
140  CheckIBLoaded;
141  FIBLoaded := True;
154    FUserNames := TStringList.Create;
155    FBackoutCount                        := nil;
156    FDeleteCount                         := nil;
# Line 152 | Line 164 | end;
164  
165   destructor TIBDatabaseInfo.Destroy;
166   begin
167 <  if FIBLoaded then
168 <  begin
169 <    FUserNames.Free;
170 <    FBackoutCount.Free;
171 <    FDeleteCount.Free;
172 <    FExpungeCount.Free;
173 <    FInsertCount.Free;
174 <    FPurgeCount.Free;
175 <    FReadIdxCount.Free;
164 <    FReadSeqCount.Free;
165 <    FUpdateCount.Free;
166 <  end;
167 >  if assigned(FUserNames) then FUserNames.Free;
168 >  if assigned(FBackoutCount) then FBackoutCount.Free;
169 >  if assigned(FDeleteCount) then FDeleteCount.Free;
170 >  if assigned(FExpungeCount) then FExpungeCount.Free;
171 >  if assigned(FInsertCount) then FInsertCount.Free;
172 >  if assigned(FPurgeCount) then FPurgeCount.Free;
173 >  if assigned(FReadIdxCount) then FReadIdxCount.Free;
174 >  if assigned(FReadSeqCount) then FReadSeqCount.Free;
175 >  if assigned(FUpdateCount) then FUpdateCount.Free;
176    inherited Destroy;
177   end;
178  
179 + function TIBDatabaseInfo.GetDateDBCreated: TDateTime;
180 + begin
181 +  CheckDatabase;
182 +  with Database.Attachment.GetDBInformation([isc_info_creation_date]) do
183 +    if (Count > 0) and (Items[0].GetItemType = isc_info_creation_date) then
184 +      Result := Items[0].GetAsDateTime
185 +    else
186 +      IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
187 + end;
188 +
189 + function TIBDatabaseInfo.GetEncrypted: boolean;
190 + var ConnFlags: Long;
191 + begin
192 +  Result := ODSMajorVersion >= 12;
193 +  if Result then
194 +  try
195 +    ConnFlags := GetLongDatabaseInfo(fb_info_conn_flags);
196 +    Result := (ConnFlags and fb_info_crypt_encrypted) <> 0;
197 +  except
198 +    Result := false; {Introduced in Firebird 3.0.3}
199 +  end;
200 + end;
201 +
202 + function TIBDatabaseInfo.GetEncryptionKeyName: string;
203 + begin
204 +  CheckDatabase;
205 +  {Introduced in Firebird 3.0.3}
206 +  with Database.Attachment.GetDBInformation([fb_info_crypt_key]) do
207 +    if (Count > 0) and (Items[0].GetItemType = fb_info_crypt_key) then
208 +      Result := Items[0].AsString
209 +    else
210 +     IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
211 + end;
212 +
213 + function TIBDatabaseInfo.GetPagesFree: Long;
214 + begin
215 +  result := GetLongDatabaseInfo(fb_info_pages_used);
216 + end;
217 +
218 + function TIBDatabaseInfo.GetPagesUsed: Long;
219 + begin
220 +  result := GetLongDatabaseInfo(fb_info_pages_free);
221 + end;
222 +
223 + function TIBDatabaseInfo.GetTransactionCount: Long;
224 + begin
225 +  result := GetLongDatabaseInfo(isc_info_active_tran_count);
226 + end;
227  
228 < function TIBDatabaseInfo.Call(ErrCode: ISC_STATUS;
172 <  RaiseError: Boolean): ISC_STATUS;
228 > procedure TIBDatabaseInfo.CheckDatabase;
229   begin
230 <  result := ErrCode;
231 <  if RaiseError and (ErrCode > 0) then
232 <    IBDataBaseError;
230 >  if Database = nil then
231 >    IBError(ibxeDatabaseNotAssigned,[]);
232 >  if Database.Attachment = nil then
233 >    IBError(ibxeDatabaseClosed,[]);
234   end;
235 +
236   function TIBDatabaseInfo.GetAllocation: Long;
237   begin
238    result := GetLongDatabaseInfo(isc_info_allocation);
239   end;
240  
241   function TIBDatabaseInfo.GetBaseLevel: Long;
242 < var
185 <  local_buffer: array[0..IBLocalBufferLength - 1] of Char;
186 <  DatabaseInfoCommand: Char;
242 > var Response: TByteArray;
243   begin
244 <  DatabaseInfoCommand := Char(isc_info_base_level);
245 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @DatabaseInfoCommand,
246 <                         IBLocalBufferLength, local_buffer), True);
247 <  result := isc_vax_integer(@local_buffer[4], 1);
244 >  CheckDatabase;
245 >  with Database.Attachment.GetDBInformation([isc_info_base_level]) do
246 >    if (Count > 0) and (Items[0].GetItemType = isc_info_base_level) then
247 >    begin
248 >      Response := Items[0].GetAsBytes;
249 >      Result := Response[1];
250 >    end
251 >  else
252 >     IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
253   end;
254  
255   function TIBDatabaseInfo.GetDBFileName: String;
256   var
257 <  local_buffer: array[0..IBLocalBufferLength - 1] of Char;
258 <  DatabaseInfoCommand: Char;
257 >  ConnectionType: integer;
258 >  SiteName: string;
259   begin
260 <  DatabaseInfoCommand := Char(isc_info_db_id);
261 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @DatabaseInfoCommand,
262 <                         IBLocalBufferLength, local_buffer), True);
263 <  local_buffer[5 + Int(local_buffer[4])] := #0;
264 <  result := String(PChar(@local_buffer[5]));
260 >  CheckDatabase;
261 >  with Database.Attachment.GetDBInformation([isc_info_db_id]) do
262 >    if (Count > 0) and (Items[0].GetItemType = isc_info_db_id) then
263 >      Items[0].DecodeIDCluster(ConnectionType,Result,SiteName)
264 >    else
265 >       IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
266   end;
267  
268   function TIBDatabaseInfo.GetDBSiteName: String;
269   var
270 <  local_buffer: array[0..IBBigLocalBufferLength - 1] of Char;
271 <  p: PChar;
272 <  DatabaseInfoCommand: Char;
273 < begin
274 <  DatabaseInfoCommand := Char(isc_info_db_id);
275 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @DatabaseInfoCommand,
276 <                        IBLocalBufferLength, local_buffer), True);
277 <  p := @local_buffer[5 + Int(local_buffer[4])]; { DBSiteName Length }
278 <  p := p + Int(p^) + 1;                         { End of DBSiteName }
217 <  p^ := #0;                                     { Null it }
218 <  result := String(PChar(@local_buffer[6 + Int(local_buffer[4])]));
270 >  ConnectionType: integer;
271 >  FileName: string;
272 > begin
273 >  CheckDatabase;
274 >  with Database.Attachment.GetDBInformation([isc_info_db_id]) do
275 >    if (Count > 0) and (Items[0].GetItemType = isc_info_db_id) then
276 >      Items[0].DecodeIDCluster(ConnectionType,FileName,Result)
277 >    else
278 >       IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
279   end;
280  
281   function TIBDatabaseInfo.GetDBImplementationNo: Long;
282 < var
223 <  local_buffer: array[0..IBLocalBufferLength - 1] of Char;
224 <  DatabaseInfoCommand: Char;
282 > var Response: TByteArray;
283   begin
284 <  DatabaseInfoCommand := Char(isc_info_implementation);
285 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @DatabaseInfoCommand,
286 <                        IBLocalBufferLength, local_buffer), True);
287 <  result := isc_vax_integer(@local_buffer[3], 1);
284 >  CheckDatabase;
285 >  with Database.Attachment.GetDBInformation([isc_info_implementation]) do
286 >    if (Count > 0) and (Items[0].GetItemType = isc_info_implementation) then
287 >    begin
288 >      Response := Items[0].GetAsBytes;
289 >      Result := Response[1];
290 >    end
291 >  else
292 >     IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
293   end;
294  
295   function TIBDatabaseInfo.GetDBImplementationClass: Long;
296 < var
234 <  local_buffer: array[0..IBLocalBufferLength - 1] of Char;
235 <  DatabaseInfoCommand: Char;
296 > var Response: TByteArray;
297   begin
298 <  DatabaseInfoCommand := Char(isc_info_implementation);
299 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @DatabaseInfoCommand,
300 <                         IBLocalBufferLength, local_buffer), True);
301 <  result := isc_vax_integer(@local_buffer[4], 1);
298 >  CheckDatabase;
299 >  with Database.Attachment.GetDBInformation([isc_info_implementation]) do
300 >    if (Count > 0) and (Items[0].GetItemType = isc_info_implementation) then
301 >    begin
302 >      Response := Items[0].GetAsBytes;
303 >      Result := Response[2];
304 >    end
305 >  else
306 >     IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
307   end;
308  
309   function TIBDatabaseInfo.GetNoReserve: Long;
# Line 247 | Line 313 | end;
313  
314   function TIBDatabaseInfo.GetODSMinorVersion: Long;
315   begin
316 <  result := GetLongDatabaseInfo(isc_info_ods_minor_version);
316 >  CheckDatabase;
317 >  Result := Database.Attachment.GetODSMinorVersion;
318   end;
319  
320   function TIBDatabaseInfo.GetODSMajorVersion: Long;
321   begin
322 <  result := GetLongDatabaseInfo(isc_info_ods_version);
322 >  CheckDatabase;
323 >  Result := Database.Attachment.GetODSMajorVersion;
324   end;
325  
326   function TIBDatabaseInfo.GetPageSize: Long;
# Line 261 | Line 329 | begin
329   end;
330  
331   function TIBDatabaseInfo.GetVersion: String;
332 < var
265 <  local_buffer: array[0..IBBigLocalBufferLength - 1] of Char;
266 <  DatabaseInfoCommand: Char;
332 > var Version: byte;
333   begin
334 <  DatabaseInfoCommand := Char(isc_info_version);
335 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @DatabaseInfoCommand,
336 <                        IBBigLocalBufferLength, local_buffer), True);
337 <  local_buffer[5 + Int(local_buffer[4])] := #0;
338 <  result := String(PChar(@local_buffer[5]));
334 >  CheckDatabase;
335 >  with Database.Attachment.GetDBInformation([isc_info_version]) do
336 >    if (Count > 0) and (Items[0].GetItemType = isc_info_version) then
337 >      Items[0].DecodeVersionString(Version,Result)
338 >  else
339 >     IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
340   end;
341  
342   function TIBDatabaseInfo.GetCurrentMemory: Long;
# Line 298 | Line 365 | begin
365   end;
366  
367   function TIBDatabaseInfo.GetUserNames: TStringList;
368 < var
369 <  local_buffer: array[0..IBHugeLocalBufferLength - 1] of Char;
370 <  temp_buffer: array[0..IBLocalBufferLength - 2] of Char;
304 <  DatabaseInfoCommand: Char;
305 <  i, user_length: Integer;
306 < begin
307 <  result := FUserNames;
308 <  DatabaseInfoCommand := Char(isc_info_user_names);
309 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @DatabaseInfoCommand,
310 <                        IBHugeLocalBufferLength, local_buffer), True);
368 > begin
369 >  CheckDatabase;
370 >  Result := FUserNames;
371    FUserNames.Clear;
372 <  i := 0;
373 <  while local_buffer[i] = Char(isc_info_user_names) do
374 <  begin
375 <    Inc(i, 3); { skip "isc_info_user_names byte" & two unknown bytes of structure (see below) }
376 <    user_length := Long(local_buffer[i]);
317 <    Inc(i,1);
318 <    Move(local_buffer[i], temp_buffer[0], user_length);
319 <    Inc(i, user_length);
320 <    temp_buffer[user_length] := #0;
321 <    FUserNames.Add(String(temp_buffer));
322 <  end;
372 >  with Database.Attachment.GetDBInformation([isc_info_user_names]) do
373 >    if (Count > 0) and (Items[0].GetItemType = isc_info_user_names) then
374 >      Items[0].DecodeUserNames(Result)
375 >  else
376 >     IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
377   end;
378  
379   function TIBDatabaseInfo.GetFetches: Long;
# Line 342 | Line 396 | begin
396    result := GetLongDatabaseInfo(isc_info_writes);
397   end;
398  
399 < function TIBDatabaseInfo.GetOperationCounts(DBInfoCommand: Integer; FOperation: TStringList): TStringList;
400 < var
401 <  local_buffer: array[0..IBHugeLocalBufferLength - 1] of Char;
402 <  DatabaseInfoCommand: Char;
349 <  i, qtd_tables, id_table, qtd_operations: Integer;
399 > function TIBDatabaseInfo.GetOperationCounts(DBInfoCommand: Integer;
400 >  var FOperation: TStringList): TStringList;
401 > var opCounts: TDBOperationCounts;
402 >    i: integer;
403   begin
404 +  CheckDatabase;
405    if FOperation = nil then FOperation := TStringList.Create;
406    result := FOperation;
407 <  DatabaseInfoCommand := Char(DBInfoCommand);
408 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @DatabaseInfoCommand,
409 <                         IBHugeLocalBufferLength, local_buffer), True);
410 <  FOperation.Clear;
411 <  { 1. 1 byte specifying the item type requested (e.g., isc_info_insert_count).
412 <    2. 2 bytes telling how many bytes compose the subsequent value pairs.
413 <    3. A pair of values for each table in the database on wich the requested
360 <      type of operation has occurred since the database was last attached.
361 <    Each pair consists of:
362 <    1. 2 bytes specifying the table ID.
363 <    2. 4 bytes listing the number of operations (e.g., inserts) done on that table.
364 <  }
365 <  qtd_tables := trunc(isc_vax_integer(@local_buffer[1],2)/6);
366 <  for i := 0 to qtd_tables - 1 do
367 <  begin
368 <    id_table := isc_vax_integer(@local_buffer[3+(i*6)],2);
369 <    qtd_operations := isc_vax_integer(@local_buffer[5+(i*6)],4);
370 <    FOperation.Add(IntToStr(id_table)+'='+IntToStr(qtd_operations));
371 <  end;
407 >  with Database.Attachment.GetDBInformation([DBInfoCommand]) do
408 >    if (Count > 0) and (Items[0].GetItemType = DBInfoCommand) then
409 >      opCounts := Items[0].getOperationCounts
410 >  else
411 >     IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
412 >  for i := 0 to Length(opCounts) - 1 do
413 >    FOperation.Add(IntToStr(opCounts[i].TableID) +'='+IntToStr(opCounts[i].Count));
414   end;
415  
416   function TIBDatabaseInfo.GetBackoutCount: TStringList;
# Line 417 | Line 459 | begin
459   end;
460  
461   function TIBDatabaseInfo.GetLongDatabaseInfo(DatabaseInfoCommand: Integer): Long;
462 < var
463 <  local_buffer: array[0..IBLocalBufferLength - 1] of Char;
464 <  length: Integer;
465 <  _DatabaseInfoCommand: Char;
466 < begin
467 <  _DatabaseInfoCommand := Char(DatabaseInfoCommand);
468 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @_DatabaseInfoCommand,
469 <                         IBLocalBufferLength, local_buffer), True);
470 <  length := isc_vax_integer(@local_buffer[1], 2);
471 <  result := isc_vax_integer(@local_buffer[3], length);
462 > begin
463 >  CheckDatabase;
464 >  with Database.Attachment.GetDBInformation([DatabaseInfoCommand]) do
465 >    if (Count > 0) and (Items[0].GetItemType = DatabaseInfoCommand) then
466 >      Result := Items[0].AsInteger
467 >    else
468 >      IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
469 > end;
470 >
471 > function TIBDatabaseInfo.GetDatabasePage(PageNo: integer): string;
472 > var DBRequest: IDIRB;
473 > begin
474 >  DBRequest := Database.Attachment.AllocateDIRB;
475 >  DBRequest.Add(fb_info_page_contents).AsInteger := PageNo;
476 >  with Database.Attachment.GetDBInformation(DBRequest) do
477 >    if (Count > 0) and (Items[0].GetItemType = fb_info_page_contents) then
478 >      Result := Items[0].AsString
479 >    else
480 >      IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
481   end;
482  
483   function TIBDatabaseInfo.GetStringDatabaseInfo(DatabaseInfoCommand: Integer): String;
433 var
434  local_buffer: array[0..IBBigLocalBufferLength - 1] of Char;
435  _DatabaseInfoCommand: Char;
484   begin
485 <  _DatabaseInfoCommand := Char(DatabaseInfoCommand);
486 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @_DatabaseInfoCommand,
487 <                         IBBigLocalBufferLength, local_buffer), True);
488 <  local_buffer[4 + Int(local_buffer[3])] := #0;
489 <  result := String(PChar(@local_buffer[4]));
485 >  CheckDatabase;
486 >  with Database.Attachment.GetDBInformation([DatabaseInfoCommand]) do
487 >    if (Count > 0) and (Items[0].GetItemType = DatabaseInfoCommand) then
488 >      Result := Items[0].AsString
489 >    else
490 >      IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
491   end;
492  
493  
494 < function TIBDatabaseInfo.GetDBSQLDialect: Integer;
495 < var
496 <  local_buffer: array[0..IBLocalBufferLength - 1] of Char;
497 <  length: Integer;
498 <  DatabaseInfoCommand: Char;
499 < begin
500 <  DatabaseInfoCommand := Char(isc_info_db_SQL_Dialect);
501 <  Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @DatabaseInfoCommand,
453 <                       IBLocalBufferLength, local_buffer), True);
454 <  if (local_buffer[0] <> Char(isc_info_db_SQL_dialect)) then
455 <    result := 1
456 <  else begin
457 <    length := isc_vax_integer(@local_buffer[1], 2);
458 <    result := isc_vax_integer(@local_buffer[3], length);
459 <  end;
494 > function TIBDatabaseInfo.GetDBSQLDialect: Long;
495 > begin
496 >  CheckDatabase;
497 >  with Database.Attachment.GetDBInformation([isc_info_db_SQL_Dialect]) do
498 >    if (Count > 0) and (Items[0].GetItemType = isc_info_db_SQL_Dialect) then
499 >      Result := Items[0].AsInteger
500 >    else
501 >      Result := 1;
502   end;
503  
504  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines