Обсуждение: Revised proposal for libpq and FE/BE protocol changes

Поиск
Список
Период
Сортировка

Revised proposal for libpq and FE/BE protocol changes

От
Tom Lane
Дата:
Here is a revised proposal that takes into account the discussions
of the last few days.  Any comments?


I propose to revise libpq and modify the frontend/backend protocol
to provide the following benefits:
 * Provide a clean way of reading multiple results from a single query
   string.  Among other things, this solves the problem of allowing a
   single query to return several result sets with different descriptors.
 * Allow a frontend to perform other work while awaiting the result of
   a query.
 * Add the ability to cancel queries in progress.
 * Eliminate the need for frontends to issue dummy queries in order
   to detect NOTIFY responses.
 * Eliminate the need for libpq to issue dummy queries internally
   to determine when a query is complete.

We can't break existing code for this, so the behavior of PQexec()
can't change.  Instead, I propose new functions to add to the API.
Internally, PQexec will be reimplemented in terms of these new
functions, but old applications shouldn't notice any difference.


The new functions are:

    bool PQsendQuery (PGconn *conn, const char *query);

Submits a query without waiting for the result.  Returns TRUE if the
query has been successfully dispatched, otherwise FALSE (in the FALSE
case, an error message is left in conn->errorMessage).

    PGresult* PQgetResult (PGconn *conn);

Waits for input from the backend, and consumes input until (a) a result is
available, (b) the current query is over, or (c) a copy in/out operation
is detected.  NULL is returned if the query is over; in all other cases a
suitable PGresult is returned (which the caller must eventually free).
Note that no actual "wait" will occur if the necessary input has already
been consumed; see below.

    bool PQisBusy (PGconn *conn);

Returns TRUE if a query operation is busy (that is, a call to PQgetResult
would block waiting for more input).  Returns FALSE if PQgetResult would
return immediately.

    void PQconsumeInput (PGconn *conn);

This can be called at any time to check for and process new input from
the backend.  It returns no status indication, but after calling it
the application can use PQisBusy() and/or PQnotifies() to see if a query
was completed or a NOTIFY message arrived.  This function will never wait
for more input to arrive.

    int PQsocket (PGconn *conn);

Returns the Unix file descriptor for the socket connection to the backend,
or -1 if there is no open connection.  This is a violation of modularity,
of course, but there is no alternative: an application that needs
asynchronous execution needs to be able to use select() to wait for input
from either the backend or any other input streams it may have.  To use
select() the underlying socket must be made visible.

    PGnotify *PQnotifies (PGconn *conn);

This function doesn't change; we just observe that notifications may
become available as a side effect of executing either PQgetResult() or
PQconsumeInput(), not just PQexec().

    void PQrequestCancel (PGconn *conn);

Issues a cancel request if possible.  There is no direct way to tell whether
this has any effect ... see discussion below.


Discussion:

An application can continue to use PQexec() as before, and notice
very little difference in behavior.

Applications that want to be able to handle multiple results from a
single query should replace PQexec calls with logic like this:

    // Submit the query
    if (! PQsendQuery(conn, query))
        reportTheError();
    // Wait for and process result(s)
    while ((result = PQgetResult(conn)) != NULL) {
        switch (PQresultStatus(result)) {
        ... process result, for example:
        case PGRES_COPY_IN:
            // ... copy data here ...
            if (PQendcopy(conn))
                reportTheError();
            break;
        ...
        }
        PQclear(result);
    }
    // When fall out of loop, we're done and ready for a new query

Note that PQgetResult will always report errors by returning a PGresult
with status PGRES_NONFATAL_ERROR or PGRES_FATAL_ERROR, not by returning
NULL (since NULL implies non-error termination of the processing loop).

PQexec() will be implemented as follows:

    if (! PQsendQuery(conn, query))
        return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
    lastResult = NULL;
    while ((result = PQgetResult(conn)) != NULL) {
        PQclear(lastResult);
        lastResult = result;
    }
    return lastResult;

