Here are my notes about what to do to extend libpq's API to support the
new features of the 3.0 frontend/backend protocol.  Not very polished
but I trust you can follow it.  Any objections?

			regards, tom lane


LIBPQ updates for new protocol
------------------------------

Needed:

* Access to individual fields of an error/notice result; also some setting to
determine how verbose PQerrorMessage is

	char *PQerrorField(conn, char fieldcode)
	char *PQresultErrorField(const PGresult *res, char fieldcode)

fieldcode is as per the protocol spec.  NULL is returned if no such field in
current result (this includes case where current result isn't an error).

Errors generated internally by libpq will have severity, primary message,
and SQLSTATE, but typically no other fields.

Seems there is no alternative for Notice except to invent a new callback
level :-(.  PQnoticeProcessor API doesn't get the job done.

	typedef PQnoticeReceiver (PGconn *conn, PGresult *res, void *arg);
	PQsetNoticeReceiver(conn, function, arg)

res will be a NONFATAL_ERROR result from which PQresultErrorField() calls
may be used to extract the individual fields.  Default version just gets
PQresultErrorMessage() and passes it to connection's noticeProcessor.

	PQsetErrorVerbosity(conn, PQERRORS_TERSE/DEFAULT/VERBOSE)

TERSE: single-line error (severity, primary text, and position only)
DEFAULT: above plus any detail, hint, or context fields (backwards compatible)
VERBOSE: all available data

* Transaction status inquiry; also access to ParameterStatus.  (Provide way to
get at server version unconditionally, so that apps do not need fallback code)

	enum PQtransactionStatus(conn)
	Returns PQTRANS_UNKNOWN, IDLE, INTRANS, INERROR
	UNKNOWN is returned if on pre-3.0 protocol or bad connection

	const char *PQparameterStatus(conn, const char *paramName)
		returns NULL if param not available, sets errmsg

	const char *PQserverVersion(conn)
		uses paramstatus if possible, else does query

	int PQprotocolVersion(conn)
		returns protocol major version (2 or 3)

* Representation of binary results?

	seems to just need some notes?  Old way is not too incompatible
	except for endianness issues.

* Extended query support: for the moment I'm just going to provide an
extension to allow access to out-of-line parameters and binary format.
Later maybe add some stuff to support separate Parse, Bind, Execute steps.

	PQexecParams(conn, const char *query,
		     int nParams,
		     Oid *paramTypes, -- may be NULL to leave all unspecified
		     char **paramValues,
		     int *paramLengths, -- may be NULL if all text
		     int *paramFormats, -- NULL means all text
		     int resultFormat)  -- zero or one

a NULL value of param[i] means that param is NULL, else it is pointer
to either null-terminated C string (if text) or binary value of length
paramLengths[i] (if binary).  Note paramLengths is not examined for
text-format params.  Semantics similar to PQexec, but cannot put multiple
commands into query string.  Note we don't allow per-column result format
selection, since we don't have a good way to tell the number of result
columns.

For asynchronous processing, also add PQsendQueryParams, with same parameters
but behaves similarly to PQsendQuery; follow with PQgetResult.

Each of these sends Parse/Bind/DescribePortal/Execute/Sync using unnamed stmt
and portal.  Will fail on old-protocol connections.

* Better COPY API

	COPY OUT and COPY IN PGresults now carry #cols and format info.
	(only if new-protocol conn, else return "zero cols")

	PQexec will cope with getting out of pre-existing COPY state (by
	discarding data or sending CopyDone)

	PQputline/PQputnbytes reject if not in COPY IN state, else they
	wrap the data as a CopyData message and send it.  It is up to
	application to send valid data for the COPY operation.

	int PQputCopyData(conn, const char *buffer, int nbytes, bool async)
	Functionally similar to PQputnbytes,
	but preferred for new coding
	Returns 1: data sent or queued
		0: data not sent, try again later (only if async is true)
		-1: trouble, use PQerrorMessage to find out why
	Do NOT send "\." as terminator.

	int PQputCopyEnd(conn, const char *error, bool async)
	Ends a COPY IN successfully if error is NULL, else makes it fail
	with given null-terminated string as the error message.
	Same return conventions as PQputCopyData.  After successful
	completion, call PQgetResult to check success or failure of COPY
	command.  (If doing async COPY, can wait in the usual way for
	PQgetResult to be ready.)

	PQgetCopyData(conn, char **buffer, bool async)
		returns a malloc'd chunk of data if successful
	Cases
		got some data
			return value is # bytes received
		data not yet avail (only in async case)
			return is 0, *buffer is NULL
		end of copy in operation (incl. error detected)
			return is -1, *buffer is NULL
			now call PQgetResult
	The returned buffer will be null-terminated, but this is only
	helpful for text copy.  The returned data always corresponds to
	one data row.

	PQendcopy: deprecated, but equivalent to PQputCopyEnd (if COPY IN
		state) followed by synchronous GetResult.

* Better FunctionCall API?

	nah, just deprecate in favor of invoking the function via
	PQexecParams().

* Access to Notification param field

	add a third field to PGnotify struct

* Access to source table's OID and column number in RowDescription,
  also per-column format codes

	Oid PQftable(const PGresult *res, int col)
	int PQftablecol(const PGresult *res, int col)
	int PQfformat(const PGresult *res, int col)

PQbinaryTuples is now deprecated in favor of looking at PQfformat.
PQbinaryTuples will return true only if all columns of the result
are binary format.

Mon, 02 Jun 2003 13:19:36 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Some quick notes about extending libpq for new protocol
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Monday 02 June 2003 10:19, Tom Lane wrote:
> * Better FunctionCall API?
>
> 	nah, just deprecate in favor of invoking the function via
> 	PQexecParams().
>

I'll admit -- the current state of PQfn is practically unuseable. However, the 
idea is pretty cool. I think it would be nice to have a direct function call 
mechanism that bypasses the parser.

Of course, I don't think I understand completely what PQexecParams would do... 
:-(

- -- 
Jonathan Gardner <jgardner@jonathangardner.net>
(was jgardn@alumni.washington.edu)
Live Free, Use Linux!
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQE+5KrhWgwF3QvpWNwRAjTlAKCUqaI77lEPxonGo2gR3c0e38lJuACeLzJe
2Sr1bewQmQT4B72bALFf9HQ=
=9SC8
-----END PGP SIGNATURE-----

Mon, 9 Jun 2003 08:42:25 -0700
Jonathan Gardner <jgardner@jonathangardner.net>
Re: Some quick notes about extending libpq for new protocol
Jonathan Gardner <jgardner@jonathangardner.net> writes:
> I'll admit -- the current state of PQfn is practically unuseable. However, the 
> idea is pretty cool. I think it would be nice to have a direct function call 
> mechanism that bypasses the parser.

The ability to prepare a "SELECT foo($1, $2, ...)" statement pretty much
eliminates any performance advantage that PQfn once had.  While I've not
had the opportunity to do performance tests, I'd think that a binary
BIND and EXECUTE of such a statement would be about on a par with
FunctionCall.

			regards, tom lane

Mon, 09 Jun 2003 11:46:57 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Some quick notes about extending libpq for new protocol 
Tom Lane writes:

> * Access to individual fields of an error/notice result; also some setting to
> determine how verbose PQerrorMessage is
>
> 	char *PQerrorField(conn, char fieldcode)
> 	char *PQresultErrorField(const PGresult *res, char fieldcode)
>
> fieldcode is as per the protocol spec.  NULL is returned if no such field in
> current result (this includes case where current result isn't an error).

In the old protocol there used to be support for more then one error
arriving, in which case they were concatenated.  What is happening with
that?

> 	PQsetErrorVerbosity(conn, PQERRORS_TERSE/DEFAULT/VERBOSE)
>
> TERSE: single-line error (severity, primary text, and position only)

Shouldn't the position be available as a separate field, so client
programs can do their own highlighting or whatnot?

> DEFAULT: above plus any detail, hint, or context fields (backwards compatible)
> VERBOSE: all available data

One more thing: It has always annoyed me that PQerrorMessage() returns the
text with a trailing newline.  Since we now redefined newlines to be
paragraph breaks, should this be changed (in a backward-compatible
fashion)?

-- 
Peter Eisentraut   peter_e@gmx.net


Mon, 16 Jun 2003 16:51:16 +0200 (CEST)
Peter Eisentraut <peter_e@gmx.net>
Re: Some quick notes about extending libpq for new
Peter Eisentraut <peter_e@gmx.net> writes:
> In the old protocol there used to be support for more then one error
> arriving, in which case they were concatenated.  What is happening with
> that?

That still works with respect to libpq's internally-generated errors,
which is as far as I know the only case that the concatenation was
actually useful for.

> Shouldn't the position be available as a separate field, so client
> programs can do their own highlighting or whatnot?

Yes, it is.  The question here is what the backwards-compatible
PQerrorMessage() call should produce.  Do you think position should
get left out of that?  My thought was that the "terse" form should
carry everything that is likely to fit on one line, and position
would usually fit on the same line with "syntax error".  Also, an app
that is using PQerrorMessage() rather than constructing its own
error message from the individual fields is likely not gonna do anything
as helpful as highlighting ...

> One more thing: It has always annoyed me that PQerrorMessage() returns the
> text with a trailing newline.  Since we now redefined newlines to be
> paragraph breaks, should this be changed (in a backward-compatible
> fashion)?

The backwards-compatible part *is* that PQerrorMessage() returns text
with a trailing newline.  If you fetch the individual fields, they don't
have trailing newlines.

			regards, tom lane

Mon, 16 Jun 2003 11:13:42 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Some quick notes about extending libpq for new protocol 