On 2020-06-16 13:57, Tony Whyman wrote:

On 15/06/2020 15:37, Alex Peshkoff via Firebird-devel wrote:
On 2020-06-11 18:30, Tony Whyman wrote:
On 11/06/2020 11:18, Pavel Cisar wrote:
This is not a problem for languages like Python, Java and .NET that don't use these files at all, but C++ & Pascal are still important languages and we should offer some better solution. At least it should be discussed with those who use them (for example MWA Software, developer of ibx4lazarus?).

Did I just hear my name mentioned ;)

My main gripe with the new API is really more about documentation than anything else. It is not easy to work out how to use it except by experimentation. E.g. with the new DecFloat type I basically had to look at how the interface returned the BCD format value by using the debugger to inspect the data at the byte level and then work out how to convert this (unpacked) format into the packed tBCD record used by FPC and Delphi - and vice versa.

That's format present in original IBM's library. They do not support packed BCD. If you provide a link to the description of packed BCD I can add support for it.
I was more concerned about documenting (or providing a reference to the documentation) for the BCD format used by the Firebird Client API. When it comes to the packed BCD format used by Delphi and FPC, there seems to be little more than the source code in the FmtBCD unit - and they are not even consistent in the way that the precision is recorded.

That's what I see in documentation:
bcd (uint8_t *) Pointer to the byte array which provides the coefficient; the most significant digit of the coefficient is at bcd[0] and the least significant is at bcd[n-1]. As far as I know that's also called 8-bit BCD or unpacked BCD. Each decimal digit is encoded into one byte, with four bits representing the number and the remaining bits having no significance.



The "firebird.pas" file is always "processed" before it is taken into IBX for Lazarus - which is perhaps why I am less bothered about any imperfections in the source code. The most important need for this is to extract the type and const declarations and separate them out in order to avoid name space conflicts between the actual API and IBX, as well as to limit pollution of the global name space. I also remove the exceptions generated by the cloop code as I prefer to handle the exceptional conditions in IBX itself.

An ability to process exception in another way is very important but missing. Can you suggest a generic way? If yes suppose we can add it to code generator.

Here's a simple example of what I have done:

function IMaster.getMetadataBuilder(status: IStatus; fieldCount: Cardinal): IMetadataBuilder;
begin
    Result := MasterVTable(vTable).getMetadataBuilder(Self, status, fieldCount);
    {$IFDEF USEFBEXCEPTION}FbException.checkException(status);{$ENDIF}
end;

I have made every call to FbException.checkException conditional - in practice, IBX never defines USEFBEXCEPTION and hence these calls are commented out. The IBX code will typically check the status itself and raise its own exception when necessary. There are some exceptions e.g. when creating an attachment, IBX looks at the error code and may perform an alternative e.g. if the database does not exist then it may be created.


Nice, now I see how can we turn exceptions On/off. Is it possible to do something like this - if user defined some variable use it as a name of user's excption class which must have checkException() procedure?
On C that looks like:

once at the beginnig:

#ifndef FBEXCEPTION
#define FBEXCEPTION FbException
#endif

in functions:

function IMaster.getMetadataBuilder(status: IStatus; fieldCount: Cardinal): IMetadataBuilder;
begin
    Result := MasterVTable(vTable).getMetadataBuilder(Self, status, fieldCount);
    FBEXCEPTION.checkException(status);
end;

Can we perform such macro subst using pascal?

Is it really necessary to perform exception handling in firebird.pas? The user can either  do their own exception handling or call FbException.checkException to perform default exception handling.


May be it's not actual for components set - but when one writes a piece of program using API that becomes true useful - manually adding checkException after each call poisons program  and makes it less readable.

There is one more good way to work with exceptions. Imagine we replace IStatus parameter with some more generic class that can:
- provide IStatus interface using some fixed function,
- perform exception check.
I.e. (returning to our sample):

function IMaster.getMetadataBuilder(status: NewClass; fieldCount: Cardinal): IMetadataBuilder;
begin
    Result := MasterVTable(vTable).getMetadataBuilder(Self, status.getStatus(), fieldCount);
    status.checkException();
end;

With virtual getStatus() & checkException() we get very flexible system - we can have different implementations of NewClass, one performing real checkException, other doing nothing with it. This makes it possible to have different behavior passing different first parameter and make it possible to not throw exception when we want to process status vector manually, at athe same time avoiding need in any manual checks in 99% of a program.

If you can help with such class on Pascal - I will add all of this to cloop generator.




The call to get the IMaster interface also assumes static linking with the client library,

???
Why?

The syntax

function fb_get_master_interface : IMaster; cdecl; external 'fbclient';

is usually used for static linking. I believe that it can be used with dlls - but you have no control over the location. You just get the first one it finds in the path.

I see...
How can it be declared better?



while IBX always dynamically loads the fb client library and then dynamically links to each exported call using GetProcAddress.

fb_get_master_interface() is absolutely same call as all others in fbclient, I do not understabd your problems with use of it in GetProcAddress. At least it's posix analogue dlsym() works fine.
I am really just making the point that the call to fb_get_master_interface in firebird.pas is really little more than a simple example of how to load the firebird client library. For anything more than basic use this has to be commented out as it will conflict with dynamic library loading.

In C declaring external function does not mean force link with a library where it's located. Library is needed only when that function was really used somewhere. And once again I'm open to suggestions how to do it better, i.e. have at the same type abilities to link fbclient static or load dynamic.

PS. I've used to work with pascal long ago, but it was in XX century...




Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel

Reply via email to