Fibplus Developer'S Guide: Database Connection
Fibplus Developer'S Guide: Database Connection
Part I
Database connection
To connect to a database (DB) you should use the TpFIBDatabase component. For more
details about its properties and methods read FIBPlus help file.
Connection parameters
Connection parameters are typical for InterBase/Firebird server:
• path to a database file;
• user name and password;
• user role;
• charset;
• dialect;
• client library (gds32.dll for InterBase and fbclient.dll for Firebird).
To set all the properties at once you can use a built-in connection setting dialog (see picture
1).
The dialog «Database Editor» can be invoked from the component context menu (right click
on the component) at design-time.
Here you may set all necessary parameters, including getting them from/saving them to Alias.
You may also check whether the parameters are correct by using a test connection.
Similar to the actions in the dialog, you can do the same in the application code.
To connect to a database you should call the Open method or set the Connected property to
True. It’s also possible to use this code to connect to a database:
function Login(DataBase: TpFIBDatabase; dbpath, uname, upass, urole: string):
Boolean;
begin
if DataBase.Connected then DataBase.Connected := False;
with FDataBase.ConnectParams do begin
UserName := uname;
Password := upass;
RoleName := urole;
end;
DataBase.DBName := dbpath;
try DataBase.Connected := True;
except
on e: Exception do
ShowMessage(e.Message);
end;
Result := DataBase.Connected;
end;
To close the connection either call the Close method or set the Connected property to False.
You can also close all datasets and connected transactions at once:
procedure Logout(DataBase: TpFIBDatabase);
var i: Integer;
begin
if not DataBase.Connected then
Exit;
for i := 0 to DataBase.TransactionCount - 1 do
if TpFIBTransaction(DataBase.Transactions[i]).InTransaction then
TpFIBTransaction(DataBase.Transactions[i]).Rollback
DataBase.CloseDataSets;
DataBase.Close;
end;
How to create and drop database
It’s very easy to create a new DB. You need to set DB parameters and call the CreateDatabase
method:
Delphi
with Database1 do begin
DBParams.Clear;
DBParams.Add('USER ''SYSDBA'' PASSWORD ''masterkey''');
DBParams.Add('PAGE_SIZE = 2048');
DBParams.Add('DEFAULT CHARACTER SET WIN1251');
DBName := 'SERV_DB:C:\DB\TEST.IB';
SQLDialect := 3;
end;
try
Database1.CreateDataBase;
except
// Error handling
end;
C++
Database1->DBParams->Clear();
Database1->DBParams->Add("USER 'SYSDBA' PASSWORD 'masterkey'");
Database1->DBParams->Add("PAGE_SIZE = 2048");
Database1->DBParams->Add("DEFAULT CHARACTER SET WIN1251");
Database1->DBName = "SERV_DB:C:\\DB\\TEST.GDB";
Database1->SQLDialect = 3;
try
{ Database1->CreateDatabase(); }
catch (...)
{ // Error
}
To drop a database, use the DropDatabase method. Note: you should be connected to the
database when using this method.
Metadata caching
FIBPlus enables developers to get system information about field tables automatically, set in
TpFIBDataSet such field properties as Required (for NOT NULL fields), ReadOnly (for
calculated fields) and DefaultExpression (for fields with default database values). This feature is
very useful for both programmers and users, because programmers do not need to set property
values manually when writing client applications, and users get clearer messages when working
with the programme e.g. if any field is NOT NULL, and the user attempts to leave it empty, he
will see a message «Field ‘…’ must have a value.». This is more understandable than a system
InterBase/Firebird PRIMARY KEY violation error. The same with calculated fields, it is not
possible to edit such fields, so FIBPlus will set the ReadOnly property to True for all calculated
fields, and the user will not get a vague message on trying to change the field values in
TDBGrid.
This feature has one disadvantage, which is revealed on low speed connections. To get
information on fields, FIBPlus components execute additional “internal queries” on
InterBase/Firebird system tables. If there are many tables in the application, or many fields in
these tables, the application work can slow down anв net traffic increase. This becomes
especially obvious on first query opening, as every open query is followed by the internal
queires. On subsequent opening of the query, FIBPlus uses the information, which has already
been obtained, but users may notice a slight work slowdown when the application starts.
This is where Metadata caching comes in. TpFIBDatabase enables developers to save
metadata information at the client machine and use it during the applications execution and
subsequent executions. The TCacheSchemaOptions.property is responsible for this process:
TCacheSchemaOptions = class(TPersistent)
property LocalCacheFile: string;
property AutoSaveToFile: Boolean .. default False;
property AutoLoadFromFile: Boolean .. default False;
property ValidateAfterLoad: Boolean .. default True;
end;
The LocalCacheFile property sets the name of the local cache file where this information will
be saved. AutoSaveToFile helps to save cache to the file automatically on closing the
application. AutoLoadFromFile loads cache from the file. And ValidateAfterLoad defines
whether it’s necessary to check the saved cache after its loading. Besides there is an
OnAcceptCacheSchemа event, where you may define objects, for which you don’t need to load
the saved information.
This property is also very easy-to-use.
with pFIBDatabase1.CacheSchemaOptions do begin
LocalCacheFile := 'fibplus.cache';
AutoSaveToFile := True;
AutoLoadFromFile := True;
ValidateAfterLoad:= True;
end;
where
TBeforeSaveBlobToSwap = procedure(const TableName, FieldName: string;
RecordKeyValues: array of variant; Stream: TStream; var FileName: string; var
CanSave: boolean) of object;
TAfterSaveLoadBlobSwap = procedure(const TableName, FieldName: string;
RecordKeyValues: array of variant; const FileName: string) of object;
TBeforeLoadBlobFromSwap = procedure(const TableName, FieldName: string;
RecordKeyValues: array of variant; var FileName: string; var CanLoad:
boolean) of object;
You do not need to worry about these event handlers unless you want more control over how
the BLOB field cache works. Event handlers help to manage BLOB field saving and reading
from the disc. In particular you can forbid saving some BLOB field in event handlers depending
on the field name and the table name, on other field values, free disc space, etc.
You can also save BLOB fields by using the MinBlobSizeToSwap property. There you can
set a minimal BLOB field size for saving at disk..
This technology has a number of limitations:
1. The table must have a primary key.
2. BLOB fields must be read by the TpFIBDataSet component.
3. Your application must monitor the free disk space. For these purposes you can use the
even handler BeforeSaveBlobToSwap.
4. Unfortunately all BLOB_ID’s are changed after database backup/restore, so local cache
becomes useless and is automatically cleared. After each application connection to the
database, FIBPlus automatically opens a special thread, which checks in a separate
connection the whole disk cache on BLOB fields. If there are no BLOB fields, the
corresponding files are immediately deleted.
Now we need to register the two methods before connecting to a database. Call the
RegisterBlobFilter function. The first parameter value is BLOB field type (equals to –15), the
second and third are packing and unpacking functions:
pFIBDatabase1.RegisterBlobFilter(-15, @PackBuffer, @UnpackBuffer);
You can also see the demo example BlobFilters for more details.
The first method gets all table names and fills the TableNames list. The WithSystem
parameter indicates whether to show system table names.
The second method takes TableName and fills FieldNames with the field names. The
WithComputedFields parameter indicates whether to include COMPUTED BY fields.
Working with transactions
A transaction is an operation of database transfer from one consistent state to another.
All operations with the dataset (data/metadata changes) are done in the context of a
transaction. To understand special FIBPlus features completely you need to know about
InterBase / FIBPlus transactions. Please read the topic «Working with Transaction» in
ApiGuide.pdf for InterBase.
All the changes done in the transaction can be either committed (in case there are no errors) by
Commit or rolled back (Rollback). Besides these basic methods TpFIBTransaction has their
context saving analogues: CommitRetaining and RollbackRetaining, i.e. on the client side, these
will not close a TpFibQuery or TpFibDataset.
To start the transaction you should call the StartTransaction method or set the Active property
to True. To commit the transaction call Commit/CommitRetaing, to roll it back -
Rollback/RollbackRetaining.
TpFIBQuery and TpFIBDataSet components have some properties which help to control
transactions automatically. In particular they are: the TpFIBDataSet.AutoCommit property; the
poStartTransaction parameter in TpFIBDataSet.Options; qoStartTransaction and
qoCommitTransaction in TpFIBQuery.Options.
The first method sets a save point with the SavePointName name. The second rolls the
transaction back to SavePointName. The third releases SavePointName server resources.
SQL-query execution
An application works with a database by issuing SQL instructions. They are used to get and
modify data\metadata. FIBPlus has a special TpFIBQuery component responsible for SQL
operator execution. This robust, light and powerful component can perform any actions with the
database.
TpFIBQuery is very easy-to-use: just set the TpFIBDatabase component, fill in the SQL
property and call any ExecQuery method (ExecQueryWP, ExecQueryWPS).
NOTE: The tpFIBQuery is not a TDataset descendant, so it does not act in exactly the same
way or exhibit the same methods / properties as you would expect to find in a dataset. For the
TDataset descendant, please refer to the TpFIBDataset.
The example below will show how to create TpFIBQuery dynamically at run-time and thus get
data about clients.
var sql: TpFIBQuery;
sql := TpFIBQuery.Create(nil);
with sql do
try
Database := db;
Transaction := db.DefaultTransaction;
SQL.Text := 'select first_name, last_name from customer';
ExecQuery;
while not Eof do begin
Memo1.Lines.Add(
FldByName['FIRST_NAME'].AsString+' '+
FldByName['LASTST_NAME'].AsString);
Next;
end;
sql.Close;
finally
sql.Free;
end;
{ variant 1 }
sql.ParamByName('first_name').AsString := 'A';
sql.ExecQuery;
{ variant 2 }
sql.ExecWP('first_name', ['A']);
{ variant 3 }
sql.ExecWP(['A']);
SQL- sections
FIBPlus provides developers with a wide range of SQL query control capabilities. In particular
they are SQL sections: a list of fields, conditions, grouping and sorting order, query execution
plan. Effectively FIBPlus parses your SQL and identifies the following elements of an SQL
statement. These simple string properties can be read and modified:
FieldsClause – has a field list;
MainWhereClause – has the main clause WHERE (see the details below);
OrderClause – has the clause «order by»;
GroupByClause – has the clause «group by»;
PlanClause – has the clause «plan».
FIBPlus also has unique features, such as macros and conditions – an extended mechanism of
work with the WHERE clause. The sections below will provide you with more details about
these features.
Macros
Macros help you to operate with the variable parts of your queries. This allows you to change
and specify the queries without rewriting the query code.
The macro syntax is @@<MACROS_NAME>[%<DEFAULT_VALUE>][#]@
So macro is a specific order of symbols between the marks @@ and @. The parameter
<MACROS_NAME> is obligatory after @@. You can also set the default macro value after the
symbol “%”. Besides you can set the parameter # (not obligatory), it will make FIBPlus write
parameter names in inverted commas.
Macros are used similar to parameters. This code example will demonstrate you this similarity:
Sql.SQL.Text := 'select * from @@table_clause@ where @@where_clause% 1=1@';
Sql.ExecWP(['CUSTOMER','FIRST_NAME STARTING WITH ''A''']);
Call the SetDefaultMacroValue method of the object parameter to set the default macro value.
Macro can also have a parameter. To search for it use the FindParam function, to set the
parameter use the ParamByName method:
Sql.SQL.Text := 'select * from @@table_clause@ where @@where_clause% 1=1@';
Sql.Params[0].AsString := 'CUSTOMER';
Sql.Params[1].AsString := 'CUST_NO = :CUST_NO';
if Assigned(Sql.FindParam('CUST_NO')) then
Sql.ParamByName('CUST_NO').AsInteger := 1001;
Sql.ExecQuery;
You can also see the code example ServerFilterMarcoses to get to know how to use macros for
TpFIBDataSet
Conditions
The mechanism of conditions is another option to change the variable part of your SQL-
queries
You can set one or more parameter conditions for any SQL at design time or runtime. The
built-in dialog shown in picture 3 is very convenient for these purposes.
To make the condition active you should set the Active property to True.
pFIBQuery1.Conditions[0].Active := True;
or
pFIBQuery1.Conditions.ByName('by_customer').Active := True;
This is a sample code showing how to work with Conditions:
if pFIBQuery1.Open then pFIBQuery1.Close;
pFIBQuery1.Conditions.CancelApply;
pFIBQuery1.Conditions.Clear;
if byCustomerFlag then
pFIBQuery1.Conditions.AddCondition('by_customer', 'cust_no = 1001',
True);
pFIBQuery1.Conditons.Apply;
pFIBQuery1.Open;
TpFIBDataSet has two additional methods CancelConditions and ApplyConditions, which call
correspondingly Conditions.Cancel and Conditions.Apply. This code sample for TpFIBDataSet
is simpler than the previous.
with pFIBDataSet1 do begin
if Active then Close;
CancelConditioins;
Conditions.Clear;
if byCustomerFlag then Conditions.AddCondition('by_customer', 'cust_no =
1001', True);
ApplyConditions;
Open;
end;
You can also see the example ServerFilterConditions to get to know how to set conditions for
TpFIBDataSet.
Batch processing
FIBPlus has internal methods for batch processing, called Batch methods. These methods can
be helpful for replication between databases and import/export operations.
function BatchInput(InputObject: TFIBBatchInputStream) :boolean;
function BatchOutput(OutputObject: TFIBBatchOutputStream):boolean;
procedure BatchInputRawFile(const FileName:string);
procedure BatchOutputRawFile(const FileName:string;Version:integer=1);
procedure BatchToQuery(ToQuery:TFIBQuery; Mappings:TStrings);
The Version parameter is responsible for format compatibility with old file versions, created
by FIBPlus BatchOutputXXX method. If Version = 1, FIBPlus uses an old principle of work
with file versions: the external file keeps data ordered by SQL query fields. It is supposed that on
reading data saved by the BatchInputRawFile method, parameters will have the same order in the
reading SQL. The number of TpFIBQuery fields (the source of the data) must coincide to the
number of TpFIBQuery parameters which will read the data. For string fields it is important to
have the same length for the field being written and for the reading parameter whereas their
names can differ.
If Version = 2, FIBPlus uses a new principle of writing data. Besides the data, the file also
keeps system information about fields (name, type and length). On reading the data, it will be
chosen by similar names. The order and number of fields in the writing TpFIBQuery can differ
from those of parameters in the reading TpFIBQuery. Their types and length can also differ.
Only names must coincide.
It’s very easy to work with batch methods. We will show this using a simple example. The
code below consists of three parts. The first saves data about clients into an external file, the
second loads them into a database and the third shows how to change the data.
{ I }
pFIBQuery1.SQL := 'select EMP_NO, FIRST_NAME, LAST_NAME from CUSOMER';
pFIBQuery1.BatchOutputRawFile('employee_buffer.fibplus', 1);
{ II }
pFIBQuery1.SQL := 'insert into employees(EMP_NO, FIRST_NAME, LAST_NAME)'+
' values(:EMP_NO, :FIRST_NAME, :LAST_NAME)';
pFIBQuery1.BatchInputRawFile('employee_buffer.fibplus');
{ III }
pFIBQuery1.SQL := 'select EMP_NO, FIRST_NAME, LAST_NAME from CUSOMER';
pFIBQuery2.SQL := 'insert into tmp_employees(EMP_NO, FIRST_NAME, LAST_NAME)'+
' values(:EMP_NO, :FIRST_NAME, :LAST_NAME)';
mapStrings.Add('EMP_NO=EMP_NO');
mapStrings.Add('FIRST_NAME=FIRST_NAME');
mapStrings.Add('LAST_NAME=LAST_NAME');
pFIBQuery1.BatchToQuery(pFIBQuery2, mapStrings);
We will discuss more about batch processing when talking about TpFIBDataSet as it also has
some batch processing methods.
The OnBatchError event occurs in case of incorrect processing. Using the parameter
BatchErrorAction (TBatchErrorAction = (beFail, beAbort, beRetry, beIgnore)) in the code of
this event you can decide what to do in this case.
This feature makes FIBPlus different from BDE, ADO and other libraries where input data
are also available through parameters.
Besides, FIBPlus enables developers to execute stored procedures by using the
TpFIBStoredProc component. TpFIBStoredProc is a direct TpFIBQuery descendant with the
StoredProcName property. It is recommended to use TpFIBStoredProc to execute non-
selectable procedures.
You don’t need to create TpFIBQuery instances. Being called for the first time the
GetQueryForUse procedure will create a TpFIBQuery instance and then will return a link to the
existing component when you execute the same query again and again. As you see, on every
recurrent procedure call FIBPlus will use the prepared query and thus transfer the query text to
the server only once. When you don’t need the recurrent query anymore (when the query results
are obtained from the TpFIBQuery component) you should call the FreeQueryForUse method.
Such FIBPlus mechanism is used for internal purposes i.e. on calling generators to get primary
key values. You can use these methods in your applications to optimize network traffic.
Work with datasets
The TpFIBDataSet component is responsible for work with datasets. It is based on the
TpFIBQuery component and helps to cache selection results. TpFIBDataSet is a TDataSet
descendant so it supports all TDataSet properties, events and methods. To get more information
about TDataSet please read Delphi/C++Builder help manuals.
InsertSQL.Text :=
'insert into CUSTOMER(CUST_NO, CUSTOMER, CONTACT_FIRST, CONTACT_LAST )'+
' values (:CUST_NO, :CUSTOMER, :CONTACT_FIRST, :CONTACT_LAST)';
UpdateSQL.Text :=
'update CUSTOMER set CUSTOMER = :CUSTOMER, '+
'CONTACT_FIRST = :CONTACT_FIRST, CONTACT_LAST = :CONTACT_LAST '+
'where CUST_NO = :CUST_NO';
RefreshSQL.Text :=
'select CUST_NO, CUSTOMER, CONTACT_FIRST, CONTACT_LAST ' +
'from CUSTOMER where CUST_NO = :CUST_NO';
Open;
end;
To open TpFIBDataSet either execute Open/OpenWP methods or set the Active property to
True. To close TpFIBDataSet call the Close method.
Don’t be concerned by seeing a lot of code lines, all these queries can be automatically created
by the TpFIBDataSet editor. You can call it from the component context menu, as shown in
picture 4.
You can get the current sorting order by checking the following properties:
function SortFieldsCount: integer;
returns the sorting field number
function SortFieldInfo(OrderIndex:integer): TSortFieldInfo –
returns information about sorting in the OrderIndex position.
function SortedFields:string
returns a string with sorting fields enumerated by ';'
TSortFieldInfo = record
FieldName: string; //field name
InDataSetIndex: Integer; //whether included into index
InOrderIndex: Integer; //included ...
Asc: Boolean; //True, if ascendant
NullsFirst: Boolean; //True, if Null values are the first
end;
Set poKeepSorting property to True to put records to the right buffer position on inserting and
editing. Use the psGetOrderInfo option if you want to TpFIBDataSet automatically use the local
sorting order defined in the ORDER BY query statement.
Set psPersistentSorting option to True in order to keep the sorting order on TpFIBDataSet
reopening. Be careful, if you have huge selections this feature will not be effective because at
first the buffer will retrieve all records from the server and only then sort them.
Sorting of national symbols
Two parameters are responsible for correct sorting of national symbols: CHARSET (set of
symbols) and COLLATION (sorting order). Even if you correctly set these parameters in a
database and queries TpFIBDataSet may sort them incorrectly. The point is that default local
sorting uses the simplest method without comparing national symbols. As if NONE charset is
set.
TpFIBDataSet can sort national symbols according to the national charset. If you use the
OnCompareFieldValues event you can compare char fields in an alternative way. There are three
standard methods for Ansi-sorting:
protected function CompareFieldValues(Field:TField;const
S1,S2:variant):integer; virtual;
Local filtering
In contrast to IBX, TpFIBDataSet has full support of local filtering. It supports the Filter and
Filtered properties and the OnFilterRecord event.
The table below shows the additional operators which can be used in the Filter property.
Operation Description
< Less than.
> Greater than.
>= Greater than or equal.
<= Less than or equal.
= Equal to
<> Not equal to
AND Logical AND
NOT Logical NOT
OR Logical OR
IS NULL Tests that a field value is null
IS NOT NULL Tests that a field value is not null
+ Adds numbers, concatenates strings, adds number to date/time values
– Subtracts numbers, subtracts dates, or subtracts a number from a date
* Multiplies two numbers
/ Divides two numbers
Upper Upper-cases a string
Lower Lower-cases a string
Substring Returns the substring starting at a specified position
Trim Trims spaces or a specified character from front and back of a string
TrimLeft Trims spaces or a specified character from front of a string
TrimRight Trims spaces or a specified character from back of a string
Year Returns the year from a date/time value
Month Returns the month from a date/time value
Day Returns the day from a date/time value
Hour Returns the hour from a time value
Operation Description
Minute Returns the minute from a time value
Second Returns the seconds from a time value
GetDate Returns the current date
Date Returns the date part of a date/time value
Time Returns the time part of a date/time value
Like Provides pattern matching in string comparisons
In Tests for set inclusion
* Wildcard for partial comparisons.
If the Filter property is set to True and is not active, you can use the following methods to
navigate on records which satisfy the filtering conditions:
FindFirst
FindLast
FindNext
FindPrior
In case of huge data sets we recommend you to use the server filtering. It can be realized by
macros and conditions mechanisms.
To know more about local filtering see the example LocalFiltering.
Important: use the VisibleRecordCount function instead of RecordCount to get the number
of records by the Filter condition.
Data search
TpFIBDataSet supports Locate, LocateNext and LocatePrior methods, which are described in
a standard Delphi/C++Builder help manual.
Besides FIBPlus has some specific analogues which have some important advantages^
function ExtLocate(const KeyFields: String; const KeyValues: Variant;
Options: TExtLocateOptions): Boolean;
function ExtLocateNext(const KeyFields: String; const KeyValues: Variant;
Options: TExtLocateOptions): Boolean;
Pessimistic locking
Standard record changing behavior of InterBase/Firebird servers is optimistic locking. If two
or more users edit the same record at the same time, only the first modification is written to the
database, and the second receives an exception error.
As a rule if you need a pessimistic locking in InterBase/Firebird, you use a «dummy update».
It means that the record is updated i.e. by the primary key before record editing:
update customer set cust_no = cust_no where cust_no = :cust_no
Then the actual record is automatically fetched from the server. This behaviour helps to
guarantee that the record won’t be updated from another transaction before the end of the
dummy update transaction.
FIBPlus manages this process automatically. You need to activate the psProtectedEdit option
or use the the TpFIBDataSet.LockRecord method.
The demo example ProtectedEditing demonstrates how this feature works.
Work in the confined local buffer mode – for huge datasets and random access
The mode was first suggested by Sergey Spirin in gb_Datasets components. Now FIBPlus is also
capable of this feature (since version 6.0). It enables navigation of TpFIBDataSet without fetch
ing all the records returned by the query. In fact it is simulation of random access to records by
means of supplementary queries. The technology sets a number of query requirements. In partic
ular, one of the obligatory requirements is use of ORDER BY in SelectSQL. First, in ORDER
BY it's important to make the combination of field values unique. Second, to speed up data trans
fer time it's better to have two indices - ascending and descending - for this field combination.
This simple example illustrates the technology. Having such a query in SelectSQL:
You may get some first records, fetching them successively. To see the last records immediately,
you may execute an additional query with descending sorting instead of querying all the records
from the server,:
TCacheModelOptions = class(TPersistent)
property BufferChunks: Integer ;
property CacheModelKind: TCacheModelKind ;
property PlanForDescSQLs: string ;
end;
The PlanForDescSQLs property enables to set a separate plan for queries with descending sort
ing.
1
FileS.Free;
end;
end;
If you use TpFIBQuery with BLOB-fields you still use streams, but in contrast to TpFIBDataSet,
you should not create any special streams. TFIBSQLDA has built-in SaveToStream and
LoadFromStream methods. I.e. for TpFIBQuery you only need to write:
pFIBQuery1.FN('BLOB_FIELD').SaveToStream(FileS);
TFIBGuidField
It works similar to TFIBBooleanField: a field should be declared in the domain and the domain
name should have GUID. psUseGuidField should be set to True. This example illustrates how to
declare a domain:
CREATE DOMAIN FIB$GUID AS CHAR(16) CHARACTER SET OCTETS;
If AutoGenerateValue is set to True, the field values will be set automatically on inserting field
values.
Newest FIBPlus versions have a simple solution: you can set the variant array directly:
FBN('LANGUAGE_REQ').Value := VarArrayOf([Edit1.Text, ...]);
It’s easy to set the field values in the BeforePost event. If Update or Insert operations are not
successful, you need to restore the internal array identifier of the editable record. For this you need
to refresh the current record by calling the Refresh method. This rule is set by InterBase API
functions, so FIBPlus should take it into consideration. So the event handler is very important for
working with array fields. You can place it into OnPostError.
procedure ArrayDataSetPostError(DataSet: TDataSet; E: EDatabaseError; var
Action: TDataAction);
begin
Action := daAbort;
MessageDlg('Error!', mtError, [mbOk], 0);
ArrayDataSet.Refresh;
end;
The TFIBXSQLDA.AsQuad function for array fields and BLOB’s has the field BLOB_ID.
Examples ArrayFields1 and ArrayFields2 demonstrate how to work with array fields.
ArrayFields1 shows how to extract an array from a field, ArrayFields2 selects an array directly
from SelectSQL. Both examples write a field into a database packing it into an array field
Firebird 1.5.X releases have an error, returning the wrong length for string fields. That’s whu
you can see a strange last symbol «|» in string array elements.
3
In FIBPlus 6.4.2 upwards, the container can be global for all TpFIBDataSet instances. For this
you need to set the IsGlobal property to True.
You can also build container chains by using the MasterContainer property. When you “inherit”
MasterContainer behaviour you expand container behaviour.
Batch processing
TpFIBDataSet has several methods for batch processing: BatchRecordToQuery and
BatchAllRecordToQuery, which execute an SQL query. This query is set in TpFIBQuery, which is
transferred as a parameter.
See DatasetBatching example to get to know how to use these methods.
Centralized error handling – TpFIBErrorHandler
FIBPlus provides developers with a mechanism of centralized handling of errors and exceptions
which occur with FIBPlus components. For this use the TpFIBErrorHandler component with the
OnFIBErrorEvent event:
TOnFIBErrorEvent = procedure(Sender: TObject; ErrorValue: EFIBError;
KindIBError: TKindIBError; var DoRaise: boolean) of object;
4
где
TKindIBError = (keNoError, keException, keForeignKey, keLostConnect,
keSecurity, keCheck, keUniqueViolation, keOther);
EFIBError = class(EDatabaseError)
//..
property SQLCode : Long read FSQLCode ;
property IBErrorCode: Long read FIBErrorCode ;
property SQLMessage : string read FSQLMessage;
property IBMessage : string read FIBMessage;
end;
The option DoRaise manages FIBPlus behaviour after the handler execution, i.e. it shows
whether a standard exception will be generated.
This option can be used for standard handling of different error types described in KindIBError.
FIBPlus versions 6.4.2 upwards have new properties in TpFIBErrorHandler. They enable
developers to work with localized server messages correctly. You should set such string properties
as Index, Constraint, Exception and At.
Getting TFIBSibEventAlerter events
Use the TFIBSibEventAlerter component to get database events. Define the Database property to
show which connection events will be monitored. Then define necessary event names in Events and
set Active to True to activate the component.
On getting the component event the OnEventAlert event handler will be executed. It is declared
as:
procedure (Sender: TObject; EventName: String; EventCount: Integer);
where EventName is an event name, EventCount is a number of events executed.
Remember that events will be sent only on committing the transaction in which context it
occurred. So several events can occur before ObEventAlert.
The Events example demonstrates how to use events in FIBPlus.
Debugging FIBPlus applications
FIBPlus provides developers with a powerful mechanism for SQL control and debugging. You
can use the SQL monitor and a feature for SQL statistics gathering while working with the
application.
Methods
function ExistStatisticsTable:boolean; - checks whether the statistics table exists
procedure CreateStatisticsTable; - creates a statistics table
procedure SaveStatisticsToDB(ForMaxExecTime:integer=0); - saves the statistics into a table.
This parameter shows statistics of certain queries which we are interested in (you should set the
minimal query execution time). Statistics will be saved for queries executed longer than
ForMaxExecTime or equal to ForMaxExecTime.
procedure SaveLog; - saves a log into a file (valid if ForceSaveLog is set to True).
The SQLLogger example shows how to work with the TFIBSQLLogger component.
FIBPlus repositories
FIBPlus has three repositories enabling developers to save and use TpFIBDataSet settings,
TFields settings and error messages. To use FIBPlus repositories you should set the
UseRepositories property (urFieldsInfo, urDataSetInfo, urErrorMessagesInfo) in TpFIBDatabase
(defining which repositories you need).
You can learn how to use all repositories from the DataSetRepository, ErrorMessagesRepository
and FieldsRepository examples.
Dataset repository
To use the dataset repository in the TpFIBDataSet context menu use «Save to DataSets
Repository table» and «Choose from dataSets Repository table». «Save to DataSets Repository
table» menu item enables you to save main TpFIBDataSet properties into a special table
FIB$DATASETS_INFO, whereas «Choose from dataSets Repository table» helps to load properties
from the component already saved in the repository. If the table does not exist in the database, you
will be asked to create it. To save the TpFIBDataSet properties into a database you should set a
DataSet_ID value (not equal to zero).
Field repository
Get access to the field repository by opening the TpFIBDatabase context menu: «Edit field
information table».
You can set such properties as DisplayLabel, DisplayWidth, Visible, DisplayFormat and
EditFormat for any table field, view and Select procedure. The TRIGGERED value helps to select
fields which will be filled in the trigger and which do not require user values even if they are
Required (NOT NULL).
You should also set the psApplyRepository parameter in TpFIBDataSet.PrepareOptions in order
to get TField settings from the repository on opening the query.
Using field aliases in SQL queries you can see that the settings are not applied for them. This is
correct because physical tables do not have aliases. Nevertheless FIBPlus field repository enables
you to have settings for such fields with aliases: write ALIAS instead of the table name in the
repository.
In version FIBPlus 6.4.2 upwards the dataset has a standard event:
TonApplyFieldRepository=procedure(DataSet:TDataSet;Field:TField;FieldInfo:TpFIBFieldInfo)
of object;
It enables developers to use their own settings in the field repository. For example if you want to
define the EditMask property, add the EDIT_MASK field to the repository table, define the
container in the application and make it global. Then write the following code in the
OnApplyFieldRepository event handler:
procedure TForm1.DataSetsContainer1ApplyFieldRepository(DataSet: TDataSet;
Field: TField; FieldInfo: TpFIBFieldInfo);
begin
Field.EditMask:=FieldInfo.OtherInfo.Values['EDIT_MASK'];
7
end;
9
Additional features
Full UNICODE_FSS support
FIBPlus version 6.0 upwards correctly works with CHARSET UNICODE_FSS. For this you
should use visual components supporting Unicode, e.g. TntControls.
To support Unicode FIBPlus has five new field types:
TFIBWideStringField = class(TWideStringField) – for work with VARCHAR,CHAR;
TFIBMemoField = class(TMemoField, IWideStringField) – for BLOB fields where
IWideStringField is an interface for visual TNT components
(http://tnt.ccci.org/delphi_unicode_controls)
The psSupportUnicodeBlobs option in TpFIBDataSet.PrepareOptions enables you to work with
UNICODE_FSS BLOB fields. By default it is not active, because you need to execute additional
query to know a charset for a certain BLOB field. If you do not work with UNICODE, the query
will be unnecessary.
TpFIBDatabase has a new method function IsUnicodeCharSet: Boolean, which returns True if
the connection uses UNICODE_FSS.
The FIBXSQLVAR class has a new property AsWideString: WideString which returns
WideString.
10
Picture 8. Tools Preferences.
Prefix Generator name and Suffix Generator name fields are important. Setting them you can
form generator names in the AutoUpdateOptions property in TpFIBDataSet. The generator name in
AutoUpdateOptions is formed from the table name (UpdateTable), its prefix and suffix.
The following dialog pages help to define main properties for TpFIBDataBase,
TpFIBTransaction and TpFIBQuery. In particular if you always work with newest
InterBase/Firebird versions (e.g InterBase version 6 upwards), set SQL Dialect=3 in
TpFIBDatabase, then you won’t need to set it manually all the time.
SQL Navigator
It’s the most interesting part of FIBPlus Tools which has no analogues in other products. This
tool helps to handle SQL centrally for the whole application.
SQL Navigator enables you to have access to SQL properties of any component from one place.
The button «Scan all forms of active project» scans all application forms and selects those which
contain FIBPlus components for work with SQL: TpFIBDataSet, TpFIBQuery,
TpFIBUpdateObject and TpFIBStoredProc. Select any of these forms. The list in the right will be
filled with components found on this form. Of you click any component you will see their
corresponding properties with the SQL code. For TpFIBDataSet there will be shown such
properties as SelectSQL, InsertSQL, UpdateSQL, DeleteSQL and RefreshSQL. For TpFIBQuery,
TpFIBUpdateObject and TpFIBStoredProc FIBPlus will show an SQL property value.
You can change any property directly from SQLNavigator and its new value will be saved.
SQLNavigator helps to work with groups of components. You only need е select corresponding
components or forms.
“Save selected SQLs” saves values of selected properties into an external file.
11
“Check selected SQLs” checks selected SQL queries on correctness in SQLNavigator.
Then you can analyze the file with selected queries by using special tools.
You can also use SQLNavigator for text searching in the SQL of the whole project.
By double clicking any found item you make SQLNavigator select a component and a property
and thus can edit SQL.
12
How to work with services
Besides the main component palette FIBPlus also has FIBPlus Services. These components are
intended for getting information about InterBase/Firebird servers, user control, database parameter
setting and database administration.
More details about each issue you can read in InterBase manuals (OpGuide.pdf, parts «Database
Security», «Database Configuration and Maintenance», «Database Backup and Restore» and
«Database and Server Statistic»).
The Services demonstration example shows how to work with services. Besides you can see a
good example in Delphi/C++BuilderL: DelphiX\Demos\Db\IBX\Admin\. Though being written for
IBX, this example suits well for FIBPlus.
All services components are TpFIBCustomService descendants and have such properties and
methods as: ServerName – a server name used for connection; Protocol – a connection protocol;
UserName – a user name; and Password – a user password.
In general work with services is the following: at first you define connection properties (server,
protocol, user and password). The you connect to the server (Attach := True), execute necessary
operations and disconnect (Attach := False). This sequence of actions is demonstrated in the code
below and is necessary for any service.
with TpFIBXXXService.Create(nil) do
try
ServerName := <server_name>;
Protocol := <net_protocol>;
UserName := <user_name>;
Password := <password>;
Atach;
try
//executed operations
finally
Deatach;
end;
finally
Free;
end;
13
Key: Variant;
Id: Variant;
Desc: Variant;
LicensedUsers: Integer;
end;
TLicenseMaskInfo = record
LicenseMask: Integer;
CapabilityMask: Integer;
end;
TConfigFileData = record
ConfigFileValue:Variant;
ConfigFileKey:Variant;
end;
TConfigParams = record
ConfigFileData: TConfigFileData;
BaseLocation: string;
LockFileLocation: string;
MessageFileLocation: string;
SecurityDatabaseLocation: string;
end;
TpFIBServerProperties = class(TpFIBCustomService)
procedure Fetch;
procedure FetchDatabaseInfo;
procedure FetchLicenseInfo;
procedure FetchLicenseMaskInfo;
procedure FetchConfigParams;
procedure FetchVersionInfo;
property DatabaseInfo: TDatabaseInfo
property LicenseInfo: TLicenseInfo
property LicenseMaskInfo: TLicenseMaskInfo
property ConfigParams: TConfigParams
property Options : TPropertyOptions
end;
14
while not Eof do
GetNextLine;
with TpFIBXXXService.Create(nil) do
try
ServerName := <server_name>;
Protocol := <net_protocol>;
UserName := <user_name>;
Password := <password>;
Atach;
try
ServiceStart;
while not Eof do
GetNextLine;
finally
Deatach;
end;
finally
Free;
end;
On working with some other similar services you should set different options.
For more details check the Services example.
15
property UserID : Integer read FUserID write SetUserID;
property GroupID : Integer read FGroupID write SetGroupID;
property Password : string read FPassword write setPassword;
end;
Use the DisplayUser method to get information about the server user (using the user name as a
parameter). DisplayUsers is used to get information about all users. After calling DisplayUser or
DisplayUsers you will see the number of users in the UserInfoCount property; the UserInfo index
property will return a user record by its index.
To add a new user you should set the following properties: UserName, FirstName, MiddleName,
LasName, Password; and execute the AddUser method. DeleteUser and ModifyUser methods work
in the same way as AddUser; they require UserName as a minimal obligatory parameter.
Note:
• the Password property is not returned by DisplayUser and DisplayUsers methods.
• The SQLRole property cannot be used to associate a role with a user.
For these operations you should execute queries using TpFIBQuery (GRANT/REVOKE).
The Services example demonstrates all aspects of work with server users.
Configuring databases
TpFIBConfigService helps to set such parameters as:
• set an interval for the automatic garbage collection in the transaction (Sweep Interval);
• set a mode of writing changes on the disk (Async Mode);
• set the DB page size;
• set the reserved space for the DB;
• set the read-only mode;
• activate and deactivate the shadow
It also helps to:
• shutdown the database (shutdown)
• start the database (online).
Before working with this service you should set the property
property DatabaseName: string
A path to the DB at the server
To set the interval for the automatic garbage collection in the transaction you should use the
SetSweepInterval method. The only SetSweepInterval parameter is the interval, and by default
it is equal to 20000.
procedure SetSweepInterval (Value: Integer);
To set the database dialect you should use the SetDBSqlDialect method; its parameter is the DB
dialect. Only three parameters are supported: 1, 2, 3.
procedure SetDBSqlDialect (Value: Integer);
To set PageBuffers use the SetPageBuffers method; its parameter is the required buffer size.
procedure SetPageBuffers (Value: Integer);
16
To activate the shadow use the ActivateShadow method. It doesn’t require any parameters.
procedure ActivateShadow;
To set the asynchronous writing mode you should set the SetAsyncMode method to True; to
deactivate this mode – to False.
procedure SetAsyncMode (Value: Boolean);
To set the read-only mode use the SetReadOnly method. If it is set to True, the read-only mode
is active; if it is set to False, the read-only mode is deactivated. This mode is used when you prepare
a database for distribution on CD or other mediums
procedure SetReadOnly (Value: Boolean);
Use the ShutdownDatabase method to shutdown the database. There are three types of shutting
the database down: forced, denying new transactions and denying new connections. All the above
mentioned operations should be better done under the SYSDBA administrator’s connection.
procedure ShutdownDatabase (Options: TShutdownMode; Wait: Integer);
These services can work with Embedded server too (remember to set the Local protocol when
working with Firebird Embedded Server).
18