Subject Re: [Firebird-devel] Gpre, Jdbc, and a Modest Proposal
Author Jim Starkey
Brad Pepers wrote:

>Just a comment on a new API idea is that I think using pointers for ResultSet,
>PreparedStatement, and any other classes is a bad idea. Rewrite your example
>code with proper error handling all along and the possiblity of exceptions
>and see what you get. If you use a smart pointer type of class that hides
>the actual pointer and calls new/delete for you then you can handle things
>much more clearly and you can depend on the object lifetime rules to destruct
>things properly in the case of exceptions raised and such. I would like to
>see your example coded like this:
> PreparedStatement statement(connection);
> statement.setCommand("select * from RDB$RELATIONS where "
> statement.setInt(1, relationId);
> ResultSet resultSet = statement.executeQuery();
> while ( {
> const char* relationName = resultSet.getString("RDB$RELATION_NAME)
> printf("Got one: %s\n", relationName);
> }
Smart pointers are generally good things and we should provide them.
But lets not confuse smart pointer semantics with the semantics of the
thing pointed to. Right now we're talking about the objects and the API.

But since you raised the question, PreparedStatement is more problematic
than you may have realized. It has two methods that control lifetime,
close() and release(). Close dumps active state associated with the
object but doesn't release it. Release decrements the use count, which
when reaching zero, does an implicit close if necessary and deletes the
object. So it would work very nicely with the smart pointer. The
internal version I use in Netfrastructure has slightly different
semantics. Internally, close disassociates the object ignoring the use
count, and deletes the object. The different is partly pragmatic and
partly internal accounts. Use counts for the internal object are held
by any dangling result sets and the connection object itself, though the
disassociating process would cleanly decrement them.

In the external API, your smart pointer would use addRef/release rather
than close, so the issue is rather moot.

>1. Use C++ exceptions. I wouldn't recommend this personally since I've fought
>this battle a few times and its not worth the hassle. It should work well
>and should be easy but there are still compiler issues (g++ in particular)
>and it still causes a huge overhead.
The API uses C++ exceptions. There really aren't any compiler issues
that I know of.

>2. Return bool results from methods that can fail. Limited when the method
>naturally returns some other result type. In that case you can decide on an
>error value in the result type (ie: -1 for integer) but then you hit times
>when all possible results are valid so there is no error code.
The JDBC philophophy, to which I subscribe, is that normal expected
results are result by values, other things are thrown as exceptions. In
the case of ResultSet::next(), both the conditions "got a record" and
"ran out of records" are normal, expected results. The condtion
"statement isn't active" is throw as an exception. There really aren't
any gray areas. Either the system didn't what you asked as returns
normally, or didn't and throws an exception.

The DSRI interface has always used the same convention. The status
reflects what the infrastructure did with your call. If the result is
success, everything else of interest is in the data. If, using the
preprocess, you can an error on a statement with an "on-error" clause,
the clause was executed, otherwise the program was aborted with an
appropriate diagnostic and return code. JDBC has the same result -- if
you get an error without a catch clause, you program is going to croak.

I have alway detested status code, particularly the sqlcode.
Programmers are constantly forgetting to test them and getting
themselves in hot water. I designed the DEC DML and GDML so no
programmer anywhere would ever have to test any status code.

The point is really how simple and trouble-free the code can be.

>3. Pass in a status vector sort of thing like is done now. Works but I think
>there is a better way.
No, exceptions are the correct and proper way.

>4. Keep the status of the last call in the class so it can be checked. Better
>than creating and passing around status vectors all the time. This is what I
>would suggest.
I couldn't diagree more. That is stale data prone to disappearing
without notice. It screws up the logic, interferes with object lifetime
control and application layer. It violates the implicit princiiple that
a wrong action should have no side effects.

>Anyway just some random thoughts on the matter with the decision of using
>pointers vrs objects the main point of consideration.
Thanks for your comments.


Jim Starkey
Netfrastructure, Inc.
978 526-1376