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

Поиск
Список
Период
Сортировка
От Bruce Momjian
Тема Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes
Дата
Msg-id 199807050005.UAA06497@candle.pha.pa.us
обсуждение исходный текст
Ответ на Revised proposal for libpq and FE/BE protocol changes  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: [HACKERS] Revised proposal for libpq and FE/BE protocol changes  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-interfaces
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)

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

Предыдущее
От: Ludovic Marcotte
Дата:
Сообщение: select w/Swing's JTable widget
Следующее
От: "Kurt J. Hoell"
Дата:
Сообщение: Re: [SQL] select w/Swing's JTable widget