I'm moving this discussion to -general. Dmitriy Igrishin wrote: >>> While developing a C++ client library for Postgres I felt lack of extra >>> information in command tags in the CommandComplete (B) message [...] >>> for the following commands: >> It seems like bad design to me to keep a list of prepared statements >> on the client side when it is already kept on the server side >> (accessible with the pg_prepared_statements view). >> >> What's wrong with the following: >> If the user wants to deallocate an individual prepared statement, >> just send "DEALLOCATE <statement name>" to the server. If the >> statement does not exist, the server will return an error. >> If the user wants to deallocate all statements, just send >> "DEALLOCATE ALL". >> Why do you need to track prepared statements on the client side? > > > Nothing wrong if the user wants to deal with scary and cumbersome code. > As library author, I want to help people make things simpler. I don't think that anything would change on the user end. > To understand me, please look at the pseudo C++ code below. > > > // A class designed to work with prepared statements > class Prepared_statement { > > public: > // Methods to generate a Bind message, like > Prepared_statement* bind(Position, Value); > // ... and more > // Methods to send Execute message, like > void execute(); > void execute_async(); > }; > > class Connection { > public: > // many stuff ... > void close(); > > Prepared_statement* prepare(Name, Query); > void prepare_async(Statement); > > // Make yet another instance of prepared statement. > Prepared_statement* prepared_statement(Name); > > // etc. > }; > > The Connection class is a factory for Prepared_statement instances. > As you can see, the Connection::prepare() returns new instance of > *synchronously* prepared statement. Next, the user can bind values > and execute the statement, like this: > > void f(Connection* cn) > { > // Prepare unnamed statement and execute it. > cn->prepare("SELECT $1::text")->bind(0, "Albe")->execute(); > // Ps: don't worry about absence of delete; We are using smart pointers :-) > } > > But there is a another possible case: > > void f(Connection* cn) > { > Prepared_statement* ps = cn->prepare("SELECT $1::text"); > cn->close(); // THIS SHOULD invalidate all Prepared_statement instances ... > ps->bind(0, "Albe"); // ... to throw the exception here > } Attempting to send a bind message over a closed connection will result in a PostgreSQL error. All you have to do is wrap that into an exception of your liking. > Moreover, consider: > > void f(Connection* cn) > { > Prepared_statement* ps1 = cn->prepare("ps1", "SELECT $1::text"); > > cn->deallocate("ps1"); // THIS invalidates ps1 object... Shouldn't that be cn->deallocate(ps1); without quotes? > ps1->bind(0, "Albe"); // ... to throw the exception here > > > Prepared_statement* ps2 = cn->prepare("ps2", "SELECT $1::text"); > > cn->perform("DEALLOCATE ps2"); // THIS SHOULD ALSO invalidate ps2 object... > ps2->bind(0, "Albe"); // ... to throw the exception here > > } Again, sending a bind message for a deallocated prepared statement will cause a PostgreSQL error automatically. > In the latter case when the user deallocates named prepared statement directly, > the implementation of Connection can invalidates the prepared statement (ps2) by > analyzing and parsing CommandComplete command tag to get it's name. > > And please note, that the user can send DEALLOCATE asynchronously. And there is > only two ways to get the prepared statement (or another session object's) name: > 1) Parse the SQL command which the user is attempts to send; > 2) Just get it from CommandComplete command tag. > > I beleive that the 1) is a 100% bad idea. > > PS: this C++11 library is not publicaly available yet, but I hope it will this year. I still think that it is a bad idea to track this on the client side. What's wrong with throwing an exception when you get a PostgreSQL error? If you want to distinguish between certain error conditions, you can use the SQLSTATE. For example, trying to execute a deallocated statement would cause SQLSTATE 26000. Yours, Laurenz Albe -- Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-general