This maintains the current behavior that the last result of a series
of commands is returned by PQexec.  (The old implementation is only
capable of doing that correctly in a limited set of cases, but in the
cases where it behaves usefully at all, that's how it behaves.)

There is a small difference in behavior, which is that PQexec will now
return a PGresult with status PGRES_FATAL_ERROR in cases where the old
implementation would just have returned NULL (and set conn->errorMessage).
However, any correctly coded application should handle this the same way.

In the above examples, the frontend application is still synchronous: it
blocks while waiting for the backend to reply to a query.  This is often
undesirable, since the application may have other work to do, such as
responding to user input.  Applications can now handle that by using
PQisBusy and PQconsumeInput along with PQsendQuery and PQgetResult.

The general idea is that the application's main loop will use select()
to wait for input (from either the backend or its other input sources).
When select() indicates that input is pending from the backend, the app
will call PQconsumeInput, followed by checking PQisBusy and/or PQnotifies
to see what has happened.  If PQisBusy returns FALSE then PQgetResult
can safely be called to obtain and process a result without blocking.

Note also that NOTIFY messages can arrive asynchronously from the backend.
They can be detected *without issuing a query* by calling PQconsumeInput
followed by PQnotifies.  I expect a lot of people will build "partially
async" applications that detect notifies this way but still do all their
queries through PQexec (or better, PQsendQuery followed by a synchronous
PQgetResult loop).  This compromise allows notifies to be detected without
wasting time by issuing null queries, yet the basic logic of issuing a
series of queries remains simple.

Finally, since the application can retain control while waiting for a
query response, it becomes meaningful to try to cancel a query in progress.
This is done by calling PQrequestCancel().  Note that PQrequestCancel()
may not have any effect --- if there is no query in progress, or if the
backend has already finished the query, then it *will* have no effect.
The application must continue to follow the result-reading protocol after
issuing a cancel request.  If the cancel is successful, its effect will be
to cause the current query to fail and return an error message.


PROTOCOL CHANGES:

We should change the protocol version number to 2.0.
It would be possible for the backend to continue to support 1.0 clients,
if you think it's worth the trouble to do so.

1. New message type:

Command Done
    Byte1('Z')

The backend will emit this message at completion of processing of every
command string, just before it resumes waiting for frontend input.
This change eliminates libpq's current hack of issuing empty queries to
see whether the backend is done.  Note that 'Z' must be emitted after
*every* query or function invocation, no matter how it terminated.

2. The RowDescription ('T') message is extended by adding a new value
for each field.  Just after the type-size value, there will now be
an int16 "atttypmod" value.  (Would someone provide text specifying
exactly what this value means?)  libpq will store this value in
a new "adtmod" field of PGresAttDesc structs.

3. The "Start Copy In" response message is changed from 'D' to 'G',
and the "Start Copy Out" response message is changed from 'B' to 'H'.
These changes eliminate potential confusion with the data row messages,
which also have message codes 'D' and 'B'.

4. The frontend may request cancellation of the current query by sending
a single byte of OOB (out-of-band) data.  The contents of the data byte
are irrelevant, since the cancellation will be triggered by the associated
signal and not by the data itself.  (But we should probably specify that
the byte be zero, in case we later think of a reason to have different
kinds of OOB messages.)  There is no specific reply to this message.
If the backend does cancel a query, the query terminates with an ordinary
error message indicating that the query was cancelled.


            regards, tom lane

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Bruce Momjian
Дата:
> 2. The RowDescription ('T') message is extended by adding a new value
> for each field.  Just after the type-size value, there will now be
> an int16 "atttypmod" value.  (Would someone provide text specifying
> exactly what this value means?)  libpq will store this value in
> a new "adtmod" field of PGresAttDesc structs.

From src/include/catalog/pg_attribute.h:

    /*
     * atttypmod records type-specific modifications supplied at table
     * creation time, and passes it to input and output functions as the
     * third argument.
     */

Currently only used for char() and varchar(), and includes a 4-byte
header.


--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
ocie@paracel.com
Дата:
Tom Lane wrote:
>
> Here is a revised proposal that takes into account the discussions
> of the last few days.  Any comments?

Just one at the end

[snip]

> 4. The frontend may request cancellation of the current query by sending
> a single byte of OOB (out-of-band) data.  The contents of the data byte
> are irrelevant, since the cancellation will be triggered by the associated
> signal and not by the data itself.  (But we should probably specify that
> the byte be zero, in case we later think of a reason to have different
> kinds of OOB messages.)  There is no specific reply to this message.
> If the backend does cancel a query, the query terminates with an ordinary
> error message indicating that the query was cancelled.

You didn't come right out and say it, but are you intending to support
multiple queries within a connection?  I gather not.  Not that I'm
suggesting that this be done, as it seems this would complicate the
user's application and the backend.  With only one possible OOB
message, you can't tell it which query to cancel.

Ocie Mitchell

Re: [INTERFACES] Revised proposal for libpq and FE/BE protocol changes

От
watts@humbug.antnet.com
Дата:
I suggest the application already has fork or fork/exec to
implement an  asynchronous design. Does that also keep the
socket out of the application's domain?

Bob
watts@humbug.antnet.com

Received: from hub.org (hub.org [209.47.148.200])
    by humbug.antnet.com (8.8.5/8.8.5) with ESMTP id LAA21503
    for <watts@humbug.antnet.com>; Tue, 28 Apr 1998 11:28:48 -0500 (CDT)
Received: from localhost (majordom@localhost) by hub.org (8.8.8/8.7.5) with SMTP id MAA01511; Tue, 28 Apr 1998 12:23:18
-0400(EDT) 
Received: by hub.org (TLB v0.10a (1.23 tibbs 1997/01/09 00:29:32)); Tue, 28 Apr 1998 12:23:16 -0400 (EDT)
Received: (from majordom@localhost) by hub.org (8.8.8/8.7.5) id MAA01498 for pgsql-interfaces-outgoing; Tue, 28 Apr
199812:23:09 -0400 (EDT) 
Received: from sss.sss.pgh.pa.us (sss.pgh.pa.us [206.210.65.6]) by hub.org (8.8.8/8.7.5) with ESMTP id MAA01401; Tue,
28Apr 1998 12:22:04 -0400 (EDT) 
Received: from sss.sss.pgh.pa.us (localhost [127.0.0.1])
    by sss.sss.pgh.pa.us (8.8.5/8.8.5) with ESMTP id MAA07043;
    Tue, 28 Apr 1998 12:21:56 -0400 (EDT)
To: pgsql-hackers@postgreSQL.org, pgsql-interfaces@postgreSQL.org
Subject: [INTERFACES] Revised proposal for libpq and FE/BE protocol changes
Date: Tue, 28 Apr 1998 12:21:55 -0400
Message-ID: <7040.893780515@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
Sender: owner-pgsql-interfaces@hub.org
Precedence: bulk

Here is a revised proposal that takes into account the discussions
of the last few days.  Any comments?


I propose to revise libpq and modify the frontend/backend protocol
to provide the following benefits:
 * Provide a clean way of reading multiple results from a single query
   string.  Among other things, this solves the problem of allowing a
   single query to return several result sets with different descriptors.
 * Allow a frontend to perform other work while awaiting the result of
   a query.
 * Add the ability to cancel queries in progress.
 * Eliminate the need for frontends to issue dummy queries in order
   to detect NOTIFY responses.
 * Eliminate the need for libpq to issue dummy queries internally
   to determine when a query is complete.

We can't break existing code for this, so the behavior of PQexec()
can't change.  Instead, I propose new functions to add to the API.
Internally, PQexec will be reimplemented in terms of these new
functions, but old applications shouldn't notice any difference.


The new functions are:

    bool PQsendQuery (PGconn *conn, const char *query);

Submits a query without waiting for the result.  Returns TRUE if the
query has been successfully dispatched, otherwise FALSE (in the FALSE
case, an error message is left in conn->errorMessage).

    PGresult* PQgetResult (PGconn *conn);

Waits for input from the backend, and consumes input until (a) a result is
available, (b) the current query is over, or (c) a copy in/out operation
is detected.  NULL is returned if the query is over; in all other cases a
suitable PGresult is returned (which the caller must eventually free).
Note that no actual "wait" will occur if the necessary input has already
been consumed; see below.

    bool PQisBusy (PGconn *conn);

Returns TRUE if a query operation is busy (that is, a call to PQgetResult
would block waiting for more input).  Returns FALSE if PQgetResult would
return immediately.

    void PQconsumeInput (PGconn *conn);

This can be called at any time to check for and process new input from
the backend.  It returns no status indication, but after calling it
the application can use PQisBusy() and/or PQnotifies() to see if a query
was completed or a NOTIFY message arrived.  This function will never wait
for more input to arrive.

    int PQsocket (PGconn *conn);

Returns the Unix file descriptor for the socket connection to the backend,
or -1 if there is no open connection.  This is a violation of modularity,
of course, but there is no alternative: an application that needs
asynchronous execution needs to be able to use select() to wait for input
from either the backend or any other input streams it may have.  To use
select() the underlying socket must be made visible.

    PGnotify *PQnotifies (PGconn *conn);

This function doesn't change; we just observe that notifications may
become available as a side effect of executing either PQgetResult() or
PQconsumeInput(), not just PQexec().

    void PQrequestCancel (PGconn *conn);

Issues a cancel request if possible.  There is no direct way to tell whether
this has any effect ... see discussion below.


Discussion:

An application can continue to use PQexec() as before, and notice
very little difference in behavior.

Applications that want to be able to handle multiple results from a
single query should replace PQexec calls with logic like this:

    // Submit the query
    if (! PQsendQuery(conn, query))
        reportTheError();
    // Wait for and process result(s)
    while ((result = PQgetResult(conn)) != NULL) {
        switch (PQresultStatus(result)) {
        ... process result, for example:
        case PGRES_COPY_IN:
            // ... copy data here ...
            if (PQendcopy(conn))
                reportTheError();
            break;
        ...
        }
        PQclear(result);
    }
    // When fall out of loop, we're done and ready for a new query

Note that PQgetResult will always report errors by returning a PGresult
with status PGRES_NONFATAL_ERROR or PGRES_FATAL_ERROR, not by returning
NULL (since NULL implies non-error termination of the processing loop).

PQexec() will be implemented as follows:

    if (! PQsendQuery(conn, query))
        return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
    lastResult = NULL;
    while ((result = PQgetResult(conn)) != NULL) {
        PQclear(lastResult);
        lastResult = result;
    }
    return lastResult;

This maintains the current behavior that the last result of a series
of commands is returned by PQexec.  (The old implementation is only
capable of doing that correctly in a limited set of cases, but in the
cases where it behaves usefully at all, that's how it behaves.)

There is a small difference in behavior, which is that PQexec will now
return a PGresult with status PGRES_FATAL_ERROR in cases where the old
implementation would just have returned NULL (and set conn->errorMessage).
However, any correctly coded application should handle this the same way.

In the above examples, the frontend application is still synchronous: it
blocks while waiting for the backend to reply to a query.  This is often
undesirable, since the application may have other work to do, such as
responding to user input.  Applications can now handle that by using
PQisBusy and PQconsumeInput along with PQsendQuery and PQgetResult.

The general idea is that the application's main loop will use select()
to wait for input (from either the backend or its other input sources).
When select() indicates that input is pending from the backend, the app
will call PQconsumeInput, followed by checking PQisBusy and/or PQnotifies
to see what has happened.  If PQisBusy returns FALSE then PQgetResult
can safely be called to obtain and process a result without blocking.

Note also that NOTIFY messages can arrive asynchronously from the backend.
They can be detected *without issuing a query* by calling PQconsumeInput
followed by PQnotifies.  I expect a lot of people will build "partially
async" applications that detect notifies this way but still do all their
queries through PQexec (or better, PQsendQuery followed by a synchronous
PQgetResult loop).  This compromise allows notifies to be detected without
wasting time by issuing null queries, yet the basic logic of issuing a
series of queries remains simple.

Finally, since the application can retain control while waiting for a
query response, it becomes meaningful to try to cancel a query in progress.
This is done by calling PQrequestCancel().  Note that PQrequestCancel()
may not have any effect --- if there is no query in progress, or if the
backend has already finished the query, then it *will* have no effect.
The application must continue to follow the result-reading protocol after
issuing a cancel request.  If the cancel is successful, its effect will be
to cause the current query to fail and return an error message.


PROTOCOL CHANGES:

We should change the protocol version number to 2.0.
It would be possible for the backend to continue to support 1.0 clients,
if you think it's worth the trouble to do so.

1. New message type:

Command Done
    Byte1('Z')

The backend will emit this message at completion of processing of every
command string, just before it resumes waiting for frontend input.
This change eliminates libpq's current hack of issuing empty queries to
see whether the backend is done.  Note that 'Z' must be emitted after
*every* query or function invocation, no matter how it terminated.

2. The RowDescription ('T') message is extended by adding a new value
for each field.  Just after the type-size value, there will now be
an int16 "atttypmod" value.  (Would someone provide text specifying
exactly what this value means?)  libpq will store this value in
a new "adtmod" field of PGresAttDesc structs.

3. The "Start Copy In" response message is changed from 'D' to 'G',
and the "Start Copy Out" response message is changed from 'B' to 'H'.
These changes eliminate potential confusion with the data row messages,
which also have message codes 'D' and 'B'.

4. The frontend may request cancellation of the current query by sending
a single byte of OOB (out-of-band) data.  The contents of the data byte
are irrelevant, since the cancellation will be triggered by the associated
signal and not by the data itself.  (But we should probably specify that
the byte be zero, in case we later think of a reason to have different
kinds of OOB messages.)  There is no specific reply to this message.
If the backend does cancel a query, the query terminates with an ordinary
error message indicating that the query was cancelled.


            regards, tom lane


Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
dg@illustra.com (David Gould)
Дата:
>
> Tom Lane wrote:
> >
> > Here is a revised proposal that takes into account the discussions
> > of the last few days.  Any comments?
>
> Just one at the end
>
> [snip]
>
> > 4. The frontend may request cancellation of the current query by sending
> > a single byte of OOB (out-of-band) data.  The contents of the data byte
> > are irrelevant, since the cancellation will be triggered by the associated
> > signal and not by the data itself.  (But we should probably specify that
> > the byte be zero, in case we later think of a reason to have different
> > kinds of OOB messages.)  There is no specific reply to this message.
> > If the backend does cancel a query, the query terminates with an ordinary
> > error message indicating that the query was cancelled.
>
> You didn't come right out and say it, but are you intending to support
> multiple queries within a connection?  I gather not.  Not that I'm
> suggesting that this be done, as it seems this would complicate the
> user's application and the backend.  With only one possible OOB
> message, you can't tell it which query to cancel.
>
> Ocie Mitchell

Waves hand wildly... I know, I know!

   All of them!

-dg

David Gould            dg@illustra.com           510.628.3783 or 510.305.9468
Informix Software  (No, really)         300 Lakeside Drive  Oakland, CA 94612
"(Windows NT) version 5.0 will build on a proven system architecture
 and incorporate tens of thousands of bug fixes from version 4.0."
                 -- <http://www.microsoft.com/y2k.asp?A=7&B=5>

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Michael Meskes
Дата:
Tom Lane writes:
> I propose to revise libpq and modify the frontend/backend protocol
> to provide the following benefits:
>  * Provide a clean way of reading multiple results from a single query
>    string.  Among other things, this solves the problem of allowing a
>    single query to return several result sets with different descriptors.

Does this mean I can read in a complete C array with one call? I mean
something like this:

char emp_name[10][10];

exec sql select name into :emp_name from emp;

But then I didn't see anything like this in your examples. Do I have to
iterate using PQgetResult then?

Michael
--
Dr. Michael Meskes, Project-Manager    | topsystem Systemhaus GmbH
meskes@topsystem.de                    | Europark A2, Adenauerstr. 20
meskes@debian.org                      | 52146 Wuerselen
Go SF49ers! Go Rhein Fire!             | Tel: (+49) 2405/4670-44
Use Debian GNU/Linux!                  | Fax: (+49) 2405/4670-10

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Tom Lane
Дата:
ocie@paracel.com writes:
> You didn't come right out and say it, but are you intending to support
> multiple queries within a connection?  I gather not.  Not that I'm
> suggesting that this be done, as it seems this would complicate the
> user's application and the backend.  With only one possible OOB
> message, you can't tell it which query to cancel.

That was something I asked about a few days ago, and didn't get any
responses suggesting that anyone thought it was likely to happen.

We would need wholesale changes everywhere in the protocol to support
concurrent queries: answers and errors coming back would have to be
tagged to indicate which query they apply to.  The lack of a tag in
the cancel message isn't the controlling factor.

In the current system architecture, much the easiest way to execute
concurrent queries is to open up more than one connection.  There's
nothing that says a frontend process can't fire up multiple backend
processes.  I think this is probably sufficient, because I don't
foresee such a thing becoming really popular anyway.

            regards, tom lane

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Tom Lane
Дата:
Michael Meskes <meskes@topsystem.de> writes:
> Does this mean I can read in a complete C array with one call? I mean
> something like this:
> char emp_name[10][10];
> exec sql select name into :emp_name from emp;

As far as I know that works now; or at least, if it doesn't work it's
a limitation of the embedded-SQL interface, and not anything that has
to do with libpq or the fe/be protocol.

A "result" in libpq's terms is the result of a single SQL command.
The result of a successful query, for example, is typically multiple
rows of data.  You only need a PQgetResult loop if (a) you send a
query string that contains several commands, or (b) you issue a
query whose answer contains more than one kind of tuple.

            regards, tom lane

Re: [HACKERS] Re: [INTERFACES] Revised proposal for libpq and FE/BE protocol changes

От
Tom Lane
Дата:
watts@humbug.antnet.com writes:
> I suggest the application already has fork or fork/exec to
> implement an  asynchronous design.

True, if you don't mind assuming you have threads then you could
dedicate one thread to blocking in libpq while your other threads manage
your user interface and so forth.  But most of these revisions would
still be useful in that situation.  The current libpq does not cope well
with query strings containing multiple commands; it doesn't cope at all
with queries that return more than one type of tuple; it requires dummy
queries (wasting both processing time and network bandwidth) to check
for NOTIFY messages; and so forth.  None of those problems can be solved
just by moving calls to libpq into a separate thread.

            regards, tom lane

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Bruce Momjian
Дата:
> That was something I asked about a few days ago, and didn't get any
> responses suggesting that anyone thought it was likely to happen.
>
> We would need wholesale changes everywhere in the protocol to support
> concurrent queries: answers and errors coming back would have to be
> tagged to indicate which query they apply to.  The lack of a tag in
> the cancel message isn't the controlling factor.
>
> In the current system architecture, much the easiest way to execute
> concurrent queries is to open up more than one connection.  There's
> nothing that says a frontend process can't fire up multiple backend
> processes.  I think this is probably sufficient, because I don't
> foresee such a thing becoming really popular anyway.

If we can remove the exec() in 6.4, that will make backend startup even
quicker.


--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Phil Thompson
Дата:
Tom Lane wrote:
>
> PROTOCOL CHANGES:
>
> We should change the protocol version number to 2.0.
> It would be possible for the backend to continue to support 1.0 clients,
> if you think it's worth the trouble to do so.

Or 1.1?  The changes don't seem too traumatic.  Either way, maintaining
support for 1.0 is important as not all of us use libpq and we need time
to catch up.  Also we don't want to put barriers in the way of companies
like Openlink who seem willing to provide support for PostgreSQL in
commercial products.

> 1. New message type:
>
> Command Done
>         Byte1('Z')
>
> The backend will emit this message at completion of processing of every
> command string, just before it resumes waiting for frontend input.
> This change eliminates libpq's current hack of issuing empty queries to
> see whether the backend is done.  Note that 'Z' must be emitted after
> *every* query or function invocation, no matter how it terminated.

The completion response already does this for successful queries, and
the error response for unsuccessful ones.  I came to the conclusion (but
not with absolute certainty) a while back that the empty query hack was
needed for an old feature of the backend that is no longer there.  From
looking at a dump of the data between psql and the backend for 6.3.2 I
don't think that those empty queries are issued any more.  I have
implemented a pure Tcl frontend that doesn't issue them and I haven't
seen any problems.

The exception to the above is the single empty query sent immediately
after the frontend has been successfully authenticated.  This is useful
because it has the side effect of checking that the user has privileges
against the particular database - it is better to do this as part of the
session set up rather than the first real query which may be some time
later.

> 3. The "Start Copy In" response message is changed from 'D' to 'G',
> and the "Start Copy Out" response message is changed from 'B' to 'H'.
> These changes eliminate potential confusion with the data row messages,
> which also have message codes 'D' and 'B'.

The context means there should be no confusion - but if the protocol is
being changed anyway then it makes sense to do this.

Phil

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Tom Lane
Дата:
Phil Thompson <phil@river-bank.demon.co.uk> writes:
> Tom Lane wrote:
>> We should change the protocol version number to 2.0.
>> It would be possible for the backend to continue to support 1.0 clients,
>> if you think it's worth the trouble to do so.

> Or 1.1?  The changes don't seem too traumatic.

Well, pqcomm.h says that an incompatible change should have a new major
version number, and minor though these changes be, they *are*
incompatible.

> Either way, maintaining support for 1.0 is important as not all of us
> use libpq and we need time to catch up.

No argument from me.  It shouldn't be hard to emit the new stuff
conditionally.

>> Command Done
>> Byte1('Z')

> The completion response already does this for successful queries, and
> the error response for unsuccessful ones.

You missed the point: it is possible to send more than one SQL command
in a single query string.  The reason that libpq sends empty queries is
to determine whether the backend is actually done processing the string.
I suppose we could instead try to make libpq smart enough to parse the
string it's sending and determine how many responses to expect ... but
it seems much easier and more robust to have the backend tell us when
it's done.

> From looking at a dump of the data between psql and the backend for
> 6.3.2 I don't think that those empty queries are issued any more.
> I have implemented a pure Tcl frontend that doesn't issue them and I
> haven't seen any problems.

You didn't exercise the cases where they are sent.  A command that
generates a "C" response without tuple data is needed to make libpq
insert an empty query at the moment.  The code is a horrible kluge,
because it only works for cases like
    set geqo to 'off'; show datestyle; select * from table;
and not for, say,
    select * from table1; select * from table2;

psql masks the problem because it splits up your input into separate
commands and hands them to libpq one at a time.  A dumber UI is needed
to exhibit the trouble.  (We should be able to rip out the
command-splitting code from psql after making this change, BTW.
I think it'll be better to have neither psql nor libpq know much of
anything about SQL syntax.)

> The exception to the above is the single empty query sent immediately
> after the frontend has been successfully authenticated.  This is useful

Right.  I didn't plan to remove that one.

            regards, tom lane

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Bruce Momjian
Дата:
>
> Tom Lane wrote:
> >
> > PROTOCOL CHANGES:
> >
> > We should change the protocol version number to 2.0.
> > It would be possible for the backend to continue to support 1.0 clients,
> > if you think it's worth the trouble to do so.
>
> Or 1.1?  The changes don't seem too traumatic.  Either way, maintaining
> support for 1.0 is important as not all of us use libpq and we need time
> to catch up.  Also we don't want to put barriers in the way of companies
> like Openlink who seem willing to provide support for PostgreSQL in
> commercial products.

Yes, but there will be a month for people to get their third-part stuff
changed, and the changes are pretty straight-forward.  Having support
for both in the backend/frontend is going to make that code more
difficult.

If it was only a small change, we could keep it compatable, but it seems
it would be best to just announce it early on.  People can start testing
their new drivers long before the beta period begins.

Also, we are making this change well in advance of the beta, so I hope
they would have enough time to make the transition.

> > The backend will emit this message at completion of processing of every
> > command string, just before it resumes waiting for frontend input.
> > This change eliminates libpq's current hack of issuing empty queries to
> > see whether the backend is done.  Note that 'Z' must be emitted after
> > *every* query or function invocation, no matter how it terminated.
>
> The completion response already does this for successful queries, and
> the error response for unsuccessful ones.  I came to the conclusion (but
> not with absolute certainty) a while back that the empty query hack was
> needed for an old feature of the backend that is no longer there.  From
> looking at a dump of the data between psql and the backend for 6.3.2 I
> don't think that those empty queries are issued any more.  I have
> implemented a pure Tcl frontend that doesn't issue them and I haven't
> seen any problems.
>
> The exception to the above is the single empty query sent immediately
> after the frontend has been successfully authenticated.  This is useful
> because it has the side effect of checking that the user has privileges
> against the particular database - it is better to do this as part of the
> session set up rather than the first real query which may be some time
> later.

Good insight on the libpq interface.  I think we need the new return
code because of the possibility of multiple results from the backend.
In the old code, without the empty query, doesn't a query with multiple
statements cause the send/return results to get out of sync.

> > 3. The "Start Copy In" response message is changed from 'D' to 'G',
> > and the "Start Copy Out" response message is changed from 'B' to 'H'.
> > These changes eliminate potential confusion with the data row messages,
> > which also have message codes 'D' and 'B'.
>
> The context means there should be no confusion - but if the protocol is
> being changed anyway then it makes sense to do this.


--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Phil Thompson
Дата:
Tom Lane wrote:
>
> Phil Thompson <phil@river-bank.demon.co.uk> writes:
> > Tom Lane wrote:
> >> We should change the protocol version number to 2.0.
> >> It would be possible for the backend to continue to support 1.0 clients,
> >> if you think it's worth the trouble to do so.
>
> > Or 1.1?  The changes don't seem too traumatic.
>
> Well, pqcomm.h says that an incompatible change should have a new major
> version number, and minor though these changes be, they *are*
> incompatible.

Err...good point :)

> >> Command Done
> >> Byte1('Z')
>
> > The completion response already does this for successful queries, and
> > the error response for unsuccessful ones.
>
> You missed the point:

I've misunderstood the protocol - and the protocol specification is
therefore wrong (or at least incomplete) in this respect.  Do you want
to fix the spec and include your enhancements or shall I?

Phil

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Phil Thompson
Дата:
Bruce Momjian wrote:

> > Either way, maintaining
> > support for 1.0 is important as not all of us use libpq and we need time
> > to catch up.  Also we don't want to put barriers in the way of companies
> > like Openlink who seem willing to provide support for PostgreSQL in
> > commercial products.
>
> Yes, but there will be a month for people to get their third-part stuff
> changed, and the changes are pretty straight-forward.  Having support
> for both in the backend/frontend is going to make that code more
> difficult.

I agree it will be easy enough for most of us, but may be less so for
companies that traditionally don't release often.  Although I don't use
Openlink's software and can't comment on whether it's any good (or if
anybody actually uses it), I take it as a compliment to PostgreSQL that
a commercial organisation is willing to provide some support for it.
Not maintaining backwards compatibility for at least some time isn't
going to encourage them to continue that support.

