Subject Re: [IB-Architect] New API -- Request for Comments
Author Glebas Paulevicius
Jim,

If I want to come up with an elegant C++ code - I follow two basic rules:
1) use exception handling;
2) manage objects by value rather by pointers - so that
whatever and whereever exception happens - destructors are called
properly,
or at least - it is compiler's problem - not yours!


What I would love to see is:

main (int argc, char **argv)
{
try
{
Connection connection = createConnection();
Parameters parameters;
parameters.putValue ("user", "jas");
parameters.putValue ("password", "in-your-dreams");
connection.openDatabase ("d:\\OdbcJdbc\\IscDbc\\employee.gdb",
&parameters);
PreparedStatement statement = connection.prepareStatement(
"select first_name, last_name, emp_no from employee where first_name
= ?");
statement.setString (1, "Robert");
ResultSet resultSet = statement.executeQuery();
while (resultSet.next())
{
const char *firstName = resultSet.getString ("first_name");
const char *lastName = resultSet.getString (2);
short empNo = resultSet.getShort (3);
printf ("%.10s %s.15s %d\n", firstName, lastName, empNo);
}
}
catch (SQLException &exception)
{
printf ("Query failed: %s\n", exception.getText());
return 1;
}
return 0;
}

In your code:

> resultSet->release();
> statement->release();
> connection->close();

Why don't you call these release()s and close()s inside catch?
How do you know if resultSet was allocated before exception was thrown or
after?
How do you know if connection was opened before exception was thrown or after?

In my understanding, nearly any method in database wrapper may cause an
exception.
And the only way not to have headache about where to put cleanup code is
to desing classes such way that application can use them by value rather
than by pointers.

>> >C. "Connection *connection = createConnection();"
>> >So you prefer to ban things like "Connection* connection = new
>> >Connection();" ?
>> >Or "Connection connection;" ?
>> >Anyway, we at least require some releaseConnection() or freeConnection()
>to
>> >free resources, then.
>> >
>>
>>First, that won't compile because Connection is an abstract class --
>>it is a pure interface with no code behind it. The actual Connection
>>object will be a subclass of Connection substantiated by a Jdbc
>>driver/subsystem. Since the client program can't be compiled against
>>the real thing, it has to call somebody to create the actual object.
>
>Good point and design.

No - this is not such an unavoidable thing.

Make it so:

class Connection
{
ConnectionInst *_inst;
public:
Connection( ConnectionInst *inst ): _inst( inst ) { _inst->incRef(); }
~Connection() { if( _inst->decRef() ) delete _inst; }
};

and have ConnectionInst as your abstract class making instantiation of
Connection possible

Yes, Java does it all for you,
Yes, it is a little more job for C++ programmer,
But if you do JDBC with C++, agree to mimic Java someplace :)
Then you come up with more elegant, safer solution
for application programmer.

>ResultSet::wasNull() returns true/false.

why "was"? I would say "isNull".

Regards,
Glebas