Re: [HACKERS] Frontend/backend protocol improvements proposal (request).

Поиск
Список
Период
Сортировка
От Dmitriy Igrishin
Тема Re: [HACKERS] Frontend/backend protocol improvements proposal (request).
Дата
Msg-id CAAfz9KOSxbZLvMm-XWNZ1B6hYQJFUUs5vjKTKM5pdh8z92X2Kw@mail.gmail.com
обсуждение исходный текст
Ответ на Re: [HACKERS] Frontend/backend protocol improvements proposal (request).  (Albe Laurenz <laurenz.albe@wien.gv.at>)
Ответы Re: [HACKERS] Frontend/backend protocol improvements proposal (request).  (Albe Laurenz <laurenz.albe@wien.gv.at>)
Список pgsql-general



2013/6/26 Albe Laurenz <laurenz.albe@wien.gv.at>
Dmitriy Igrishin wrote:
>> I understand the problem now.
>> I pondered a bit over your design, and I came up with a different
>> idea how to represent prepared statements in a C++ library.

>> First, a prepared statement is identified by its name.
>> To make the relationship between a PreparedStatement object
>> and the PostgreSQL prepared statement unique, I suggest that
>> the prepared statement name should not be exposed to the
>> library user.  It should be a private property that is
>> set in the initializer in a unique fashion (for example, it
>> could be a string representation of the memory address
>> of the object).
>> That way, there can never be a name collision.  That should take
>> care of the problem.
>
>
> In fact something like was implemented in very early versions of my
> library. There are some reasons why I've redesigned the library:
>
> 1) If the user does not specify the name of the prepared statement (or
> specify it as "") it is considered as unnamed prepared statement -- a one of
> the important concepts of the frontend/backend protocol, which is a base of
> my current design.
> The unnamed prepared statements are very useful since they are deallocated
> authomatically when the backend receives the next Parse message with
> empty name.

If you want unnamed prepared statements in your library, I would
use a different class for them since they behave quite differently.
That would also make this concern go away.
I've considered this approach also on the designing stage, but I dislike it, because
Named_prepared_statement and Unnamed_prepared_statement, derived from
Prepared_statement, will have exactly the same invariant. The name is a common
property of all prepared statements.

Since there can be only one unnamed prepared statement per
session, there should be only one such object per connection.
It should not get deallocated; maybe it could be private to the
connection, which only offers a "parseUnnamed" and "executeUnnamed"
mathod. 
More precisely, there can be only one uniquely named prepared statement (named
or unnamed) per session.
Could you provide a signature of parseUnnamed and executeUnnamed please?
I don't clearly understand this approach.

> 2) Meaningful names of the named prepared statements (as any other database
> objects) may be useful while debugging the application. Imagine the memory
> addresses (or any other surrogate names) in the Postgres logs...

That wouldn't worry me, but that's a matter of taste.

> Hence, the name() method should be public and name().empty() means
> unnamed prepared statement.

You could offer a getter for the name if anybody needs it for debugging.

If you really want your users to be able to set prepared statement
names, you'd have to warn them to be careful to avoid the
problem of name collision -- you'd handle the burden to them.
That's of course also a possible way, but I thought you wanted
to avoid that.
The mentioned burden is already handled by backend which throws
duplicate_prepared_statement (42P05) error.

>> I also wouldn't provide a deallocate() method.  A deallocated
>> prepared statement is useless.  I think that it would be more
>> logical to put that into the destructor method.
>> If somebody wants to get rid of the prepared statement
>> ahead of time, they can destroy the object.
>
>
> I've also considered this approach and there are some reasons why I don't
> implemented the prepared statement class this way:
>
> 1) There are Describe message in the protocol. Thus, any prepared statement
> can be also described this way:
>   Prepared_statement* pst1 = connection->describe("name");
>   Prepared_statement* pst2 = connection->describe("name"); // pst2 points to the same remote object
> Think about the pst as a pointer to the remote object (prepared statement).
> Since each statement can be described multiple times, the deleting one of them
> should not result in deallocating the prepared statement by the backend.

That seems like bad design to me.
I wouldn't allow different objects pointing to the same prepared
statement.  What is the benefit?
Shouldn't the model represent reality?
Well, then the C and C++ languages are bad designed too, because they
allow to have as many pointers to the same as the user like (needs) :-)
Really, I don't see bad design here. Describing prepared statement
multiple times will results in allocating several independent descriptors.
(As with, for example, performing two SELECTs will result in allocating
several independent results by libpq.)
As a bonus, the user can bind different data to independent prepared statements
objects stepwise (which may be important in some cases) before executing.


> 2) The best way to inform the user about errors in the modern C++ are exceptions.
> The dellocate operation (as any other query to the database) can be result in
> throwing some exception. But descructors should not throw. (If you are familiar with
> C++ well you should know about the gotchas when destructors throw.)
> So, there are deallocate() method which seems to me ok.

Of course an error during DEALLOCATE should be ignored in that case.
It's hard to conceive of a case where deallocation fails, but the
connection is fine.  And if the connection is closed, the statement
will be deallocated anyway.
Why this error should be ignored? I believe that this should be decided by the user.
As a library author I don't know (and cannot know) how to react on such errors
in the end applications.

> Btw, by the reason 2) there are no any transaction RAII classes as in some other libraries,
> because the ROLLBACK command should be executed in the destructor and may throw.

I tend to believe that such errors could also be ignored.
If ROLLBACK (or anything else) throws an error, the transaction will
get rolled back anyway.
Perhaps, but, again, I don't know how the user will prefer to react. So, I prefer just
to throw and allow the user to decide.


--
// Dmitriy.

В списке pgsql-general по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: Problem with at_askml function in Postgis
Следующее
От: Jake Silverman
Дата:
Сообщение: Re: Need help compiling from souce