Phil

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Tom Lane
Дата:
Phil Thompson <phil@river-bank.demon.co.uk> writes:
> I've misunderstood the protocol - and the protocol specification is
> therefore wrong (or at least incomplete) in this respect.  Do you want
> to fix the spec and include your enhancements or shall I?

Yes, there are some things I thought were wrong in the programmer's guide
chapter about the FE/BE protocol.  I'd be happy to submit revised text.

I haven't paid any attention yet to how the documentation is handled.
Is the stuff in the distribution under doc/src/sgml considered the
editable master text, or is it generated from some other format?
Do I need to subscribe to pgsql-docs to find out what to do? :-)

            regards, tom lane

Re: [INTERFACES] Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
"Thomas G. Lockhart"
Дата:
Tom Lane wrote:
>
> Phil Thompson <phil@river-bank.demon.co.uk> writes:
> > I've misunderstood the protocol - and the protocol specification is
> > therefore wrong (or at least incomplete) in this respect.  Do you want
> > to fix the spec and include your enhancements or shall I?
>
> Yes, there are some things I thought were wrong in the programmer's guide
> chapter about the FE/BE protocol.  I'd be happy to submit revised text.
>
> I haven't paid any attention yet to how the documentation is handled.
> Is the stuff in the distribution under doc/src/sgml considered the
> editable master text, or is it generated from some other format?

