Subject Re: [Firebird-Java] Services API
Author Roman Rokytskyy
Hi,

> I have some questions about using FB Services API from JBird. I'm new in using services API at all, I've just know it's easy way to gather DB stats. As I can understand, it should be done via FBServiceManager subclassing. After digging sources and experimenting it seems like I've found the way. Here is the example of getting PAGE_SIZE from db

Issue is that, AFAIK, you won't get page size (and other isc_info*
items) via Services API - the Services API is to perform some job on the
server and you can think of it as sending a command and parameters to
fork gbak, gstat or gfix processes on the server (in SuperServer no
process is started, it works differently, but anyway the server executes
the code of those utilities in its process). So, execution of the info
calls works only using a normal connection.

That means:

- you don't need to subclass FBServiceManager:

> public class FBServiceManagerEx extends org.firebirdsql.management.FBServiceManager {
> //.... constructors skipped ...
> public int queryPageSize() throws SQLException {
> final GDS gds = getGds();

- you have to instantiate GDS here yourself (there is appropriate
factory method that takes also the type of GDS as parameter)

> final GDSType type = ( ( AbstractGDS )gds ).getType();
> try {
> final IscDbHandle db = gds.createIscDbHandle();
> final DatabaseParameterBuffer dpb = gds.createDatabaseParameterBuffer();
> dpb.addArgument( DatabaseParameterBuffer.USER_NAME, getUser() );
> dpb.addArgument( DatabaseParameterBuffer.PASSWORD, getPassword() );
> final String dbPath = GDSFactory.getDatabasePath(
> type,
> getHost(), getPort(), getDatabase()
> );
> gds.iscAttachDatabase( dbPath, db, dpb );

- here you just opened normal connection to the database, nothing about
services API.

> try {
> final byte[] result = gds.iscDatabaseInfo(
> db,
> new byte[]{ ISCConstants.isc_info_page_size },
> 1024
> );

- this is normal API call;

> final int lengthLen = 2;
> int i = 0;
> while ( result[i] != ISCConstants.isc_info_end ) {
> switch ( result[i++] ) {
> case ISCConstants.isc_info_page_size:
> final int valueLen = gds.iscVaxInteger( result, i, lengthLen );
> i += lengthLen;
> final int res = gds.iscVaxInteger( result, i, valueLen );
> return res;
> default:
> throw new FBSQLException( "Shit happens" );
> }
> }
> throw new FBSQLException( "Shit happens" );
> } finally {
> gds.iscDetachDatabase( db );
> }

- here is everything ok.

> } catch ( GDSException ex ) {
> throw new FBSQLException( ex );
> }
> }

- and here as well.

> So, first of my question is: is it "the right (expected) way" to call services api from JBird, or a kind of Frankenstein creature built up from pieces of code?

The code above does not use services API at all. But I suspect that you
don't need to use Services API directly at all - the subclasses of
FBServiceManager should now contain everything that is available via
Services API (and if not, talk before your begin coding - we need to
check it).

If you implement things like getPageSize() or similar (info calls), then
the best would be to export the calls by extending the
FBDatabaseMetaData class.

> What is the right way, and where can I find Dao of calling services API from JBird?

In test cases :)

> For example, do I really need to finish every query buffer with ISCConstants.isc_info_end -- here I ommit it, but somewhere in sources I've seen it was used (I mean format buffer like new byte[]{ISCConstants.isc_info_page_size, ISCConstants.isc_info_end} )

Yes, the isc_info_end is an marker like EOF - must be always present there.

> Second question is about quering DB transaction info via services API.

Has also nothing to do with Services API.

> I modify query buffer in code above:
> //..
> final byte[] queryItems = {
> ISCConstants.isc_info_oldest_transaction,
> ISCConstants.isc_info_oldest_active,
> ISCConstants.isc_info_oldest_snapshot,
> ISCConstants.isc_info_next_transaction,
> ISCConstants.isc_info_active_transactions,
> ISCConstants.isc_info_end
> };
> final byte[] result = gds.iscDatabaseInfo(
> db,
> queryItems,
> 1024
> );
> //....same processing as above...
>
> And I've really got info about oldest_* and next_* transactions. But
> 1. Server tell me nothing about active_*! It's simply nothing about it in responce buffer!

That you'd better ask Vlad Horsun, and prepare some test case,
preferably in C/C++ so he can check it.

> 2. It seems like quering transaction info itself doing in transaction, and not one transaction -- I've noticed transactions counters incremented by 3 every time I've run last script. Is it any way to "just check, don't touch" this kind of statistics? And if no -- is it, at least, any way to gather all stats I need in one transaction?

That seems to be ok - IIRC the transaction IDs have always a gap between
them.

Roman