Yes, doc/src/sgml/*.sgml is the editable format. Phil's writeup is in
protocol.sgml and that is all that would need to be touched. Then submit
the patches (or a replacement file since you are the only one editing
that at the moment) and we'll snarf them up and merge.

The SGML markup is not the prettiest, but don't be intimidated/annoyed
by it. Especially if you are making incremental changes, I would guess
that you will see how to cut and paste using the existing markup tags in
the file. Let us know if you have any trouble with it. We can fix markup
problems after you post changes too...

> Do I need to subscribe to pgsql-docs to find out what to do? :-)

Only if you want to keep writing :)

                        - Tom

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
dg@illustra.com (David Gould)
Дата:
Bruce Momjian wrote:
> >
> > Tom Lane wrote:
> > >
> > > PROTOCOL CHANGES:
> > >
> > > We should change the protocol version number to 2.0.
> > > It would be possible for the backend to continue to support 1.0 clients,
> > > if you think it's worth the trouble to do so.
> >
> > Or 1.1?  The changes don't seem too traumatic.  Either way, maintaining
> > support for 1.0 is important as not all of us use libpq and we need time
> > to catch up.  Also we don't want to put barriers in the way of companies
> > like Openlink who seem willing to provide support for PostgreSQL in
> > commercial products.
>
> Yes, but there will be a month for people to get their third-part stuff
> changed, and the changes are pretty straight-forward.  Having support
> for both in the backend/frontend is going to make that code more
> difficult.
>
> If it was only a small change, we could keep it compatable, but it seems
> it would be best to just announce it early on.  People can start testing
> their new drivers long before the beta period begins.
>
> Also, we are making this change well in advance of the beta, so I hope
> they would have enough time to make the transition.

I know this is old old discussion, so "shut up, we're done with it" is a
fine answer...

But, I think maintaining compatibility with 1.0 is important. If we expect
people to really use this software to build real applications, then we
cannot expect them to be interested in revising or even recompiling their
applications.

For example a web development consulting house. They build shopping cart
or other database using web sites for their clients.  They do not want to
have to go to each of their customers (say hundreds of sites) and recompile
everything just to take advantage of a new server that happens to fix some
bugs they needed fixed. They also don't want to reload the databases or
otherwise get involved in upgrade issues. And, their clients don't want
to pay for this either.

Database customers at least in the commercial world can be incredibly
conservative. It is not at all uncommon to have large sites running DBMS
engines that are three major releases (ie, well over three years) old.
Once they get an app working, they really don't want anything to change.

-dg

David Gould            dg@illustra.com           510.628.3783 or 510.305.9468
Informix Software  (No, really)         300 Lakeside Drive  Oakland, CA 94612
"Of course, someone who knows more about this will correct me if I'm wrong,
 and someone who knows less will correct me if I'm right."
               --David Palmer (palmer@tybalt.caltech.edu)

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Bruce Momjian
Дата:
> Database customers at least in the commercial world can be incredibly
> conservative. It is not at all uncommon to have large sites running DBMS
> engines that are three major releases (ie, well over three years) old.
> Once they get an app working, they really don't want anything to change.

And, oh yea, we kept database compatability, thanks to Tom Lane.

--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Bruce Momjian
Дата:
> Database customers at least in the commercial world can be incredibly
> conservative. It is not at all uncommon to have large sites running DBMS
> engines that are three major releases (ie, well over three years) old.
> Once they get an app working, they really don't want anything to change.

Yes, this is true.  Their data is locked in Our database.  And you can't
just restart it like a PC OS or word processor.  Database demands are
much different.

--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Tom Lane
Дата:
dg@illustra.com (David Gould) writes:
> I know this is old old discussion, so "shut up, we're done with it" is a
> fine answer...
> But, I think maintaining compatibility with 1.0 is important.

We did maintain compatibility, in that the server will still talk to
a client that identifies itself as 1.0 in the initial handshake.
(Kudos to whoever had the foresight to put a protocol version number
in the startup message, BTW.)

As things are currently set up, however, a new compilation of libpq
will only know how to talk protocol 2.0, so it cannot be used to
talk to an old server.  Are you concerned about that?  I don't see
any easy way around it...

            regards, tom lane

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Bruce Momjian
Дата:
Tom, just wondering were we are with this.  Can you update libpq.3?  I
think until the sgml of the manual is converted, they are the most
current.  I just made some cleanups there myself.  Are the sgml sources
updated with the protocol changes?

Also, are these items completed?  How about our cancel query key?  I
think it is random/secure enough for our purposes.  Can you make the
changes, or do you need changes from me?

---------------------------------------------------------------------------


> Here is a revised proposal that takes into account the discussions
> of the last few days.  Any comments?
>
>
> I propose to revise libpq and modify the frontend/backend protocol
> to provide the following benefits:
>  * Provide a clean way of reading multiple results from a single query
>    string.  Among other things, this solves the problem of allowing a
>    single query to return several result sets with different descriptors.
>  * Allow a frontend to perform other work while awaiting the result of
>    a query.
>  * Add the ability to cancel queries in progress.
>  * Eliminate the need for frontends to issue dummy queries in order
>    to detect NOTIFY responses.
>  * Eliminate the need for libpq to issue dummy queries internally
>    to determine when a query is complete.
>
> We can't break existing code for this, so the behavior of PQexec()
> can't change.  Instead, I propose new functions to add to the API.
> Internally, PQexec will be reimplemented in terms of these new
> functions, but old applications shouldn't notice any difference.
>
>
> The new functions are:
>
>     bool PQsendQuery (PGconn *conn, const char *query);
>
> Submits a query without waiting for the result.  Returns TRUE if the
> query has been successfully dispatched, otherwise FALSE (in the FALSE
> case, an error message is left in conn->errorMessage).
>
>     PGresult* PQgetResult (PGconn *conn);
>
> Waits for input from the backend, and consumes input until (a) a result is
> available, (b) the current query is over, or (c) a copy in/out operation
> is detected.  NULL is returned if the query is over; in all other cases a
> suitable PGresult is returned (which the caller must eventually free).
> Note that no actual "wait" will occur if the necessary input has already
> been consumed; see below.
>
>     bool PQisBusy (PGconn *conn);
>
> Returns TRUE if a query operation is busy (that is, a call to PQgetResult
> would block waiting for more input).  Returns FALSE if PQgetResult would
> return immediately.
>
>     void PQconsumeInput (PGconn *conn);
>
> This can be called at any time to check for and process new input from
> the backend.  It returns no status indication, but after calling it
> the application can use PQisBusy() and/or PQnotifies() to see if a query
> was completed or a NOTIFY message arrived.  This function will never wait
> for more input to arrive.
>
>     int PQsocket (PGconn *conn);
>
> Returns the Unix file descriptor for the socket connection to the backend,
> or -1 if there is no open connection.  This is a violation of modularity,
> of course, but there is no alternative: an application that needs
> asynchronous execution needs to be able to use select() to wait for input
> from either the backend or any other input streams it may have.  To use
> select() the underlying socket must be made visible.
>
>     PGnotify *PQnotifies (PGconn *conn);
>
> This function doesn't change; we just observe that notifications may
> become available as a side effect of executing either PQgetResult() or
> PQconsumeInput(), not just PQexec().
>
>     void PQrequestCancel (PGconn *conn);
>
> Issues a cancel request if possible.  There is no direct way to tell whether
> this has any effect ... see discussion below.
>
>
> Discussion:
>
> An application can continue to use PQexec() as before, and notice
> very little difference in behavior.
>
> Applications that want to be able to handle multiple results from a
> single query should replace PQexec calls with logic like this:
>
>     // Submit the query
>     if (! PQsendQuery(conn, query))
>         reportTheError();
>     // Wait for and process result(s)
>     while ((result = PQgetResult(conn)) != NULL) {
>         switch (PQresultStatus(result)) {
>         ... process result, for example:
>         case PGRES_COPY_IN:
>             // ... copy data here ...
>             if (PQendcopy(conn))
>                 reportTheError();
>             break;
>         ...
>         }
>         PQclear(result);
>     }
>     // When fall out of loop, we're done and ready for a new query
>
> Note that PQgetResult will always report errors by returning a PGresult
> with status PGRES_NONFATAL_ERROR or PGRES_FATAL_ERROR, not by returning
> NULL (since NULL implies non-error termination of the processing loop).
>
> PQexec() will be implemented as follows:
>
>     if (! PQsendQuery(conn, query))
>         return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
>     lastResult = NULL;
>     while ((result = PQgetResult(conn)) != NULL) {
>         PQclear(lastResult);
>         lastResult = result;
>     }
>     return lastResult;
>
> This maintains the current behavior that the last result of a series
> of commands is returned by PQexec.  (The old implementation is only
> capable of doing that correctly in a limited set of cases, but in the
> cases where it behaves usefully at all, that's how it behaves.)
>
> There is a small difference in behavior, which is that PQexec will now
> return a PGresult with status PGRES_FATAL_ERROR in cases where the old
> implementation would just have returned NULL (and set conn->errorMessage).
> However, any correctly coded application should handle this the same way.
>
> In the above examples, the frontend application is still synchronous: it
> blocks while waiting for the backend to reply to a query.  This is often
> undesirable, since the application may have other work to do, such as
> responding to user input.  Applications can now handle that by using
> PQisBusy and PQconsumeInput along with PQsendQuery and PQgetResult.
>
> The general idea is that the application's main loop will use select()
> to wait for input (from either the backend or its other input sources).
> When select() indicates that input is pending from the backend, the app
> will call PQconsumeInput, followed by checking PQisBusy and/or PQnotifies
> to see what has happened.  If PQisBusy returns FALSE then PQgetResult
> can safely be called to obtain and process a result without blocking.
>
> Note also that NOTIFY messages can arrive asynchronously from the backend.
> They can be detected *without issuing a query* by calling PQconsumeInput
> followed by PQnotifies.  I expect a lot of people will build "partially
> async" applications that detect notifies this way but still do all their
> queries through PQexec (or better, PQsendQuery followed by a synchronous
> PQgetResult loop).  This compromise allows notifies to be detected without
> wasting time by issuing null queries, yet the basic logic of issuing a
> series of queries remains simple.
>
> Finally, since the application can retain control while waiting for a
> query response, it becomes meaningful to try to cancel a query in progress.
> This is done by calling PQrequestCancel().  Note that PQrequestCancel()
> may not have any effect --- if there is no query in progress, or if the
> backend has already finished the query, then it *will* have no effect.
> The application must continue to follow the result-reading protocol after
> issuing a cancel request.  If the cancel is successful, its effect will be
> to cause the current query to fail and return an error message.
>
>
> PROTOCOL CHANGES:
>
> We should change the protocol version number to 2.0.
> It would be possible for the backend to continue to support 1.0 clients,
> if you think it's worth the trouble to do so.
>
> 1. New message type:
>
> Command Done
>     Byte1('Z')
>
> The backend will emit this message at completion of processing of every
> command string, just before it resumes waiting for frontend input.
> This change eliminates libpq's current hack of issuing empty queries to
> see whether the backend is done.  Note that 'Z' must be emitted after
> *every* query or function invocation, no matter how it terminated.
>
> 2. The RowDescription ('T') message is extended by adding a new value
> for each field.  Just after the type-size value, there will now be
> an int16 "atttypmod" value.  (Would someone provide text specifying
> exactly what this value means?)  libpq will store this value in
> a new "adtmod" field of PGresAttDesc structs.
>
> 3. The "Start Copy In" response message is changed from 'D' to 'G',
> and the "Start Copy Out" response message is changed from 'B' to 'H'.
> These changes eliminate potential confusion with the data row messages,
> which also have message codes 'D' and 'B'.
>
> 4. The frontend may request cancellation of the current query by sending
> a single byte of OOB (out-of-band) data.  The contents of the data byte
> are irrelevant, since the cancellation will be triggered by the associated
> signal and not by the data itself.  (But we should probably specify that
> the byte be zero, in case we later think of a reason to have different
> kinds of OOB messages.)  There is no specific reply to this message.
> If the backend does cancel a query, the query terminates with an ordinary
> error message indicating that the query was cancelled.


--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Tom Lane
Дата:
Bruce Momjian <maillist@candle.pha.pa.us> writes:
> Tom, just wondering were we are with this.  Can you update libpq.3?

Will do.  I've been busy with other stuff and have not had time to spend
on pgsql, but will try to push it up the priority list.

> Are the sgml sources updated with the protocol changes?

Yes, those are done.  I had been hoping not to have to update libpq.3
manually, that's all...

> Also, are these items completed?  How about our cancel query key?  I
> think it is random/secure enough for our purposes.  Can you make the
> changes, or do you need changes from me?

I haven't looked to see what's been done there --- have you finished an
initial implementation, or is the cancel-via-postmaster-instead-of-OOB
change still just at the talk stage?  I can handle the libpq end of it,
but feel less secure about modifying the postmaster.

            regards, tom lane

Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes

От
Bruce Momjian
Дата:
> Bruce Momjian <maillist@candle.pha.pa.us> writes:
> > Tom, just wondering were we are with this.  Can you update libpq.3?
>
> Will do.  I've been busy with other stuff and have not had time to spend
> on pgsql, but will try to push it up the priority list.
>
> > Are the sgml sources updated with the protocol changes?
>
> Yes, those are done.  I had been hoping not to have to update libpq.3
> manually, that's all...
>
> > Also, are these items completed?  How about our cancel query key?  I
> > think it is random/secure enough for our purposes.  Can you make the
> > changes, or do you need changes from me?
>
> I haven't looked to see what's been done there --- have you finished an
> initial implementation, or is the cancel-via-postmaster-instead-of-OOB
> change still just at the talk stage?  I can handle the libpq end of it,
> but feel less secure about modifying the postmaster.

Perhaps you can work up a patch, and I can review it, or give ideas on
how to proceed.  The actual protocol layers in the postmaster,
especially for authentication, are very hard for me to understand.

--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)