Commit 5ed27e35 authored by Tom Lane's avatar Tom Lane

Another round of protocol changes. Backend-to-frontend messages now all

have length words.  COPY OUT reimplemented per new protocol: it doesn't
need \. anymore, thank goodness.  COPY BINARY to/from frontend works,
at least as far as the backend is concerned --- libpq's PQgetline API
is not up to snuff, and will have to be replaced with something that is
null-safe.  libpq uses message length words for performance improvement
(no cycles wasted rescanning long messages), but not yet for error
recovery.
parent ca944bd2
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.119 2003/04/19 00:02:29 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.120 2003/04/22 00:08:06 tgl Exp $
-->
<chapter id="libpq">
......@@ -175,7 +175,8 @@ PGconn *PQconnectdb(const char *conninfo);
<term><literal>connect_timeout</literal></term>
<listitem>
<para>
Time space in seconds given to connection function. Zero or not set means infinite.
Maximum wait for connection, in seconds (write as a decimal integer
string). Zero or not specified means infinite.
</para>
</listitem>
</varlistentry>
......@@ -184,7 +185,7 @@ PGconn *PQconnectdb(const char *conninfo);
<term><literal>options</literal></term>
<listitem>
<para>
Configuration options to be sent to the server.
Command-line options to be sent to the server.
</para>
</listitem>
</varlistentry>
......@@ -252,8 +253,9 @@ PGconn *PQsetdbLogin(const char *pghost,
</para>
<para>
This is the predecessor of <function>PQconnectdb</function> with a fixed number
of parameters but the same functionality.
This is the predecessor of <function>PQconnectdb</function> with a fixed
number of parameters. It has the same functionality except that the
missing parameters cannot be specified in the call.
</para>
</listitem>
</varlistentry>
......@@ -274,8 +276,8 @@ PGconn *PQsetdb(char *pghost,
<para>
This is a macro that calls <function>PQsetdbLogin</function> with null pointers
for the <parameter>login</> and <parameter>pwd</> parameters. It is provided primarily
for backward compatibility with old programs.
for the <parameter>login</> and <parameter>pwd</> parameters. It is provided
for backward compatibility with very old programs.
</para>
</listitem>
</varlistentry>
......@@ -454,7 +456,7 @@ switch(PQstatus(conn))
</para>
<para>
Finally, these functions leave the socket in a nonblocking state as if
Finally, these functions leave the connection in a nonblocking state as if
<function>PQsetnonblocking</function> had been called.
</para>
</listitem>
......@@ -486,8 +488,6 @@ typedef struct
</para>
<para>
converts an escaped string representation of binary data into binary
data --- the reverse of <function>PQescapeBytea</function>.
Returns a connection options array. This may
be used to determine all possible <function>PQconnectdb</function> options and their
current default values. The return value points to an array of
......@@ -683,7 +683,7 @@ char *PQtty(const PGconn *conn);
<term><function>PQoptions</function></term>
<listitem>
<para>
Returns the configuration options passed in the connection request.
Returns the command-line options passed in the connection request.
<synopsis>
char *PQoptions(const PGconn *conn);
</synopsis>
......@@ -2047,13 +2047,13 @@ contains example functions that correctly handle the <command>COPY</command> pro
<term><function>PQgetlineAsync</function></term>
<listitem>
<para>
Reads a newline-terminated line of characters
Reads a row of COPY data
(transmitted by the server) into a buffer
without blocking.
<synopsis>
int PQgetlineAsync(PGconn *conn,
char *buffer,
int length);
int bufsize);
</synopsis>
</para>
......@@ -2070,24 +2070,27 @@ end-of-data signal is detected.
<para>
Unlike <function>PQgetline</function>, this function takes
responsibility for detecting end-of-data.
On each call, <function>PQgetlineAsync</function> will return data if a complete newline-
terminated data line is available in <application>libpq</>'s input buffer, or if the
incoming data line is too long to fit in the buffer offered by the caller.
Otherwise, no data is returned until the rest of the line arrives.
</para>
<para>
On each call, <function>PQgetlineAsync</function> will return data if a
complete data row is available in <application>libpq</>'s input buffer.
Otherwise, no data is returned until the rest of the row arrives.
The function returns -1 if the end-of-copy-data marker has been recognized,
or 0 if no data is available, or a positive number giving the number of
bytes of data returned. If -1 is returned, the caller must next call
<function>PQendcopy</function>, and then return to normal processing.
</para>
<para>
The data returned will not extend beyond a newline character. If possible
a whole line will be returned at one time. But if the buffer offered by
the caller is too small to hold a line sent by the server, then a partial
data line will be returned. This can be detected by testing whether the
last returned byte is <literal>\n</literal> or not.
The data returned will not extend beyond a data-row boundary. If possible
a whole row will be returned at one time. But if the buffer offered by
the caller is too small to hold a row sent by the server, then a partial
data row will be returned. With textual data this can be detected by testing
whether the last returned byte is <literal>\n</literal> or not. (In a binary
COPY, actual parsing of the COPY data format will be needed to make the
equivalent determination.)
The returned string is not null-terminated. (If you want to add a
terminating null, be sure to pass a <parameter>length</parameter> one smaller than the room
actually available.)
terminating null, be sure to pass a <parameter>bufsize</parameter> one smaller
than the room actually available.)
</para>
</listitem>
</varlistentry>
......@@ -2105,10 +2108,24 @@ int PQputline(PGconn *conn,
</para>
<para>
Note the application must explicitly send the two
characters <literal>\.</literal> on a final line to indicate to
the server that it has finished sending its data.
The COPY datastream sent by a series of calls to
<function>PQputline</function> has the same format as that returned by
<function>PQgetlineAsync</function>, except that applications are not
obliged to send exactly one data row per <function>PQputline</function>
call; it is okay to send a partial line or multiple lines per call.
</para>
<note>
<para>
Before <productname>PostgreSQL</productname> 7.4, it was necessary for the
application to explicitly send the two characters <literal>\.</literal> as a
final line to indicate to the server that it had finished sending COPY data.
While this still works, it is deprecated and the special meaning of
<literal>\.</literal> can be expected to be removed in a future release.
It is sufficient to call <function>PQendcopy</function> after having sent the
actual data.
</para>
</note>
</listitem>
</varlistentry>
......@@ -2126,9 +2143,9 @@ int PQputnbytes(PGconn *conn,
</para>
<para>
This is exactly like <function>PQputline</function>, except that the data buffer need
not be null-terminated since the number of bytes to send is
specified directly.
This is exactly like <function>PQputline</function>, except that the data
buffer need not be null-terminated since the number of bytes to send is
specified directly. Use this procedure when sending binary data.
</para>
</listitem>
</varlistentry>
......@@ -2147,11 +2164,12 @@ int PQendcopy(PGconn *conn);
sent to the server using <function>PQputline</function> or when the
last string has been received from the server
using <function>PGgetline</function>. It must be issued or the server
may get <quote>out of sync</quote> with the client. Upon
will get <quote>out of sync</quote> with the client. Upon
return from this function, the server is ready to
receive the next SQL command.
The return value is 0 on successful completion,
nonzero otherwise.
nonzero otherwise. (Use <function>PQerrorMessage</function> to retrieve
details if the return value is nonzero.)
</para>
<para>
......@@ -2187,7 +2205,6 @@ PQexec(conn, "COPY foo FROM STDIN;");
PQputline(conn, "3\thello world\t4.5\n");
PQputline(conn, "4\tgoodbye world\t7.11\n");
...
PQputline(conn, "\\.\n");
PQendcopy(conn);
</programlisting>
</para>
......
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.28 2003/04/19 00:02:29 tgl Exp $ -->
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.29 2003/04/22 00:08:06 tgl Exp $ -->
<chapter id="protocol">
<title>Frontend/Backend Protocol</title>
......@@ -3691,7 +3691,8 @@ Terminate (F)
<para>
This section describes the fields that may appear in ErrorResponse and
NoticeResponse messages. Each field type has a single-byte identification
token.
token. Note that any given field type should appear at most once per
message.
</para>
<VariableList>
......@@ -3863,7 +3864,29 @@ PasswordMessage now has a type byte.
<para>
COPY data is now encapsulated into CopyData and CopyDone messages. There
is a well-defined way to recover from errors during COPY.
is a well-defined way to recover from errors during COPY. The special
<quote><literal>\.</></quote> last line is not needed anymore, and is not sent
during COPY OUT.
(It is still recognized as a terminator during COPY IN, but its use is
deprecated and will eventually be removed.) Binary COPY is supported.
The CopyInResponse and CopyOutResponse messages carry a field indicating
whether the COPY operation is text or binary.
</para>
<para>
The CursorResponse ('<literal>P</>') message is no longer generated by
the backend.
</para>
<para>
The NotificationResponse ('<literal>A</>') message has an additional string
field, which is presently empty but may someday carry additional data passed
from the NOTIFY event sender.
</para>
<para>
The EmptyQueryResponse ('<literal>I</>') message used to include an empty
string parameter; this has been removed.
</para>
<note>
......
......@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.65 2002/09/04 20:31:08 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.66 2003/04/22 00:08:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -77,15 +77,18 @@ static void
printtup_setup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo)
{
/*
* Send portal name to frontend.
*
* If portal name not specified, use "blank" portal.
*/
if (portalName == NULL)
portalName = "blank";
pq_puttextmessage('P', portalName);
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
{
/*
* Send portal name to frontend (obsolete cruft, gone in proto 3.0)
*
* If portal name not specified, use "blank" portal.
*/
if (portalName == NULL)
portalName = "blank";
pq_puttextmessage('P', portalName);
}
/*
* if this is a retrieve, then we send back the tuple descriptor of
......@@ -98,8 +101,7 @@ printtup_setup(DestReceiver *self, int operation,
int i;
StringInfoData buf;
pq_beginmessage(&buf);
pq_sendbyte(&buf, 'T'); /* tuple descriptor message type */
pq_beginmessage(&buf, 'T'); /* tuple descriptor message type */
pq_sendint(&buf, natts, 2); /* # of attrs in tuples */
for (i = 0; i < natts; ++i)
......@@ -174,8 +176,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
/*
* tell the frontend to expect new tuple data (in ASCII style)
*/
pq_beginmessage(&buf);
pq_sendbyte(&buf, 'D');
pq_beginmessage(&buf, 'D');
/*
* send a bitmap of which attributes are not null
......@@ -388,8 +389,7 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
/*
* tell the frontend to expect new tuple data (in binary style)
*/
pq_beginmessage(&buf);
pq_sendbyte(&buf, 'B');
pq_beginmessage(&buf, 'B');
/*
* send a bitmap of which attributes are not null
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.92 2003/02/18 02:53:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.93 2003/04/22 00:08:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -847,10 +847,14 @@ NotifyMyFrontEnd(char *relname, int32 listenerPID)
{
StringInfoData buf;
pq_beginmessage(&buf);
pq_sendbyte(&buf, 'A');
pq_beginmessage(&buf, 'A');
pq_sendint(&buf, listenerPID, sizeof(int32));
pq_sendstring(&buf, relname);
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
/* XXX Add parameter string here later */
pq_sendstring(&buf, "");
}
pq_endmessage(&buf);
/*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.194 2003/04/19 20:36:03 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.195 2003/04/22 00:08:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -50,13 +50,6 @@
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
#define OCTVALUE(c) ((c) - '0')
/* Default line termination */
#ifndef WIN32
#define PGEOL "\n"
#else
#define PGEOL "\r\n"
#endif
/*
* Represents the different source/dest cases we need to worry about at
* the bottom level
......@@ -92,7 +85,7 @@ typedef enum EolType
/* non-export function prototypes */
static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
bool pipe, char *delim, char *null_print);
char *delim, char *null_print);
static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
char *delim, char *null_print);
static Oid GetInputFunction(Oid type);
......@@ -101,8 +94,7 @@ static char *CopyReadAttribute(const char *delim, CopyReadResult *result);
static void CopyAttributeOut(char *string, char *delim);
static List *CopyGetAttnums(Relation rel, List *attnamelist);
/* The trailing null is part of the signature */
static const char BinarySignature[] = "PGBCOPY\n\377\r\n";
static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0";
/*
* Static communication variables ... pretty grotty, but COPY has
......@@ -135,10 +127,11 @@ static int server_encoding;
*/
static void SendCopyBegin(bool binary);
static void ReceiveCopyBegin(bool binary);
static void SendCopyEnd(bool binary, bool pipe);
static void SendCopyEnd(bool binary);
static void CopySendData(void *databuf, int datasize);
static void CopySendString(const char *str);
static void CopySendChar(char c);
static void CopySendEndOfRow(bool binary);
static void CopyGetData(void *databuf, int datasize);
static int CopyGetChar(void);
#define CopyGetEof() (fe_eof)
......@@ -154,22 +147,32 @@ SendCopyBegin(bool binary)
{
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
pq_putbytes("H", 1); /* new way */
/* XXX grottiness needed for old protocol */
pq_startcopyout();
/* new way */
StringInfoData buf;
pq_beginmessage(&buf, 'H');
pq_sendbyte(&buf, binary ? 1 : 0);
pq_endmessage(&buf);
copy_dest = COPY_NEW_FE;
copy_msgbuf = makeStringInfo();
}
else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
{
pq_putbytes("H", 1); /* old way */
/* grottiness needed for old protocol */
/* old way */
if (binary)
elog(ERROR, "COPY BINARY is not supported to stdout or from stdin");
pq_putemptymessage('H');
/* grottiness needed for old COPY OUT protocol */
pq_startcopyout();
copy_dest = COPY_OLD_FE;
}
else
{
pq_putbytes("B", 1); /* very old way */
/* grottiness needed for old protocol */
/* very old way */
if (binary)
elog(ERROR, "COPY BINARY is not supported to stdout or from stdin");
pq_putemptymessage('B');
/* grottiness needed for old COPY OUT protocol */
pq_startcopyout();
copy_dest = COPY_OLD_FE;
}
......@@ -180,18 +183,29 @@ ReceiveCopyBegin(bool binary)
{
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
pq_putbytes("G", 1); /* new way */
/* new way */
StringInfoData buf;
pq_beginmessage(&buf, 'G');
pq_sendbyte(&buf, binary ? 1 : 0);
pq_endmessage(&buf);
copy_dest = COPY_NEW_FE;
copy_msgbuf = makeStringInfo();
}
else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
{
pq_putbytes("G", 1); /* old way */
/* old way */
if (binary)
elog(ERROR, "COPY BINARY is not supported to stdout or from stdin");
pq_putemptymessage('G');
copy_dest = COPY_OLD_FE;
}
else
{
pq_putbytes("D", 1); /* very old way */
/* very old way */
if (binary)
elog(ERROR, "COPY BINARY is not supported to stdout or from stdin");
pq_putemptymessage('D');
copy_dest = COPY_OLD_FE;
}
/* We *must* flush here to ensure FE knows it can send. */
......@@ -199,22 +213,39 @@ ReceiveCopyBegin(bool binary)
}
static void
SendCopyEnd(bool binary, bool pipe)
SendCopyEnd(bool binary)
{
if (!binary)
if (copy_dest == COPY_NEW_FE)
{
CopySendString("\\.");
CopySendString(!pipe ? PGEOL : "\n");
if (binary)
{
/* Need to flush out file trailer word */
CopySendEndOfRow(true);
}
else
{
/* Shouldn't have any unsent data */
Assert(copy_msgbuf->len == 0);
}
/* Send Copy Done message */
pq_putemptymessage('c');
}
else
{
/* The FE/BE protocol uses \n as newline for all platforms */
CopySendData("\\.\n", 3);
pq_endcopyout(false);
}
pq_endcopyout(false);
}
/*
/*----------
* CopySendData sends output data to the destination (file or frontend)
* CopySendString does the same for null-terminated strings
* CopySendChar does the same for single characters
* CopySendEndOfRow does the appropriate thing at end of each data row
*
* NB: no data conversion is applied by these functions
*----------
*/
static void
CopySendData(void *databuf, int datasize)
......@@ -228,12 +259,13 @@ CopySendData(void *databuf, int datasize)
break;
case COPY_OLD_FE:
if (pq_putbytes((char *) databuf, datasize))
fe_eof = true;
{
/* no hope of recovering connection sync, so FATAL */
elog(FATAL, "CopySendData: connection lost");
}
break;
case COPY_NEW_FE:
/* XXX fix later */
if (pq_putbytes((char *) databuf, datasize))
fe_eof = true;
appendBinaryStringInfo(copy_msgbuf, (char *) databuf, datasize);
break;
}
}
......@@ -250,6 +282,40 @@ CopySendChar(char c)
CopySendData(&c, 1);
}
static void
CopySendEndOfRow(bool binary)
{
switch (copy_dest)
{
case COPY_FILE:
if (!binary)
{
/* Default line termination depends on platform */
#ifndef WIN32
CopySendChar('\n');
#else
CopySendString("\r\n");
#endif
}
break;
case COPY_OLD_FE:
/* The FE/BE protocol uses \n as newline for all platforms */
if (!binary)
CopySendChar('\n');
break;
case COPY_NEW_FE:
/* The FE/BE protocol uses \n as newline for all platforms */
if (!binary)
CopySendChar('\n');
/* Dump the accumulated row as one CopyData message */
(void) pq_putmessage('d', copy_msgbuf->data, copy_msgbuf->len);
/* Reset copy_msgbuf to empty */
copy_msgbuf->len = 0;
copy_msgbuf->data[0] = '\0';
break;
}
}
/*
* CopyGetData reads data from the source (file or frontend)
* CopyGetChar does the same for single characters
......@@ -568,13 +634,6 @@ DoCopy(const CopyStmt *stmt)
"directly to or from a file. Anyone can COPY to stdout or "
"from stdin. Psql's \\copy command also works for anyone.");
/*
* This restriction is unfortunate, but necessary until the frontend
* COPY protocol is redesigned to be binary-safe...
*/
if (pipe && binary)
elog(ERROR, "COPY BINARY is not supported to stdout or from stdin");
/*
* Presently, only single-character delimiter strings are supported.
*/
......@@ -698,13 +757,13 @@ DoCopy(const CopyStmt *stmt)
elog(ERROR, "COPY: %s is a directory", filename);
}
}
CopyTo(rel, attnumlist, binary, oids, pipe, delim, null_print);
CopyTo(rel, attnumlist, binary, oids, delim, null_print);
}
if (!pipe)
FreeFile(copy_file);
else if (IsUnderPostmaster && !is_from)
SendCopyEnd(binary, pipe);
SendCopyEnd(binary);
pfree(attribute_buf.data);
/*
......@@ -721,7 +780,7 @@ DoCopy(const CopyStmt *stmt)
* Copy from relation TO file.
*/
static void
CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, bool pipe,
CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
char *delim, char *null_print)
{
HeapTuple tuple;
......@@ -786,7 +845,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, bool pipe,
int32 tmp;
/* Signature */
CopySendData((char *) BinarySignature, sizeof(BinarySignature));
CopySendData((char *) BinarySignature, 12);
/* Integer layout field */
tmp = 0x01020304;
CopySendData(&tmp, sizeof(int32));
......@@ -918,8 +977,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, bool pipe,
}
}
if (!binary)
CopySendString(!pipe ? PGEOL : "\n");
CopySendEndOfRow(binary);
MemoryContextSwitchTo(oldcontext);
}
......@@ -1100,8 +1158,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
/* Signature */
CopyGetData(readSig, 12);
if (CopyGetEof() || memcmp(readSig, BinarySignature,
sizeof(BinarySignature)) != 0)
if (CopyGetEof() || memcmp(readSig, BinarySignature, 12) != 0)
elog(ERROR, "COPY BINARY: file signature not recognized");
/* Integer layout field */
CopyGetData(&tmp, sizeof(int32));
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.99 2003/04/19 00:02:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.100 2003/04/22 00:08:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -512,8 +512,7 @@ sendAuthRequest(Port *port, AuthRequest areq)
{
StringInfoData buf;
pq_beginmessage(&buf);
pq_sendbyte(&buf, 'R');
pq_beginmessage(&buf, 'R');
pq_sendint(&buf, (int32) areq, sizeof(int32));
/* Add the salt for encrypted passwords. */
......
......@@ -12,15 +12,16 @@
* No other messages can be sent while COPY OUT is in progress; and if the
* copy is aborted by an elog(ERROR), we need to close out the copy so that
* the frontend gets back into sync. Therefore, these routines have to be
* aware of COPY OUT state.
* aware of COPY OUT state. (New COPY-OUT is message-based and does *not*
* set the DoingCopyOut flag.)
*
* NOTE: generally, it's a bad idea to emit outgoing messages directly with
* pq_putbytes(), especially if the message would require multiple calls
* to send. Instead, use the routines in pqformat.c to construct the message
* in a buffer and then emit it in one call to pq_putmessage. This helps
* ensure that the channel will not be clogged by an incomplete message
* if execution is aborted by elog(ERROR) partway through the message.
* The only non-libpq code that should call pq_putbytes directly is COPY OUT.
* in a buffer and then emit it in one call to pq_putmessage. This ensures
* that the channel will not be clogged by an incomplete message if execution
* is aborted by elog(ERROR) partway through the message. The only non-libpq
* code that should call pq_putbytes directly is old-style COPY OUT.
*
* At one time, libpq was shared between frontend and backend, but now
* the backend's "backend/libpq" is quite separate from "interfaces/libpq".
......@@ -29,7 +30,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.150 2003/04/19 00:02:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.151 2003/04/22 00:08:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -846,13 +847,17 @@ pq_flush(void)
* pq_putmessage - send a normal message (suppressed in COPY OUT mode)
*
* If msgtype is not '\0', it is a message type code to place before
* the message body (len counts only the body size!).
* If msgtype is '\0', then the buffer already includes the type code.
* the message body. If msgtype is '\0', then the message has no type
* code (this is only valid in pre-3.0 protocols).
*
* All normal messages are suppressed while COPY OUT is in progress.
* (In practice only a few messages might get emitted then; dropping
* them is annoying, but at least they will still appear in the
* postmaster log.)
* len is the length of the message body data at *s. In protocol 3.0
* and later, a message length word (equal to len+4 because it counts
* itself too) is inserted by this routine.
*
* All normal messages are suppressed while old-style COPY OUT is in
* progress. (In practice only a few notice messages might get emitted
* then; dropping them is annoying, but at least they will still appear
* in the postmaster log.)
*
* returns 0 if OK, EOF if trouble
* --------------------------------
......@@ -865,6 +870,14 @@ pq_putmessage(char msgtype, const char *s, size_t len)
if (msgtype)
if (pq_putbytes(&msgtype, 1))
return EOF;
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
uint32 n32;
n32 = htonl((uint32) (len + 4));
if (pq_putbytes((char *) &n32, 4))
return EOF;
}
return pq_putbytes(s, len);
}
......@@ -880,12 +893,13 @@ pq_startcopyout(void)
}
/* --------------------------------
* pq_endcopyout - end a COPY OUT transfer
* pq_endcopyout - end an old-style COPY OUT transfer
*
* If errorAbort is indicated, we are aborting a COPY OUT due to an error,
* and must send a terminator line. Since a partial data line might have
* been emitted, send a couple of newlines first (the first one could
* get absorbed by a backslash...)
* get absorbed by a backslash...) Note that old-style COPY OUT does
* not allow binary transfers, so a textual terminator is always correct.
* --------------------------------
*/
void
......@@ -893,8 +907,8 @@ pq_endcopyout(bool errorAbort)
{
if (!DoingCopyOut)
return;
DoingCopyOut = false;
if (errorAbort)
pq_putbytes("\n\n\\.\n", 5);
/* in non-error case, copy.c will have emitted the terminator line */
DoingCopyOut = false;
}
......@@ -18,7 +18,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.27 2003/04/19 00:02:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.28 2003/04/22 00:08:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -38,6 +38,7 @@
*
* Special-case message output:
* pq_puttextmessage - generate a character set-converted message in one step
* pq_putemptymessage - convenience routine for message with empty body
*
* Message parsing after input:
* pq_getmsgbyte - get a raw byte from a message buffer
......@@ -63,6 +64,22 @@
#include "mb/pg_wchar.h"
/* --------------------------------
* pq_beginmessage - initialize for sending a message
* --------------------------------
*/
void
pq_beginmessage(StringInfo buf, char msgtype)
{
initStringInfo(buf);
/*
* We stash the message type into the buffer's cursor field, expecting
* that the pq_sendXXX routines won't touch it. We could alternatively
* make it the first byte of the buffer contents, but this seems easier.
*/
buf->cursor = msgtype;
}
/* --------------------------------
* pq_sendbyte - append a raw byte to a StringInfo buffer
* --------------------------------
......@@ -176,7 +193,8 @@ pq_sendint(StringInfo buf, int i, int b)
void
pq_endmessage(StringInfo buf)
{
(void) pq_putmessage('\0', buf->data, buf->len);
/* msgtype was saved in cursor field */
(void) pq_putmessage(buf->cursor, buf->data, buf->len);
/* no need to complain about any failure, since pqcomm.c already did */
pfree(buf->data);
buf->data = NULL;
......@@ -188,11 +206,9 @@ pq_endmessage(StringInfo buf)
* This is the same as the pqcomm.c routine pq_putmessage, except that
* the message body is a null-terminated string to which encoding
* conversion applies.
*
* returns 0 if OK, EOF if trouble
* --------------------------------
*/
int
void
pq_puttextmessage(char msgtype, const char *str)
{
int slen = strlen(str);
......@@ -201,12 +217,22 @@ pq_puttextmessage(char msgtype, const char *str)
p = (char *) pg_server_to_client((unsigned char *) str, slen);
if (p != str) /* actual conversion has been done? */
{
int result = pq_putmessage(msgtype, p, strlen(p) + 1);
(void) pq_putmessage(msgtype, p, strlen(p) + 1);
pfree(p);
return result;
return;
}
return pq_putmessage(msgtype, str, slen + 1);
(void) pq_putmessage(msgtype, str, slen + 1);
}
/* --------------------------------
* pq_putemptymessage - convenience routine for message with empty body
* --------------------------------
*/
void
pq_putemptymessage(char msgtype)
{
(void) pq_putmessage(msgtype, NULL, 0);
}
......
......@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.313 2003/04/19 00:02:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.314 2003/04/22 00:08:06 tgl Exp $
*
* NOTES
*
......@@ -1118,7 +1118,13 @@ ProcessStartupPacket(Port *port, bool SSLdone)
if (pq_getbytes((char *) &len, 4) == EOF)
{
elog(COMMERROR, "incomplete startup packet");
/*
* EOF after SSLdone probably means the client didn't like our
* response to NEGOTIATE_SSL_CODE. That's not an error condition,
* so don't clutter the log with a complaint.
*/
if (!SSLdone)
elog(COMMERROR, "incomplete startup packet");
return STATUS_ERROR;
}
......@@ -1127,7 +1133,10 @@ ProcessStartupPacket(Port *port, bool SSLdone)
if (len < (int32) sizeof(ProtocolVersion) ||
len > MAX_STARTUP_PACKET_LENGTH)
elog(FATAL, "invalid length of startup packet");
{
elog(COMMERROR, "invalid length of startup packet");
return STATUS_ERROR;
}
/*
* Allocate at least the size of an old-style startup packet, plus one
......@@ -1173,7 +1182,7 @@ ProcessStartupPacket(Port *port, bool SSLdone)
#endif
if (send(port->sock, &SSLok, 1, 0) != 1)
{
elog(LOG, "failed to send SSL negotiation response: %m");
elog(COMMERROR, "failed to send SSL negotiation response: %m");
return STATUS_ERROR; /* close the connection */
}
......@@ -1188,6 +1197,11 @@ ProcessStartupPacket(Port *port, bool SSLdone)
/* Could add additional special packet types here */
/*
* Set FrontendProtocol now so that elog() knows what format to send
* if we fail during startup.
*/
FrontendProtocol = proto;
/*
* XXX temporary for 3.0 protocol development: we are using the minor
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.52 2003/04/19 00:02:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.53 2003/04/22 00:08:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -141,7 +141,9 @@ EndCommand(const char *commandTag, CommandDest dest)
* libpq's crufty way of determining whether a multiple-command
* query string is done. In protocol 2.0 it's probably not really
* necessary to distinguish empty queries anymore, but we still do it
* for backwards compatibility with 1.0.
* for backwards compatibility with 1.0. In protocol 3.0 it has some
* use again, since it ensures that there will be a recognizable end
* to the response to an Execute message.
* ----------------
*/
void
......@@ -153,9 +155,13 @@ NullCommand(CommandDest dest)
case Remote:
/*
* tell the fe that we saw an empty query string
* tell the fe that we saw an empty query string. In protocols
* before 3.0 this has a useless empty-string message body.
*/
pq_putbytes("I", 2); /* note we send I and \0 */
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
pq_putemptymessage('I');
else
pq_puttextmessage('I', "");
break;
case Debug:
......@@ -184,7 +190,7 @@ ReadyForQuery(CommandDest dest)
case RemoteInternal:
case Remote:
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
pq_putbytes("Z", 1);
pq_putemptymessage('Z');
/* Flush output at end of cycle in any case. */
pq_flush();
break;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.58 2003/04/19 00:02:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.59 2003/04/22 00:08:07 tgl Exp $
*
* NOTES
* This cruft is the server side of PQfn.
......@@ -119,8 +119,7 @@ SendFunctionResult(Datum retval, bool retbyval, int retlen)
{
StringInfoData buf;
pq_beginmessage(&buf);
pq_sendbyte(&buf, 'V');
pq_beginmessage(&buf, 'V');
if (retlen != 0)
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.322 2003/04/19 00:02:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.323 2003/04/22 00:08:07 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
......@@ -1821,8 +1821,7 @@ PostgresMain(int argc, char *argv[], const char *username)
{
StringInfoData buf;
pq_beginmessage(&buf);
pq_sendbyte(&buf, 'K');
pq_beginmessage(&buf, 'K');
pq_sendint(&buf, (int32) MyProcPid, sizeof(int32));
pq_sendint(&buf, (int32) MyCancelKey, sizeof(int32));
pq_endmessage(&buf);
......@@ -1832,7 +1831,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.322 $ $Date: 2003/04/19 00:02:29 $\n");
puts("$Revision: 1.323 $ $Date: 2003/04/22 00:08:07 $\n");
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.107 2003/03/20 03:34:56 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.108 2003/04/22 00:08:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -406,20 +406,19 @@ elog(int lev, const char *fmt,...)
*/
oldcxt = MemoryContextSwitchTo(ErrorContext);
if (lev <= WARNING)
/* exclude the timestamp from msg sent to frontend */
send_message_to_frontend(lev, msg_buf + timestamp_size);
else
if (lev >= ERROR)
{
/*
* Abort any COPY OUT in progress when an error is detected.
* This hack is necessary because of poor design of copy
* protocol.
* This hack is necessary because of poor design of old-style
* copy protocol.
*/
pq_endcopyout(true);
send_message_to_frontend(ERROR, msg_buf + timestamp_size);
}
/* Exclude the timestamp from msg sent to frontend */
send_message_to_frontend(lev, msg_buf + timestamp_size);
MemoryContextSwitchTo(oldcxt);
}
......@@ -745,11 +744,9 @@ send_message_to_frontend(int type, const char *msg)
{
StringInfoData buf;
AssertArg(type <= ERROR);
pq_beginmessage(&buf);
/* 'N' (Notice) is for nonfatal conditions, 'E' is for errors */
pq_sendbyte(&buf, type < ERROR ? 'N' : 'E');
pq_beginmessage(&buf, (type < ERROR) ? 'N' : 'E');
/* XXX more to do here */
pq_sendstring(&buf, msg);
pq_endmessage(&buf);
......
......@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pqcomm.h,v 1.77 2003/04/19 00:02:29 tgl Exp $
* $Id: pqcomm.h,v 1.78 2003/04/22 00:08:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -106,7 +106,7 @@ typedef union SockAddr
/* The earliest and latest frontend/backend protocol version supported. */
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0)
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,101) /* XXX temporary value */
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,102) /* XXX temporary value */
typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pqformat.h,v 1.14 2003/04/19 00:02:29 tgl Exp $
* $Id: pqformat.h,v 1.15 2003/04/22 00:08:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -15,8 +15,7 @@
#include "lib/stringinfo.h"
#define pq_beginmessage(buf) initStringInfo(buf)
extern void pq_beginmessage(StringInfo buf, char msgtype);
extern void pq_sendbyte(StringInfo buf, int byt);
extern void pq_sendbytes(StringInfo buf, const char *data, int datalen);
extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen);
......@@ -24,7 +23,8 @@ extern void pq_sendstring(StringInfo buf, const char *str);
extern void pq_sendint(StringInfo buf, int i, int b);
extern void pq_endmessage(StringInfo buf);
extern int pq_puttextmessage(char msgtype, const char *str);
extern void pq_puttextmessage(char msgtype, const char *str);
extern void pq_putemptymessage(char msgtype);
extern int pq_getmsgbyte(StringInfo msg);
extern unsigned int pq_getmsgint(StringInfo msg, int b);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.233 2003/04/19 00:02:30 tgl Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.234 2003/04/22 00:08:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1328,6 +1328,8 @@ keep_going: /* We will come back to here until there
case CONNECTION_AWAITING_RESPONSE:
{
char beresp;
int msgLength;
int avail;
AuthRequest areq;
/*
......@@ -1337,15 +1339,58 @@ keep_going: /* We will come back to here until there
*/
conn->inCursor = conn->inStart;
/* Read type byte */
if (pqGetc(&beresp, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/* Handle errors. */
if (beresp == 'E')
/*
* Validate message type: we expect only an authentication
* request or an error here. Anything else probably means
* it's not Postgres on the other end at all.
*/
if (!(beresp == 'R' || beresp == 'E'))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
"server, but received %c\n"
),
beresp);
goto error_return;
}
/* Read message length word */
if (pqGetInt(&msgLength, 4, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/*
* Try to validate message length before using it.
* Authentication requests can't be very large. Errors
* can be a little larger, but not huge. If we see a large
* apparent length in an error, it means we're really talking
* to a pre-3.0-protocol server; cope.
*/
if (beresp == 'R' && (msgLength < 8 || msgLength > 100))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
"server, but received %c\n"
),
beresp);
goto error_return;
}
if (beresp == 'E' && (msgLength < 8 || msgLength > 30000))
{
/* Handle error from a pre-3.0 server */
conn->inCursor = conn->inStart + 1; /* reread data */
if (pqGets(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
......@@ -1363,18 +1408,45 @@ keep_going: /* We will come back to here until there
goto error_return;
}
/* Otherwise it should be an authentication request. */
if (beresp != 'R')
/*
* Can't process if message body isn't all here yet.
*/
msgLength -= 4;
avail = conn->inEnd - conn->inCursor;
if (avail < msgLength)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
"server, but received %c\n"
),
beresp);
/*
* Before returning, try to enlarge the input buffer if
* needed to hold the whole message; see notes in
* parseInput.
*/
if (pqCheckInBufferSpace(conn->inCursor + msgLength, conn))
goto error_return;
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/* Handle errors. */
if (beresp == 'E')
{
if (pqGets(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/* OK, we read the message; mark data consumed */
conn->inStart = conn->inCursor;
/*
* The postmaster typically won't end its message with
* a newline, so add one to conform to libpq
* conventions.
*/
appendPQExpBufferChar(&conn->errorMessage, '\n');
goto error_return;
}
/* It is an authentication request. */
/* Get the type of request. */
if (pqGetInt((int *) &areq, 4, conn))
{
......
This diff is collapsed.
......@@ -23,7 +23,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.89 2003/04/19 00:02:30 tgl Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.90 2003/04/22 00:08:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -277,12 +277,12 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
/*
* Make sure conn's output buffer can hold bytes_needed bytes (caller must
* include existing outCount into the value!)
* include already-stored data into the value!)
*
* Returns 0 on success, EOF on error
* Returns 0 on success, EOF if failed to enlarge buffer
*/
static int
checkOutBufferSpace(int bytes_needed, PGconn *conn)
pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
{
int newsize = conn->outBufSize;
char *newbuf;
......@@ -335,6 +335,66 @@ checkOutBufferSpace(int bytes_needed, PGconn *conn)
return EOF;
}
/*
* Make sure conn's input buffer can hold bytes_needed bytes (caller must
* include already-stored data into the value!)
*
* Returns 0 on success, EOF if failed to enlarge buffer
*/
int
pqCheckInBufferSpace(int bytes_needed, PGconn *conn)
{
int newsize = conn->inBufSize;
char *newbuf;
if (bytes_needed <= newsize)
return 0;
/*
* If we need to enlarge the buffer, we first try to double it in size;
* if that doesn't work, enlarge in multiples of 8K. This avoids
* thrashing the malloc pool by repeated small enlargements.
*
* Note: tests for newsize > 0 are to catch integer overflow.
*/
do {
newsize *= 2;
} while (bytes_needed > newsize && newsize > 0);
if (bytes_needed <= newsize)
{
newbuf = realloc(conn->inBuffer, newsize);
if (newbuf)
{
/* realloc succeeded */
conn->inBuffer = newbuf;
conn->inBufSize = newsize;
return 0;
}
}
newsize = conn->inBufSize;
do {
newsize += 8192;
} while (bytes_needed > newsize && newsize > 0);
if (bytes_needed <= newsize)
{
newbuf = realloc(conn->inBuffer, newsize);
if (newbuf)
{
/* realloc succeeded */
conn->inBuffer = newbuf;
conn->inBufSize = newsize;
return 0;
}
}
/* realloc failed. Probably out of memory */
printfPQExpBuffer(&conn->errorMessage,
"cannot allocate memory for input buffer\n");
return EOF;
}
/*
* pqPutMsgStart: begin construction of a message to the server
*
......@@ -364,7 +424,7 @@ pqPutMsgStart(char msg_type, PGconn *conn)
else
lenPos = conn->outCount;
/* make sure there is room for it */
if (checkOutBufferSpace(lenPos + 4, conn))
if (pqCheckOutBufferSpace(lenPos + 4, conn))
return EOF;
/* okay, save the message type byte if any */
if (msg_type)
......@@ -390,7 +450,7 @@ static int
pqPutMsgBytes(const void *buf, size_t len, PGconn *conn)
{
/* make sure there is room for it */
if (checkOutBufferSpace(conn->outMsgEnd + len, conn))
if (pqCheckOutBufferSpace(conn->outMsgEnd + len, conn))
return EOF;
/* okay, save the data */
memcpy(conn->outBuffer + conn->outMsgEnd, buf, len);
......@@ -486,13 +546,13 @@ pqReadData(PGconn *conn)
*/
if (conn->inBufSize - conn->inEnd < 8192)
{
int newSize = conn->inBufSize * 2;
char *newBuf = (char *) realloc(conn->inBuffer, newSize);
if (newBuf)
if (pqCheckInBufferSpace(conn->inEnd + 8192, conn))
{
conn->inBuffer = newBuf;
conn->inBufSize = newSize;
/*
* We don't insist that the enlarge worked, but we need some room
*/
if (conn->inBufSize - conn->inEnd < 100)
return -1; /* errorMessage already set */
}
}
......
......@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq-int.h,v 1.62 2003/04/19 00:02:30 tgl Exp $
* $Id: libpq-int.h,v 1.63 2003/04/22 00:08:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
* pqcomm.h describe what the backend knows, not what libpq knows.
*/
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,101) /* XXX temporary value */
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,102) /* XXX temporary value */
/*
* POSTGRES backend dependent Constants.
......@@ -216,7 +216,8 @@ struct pg_conn
* is listening on; if NULL, uses a
* default constructed from pgport */
char *pgtty; /* tty on which the backend messages is
* displayed (NOT ACTUALLY USED???) */
* displayed (OBSOLETE, NOT USED) */
char *connect_timeout; /* connection timeout (numeric string) */
char *pgoptions; /* options to start the backend with */
char *dbName; /* database name */
char *pguser; /* Postgres username and password, if any */
......@@ -232,6 +233,10 @@ struct pg_conn
/* Status indicators */
ConnStatusType status;
PGAsyncStatusType asyncStatus;
char copy_is_binary; /* 1 = copy binary, 0 = copy text */
int copy_already_done; /* # bytes already returned in COPY OUT */
int nonblocking; /* whether this connection is using a
* blocking socket to the backend or not */
Dllist *notifyList; /* Notify msgs not yet handed to
* application */
......@@ -246,6 +251,7 @@ struct pg_conn
int be_key; /* key of backend --- needed for cancels */
char md5Salt[4]; /* password salt received from backend */
char cryptSalt[2]; /* password salt received from backend */
int client_encoding; /* encoding id */
PGlobjfuncs *lobjfuncs; /* private state for large-object access
* fns */
......@@ -258,9 +264,6 @@ struct pg_conn
int inEnd; /* offset to first position after avail
* data */
int nonblocking; /* whether this connection is using a
* blocking socket to the backend or not */
/* Buffer for data not yet sent to backend */
char *outBuffer; /* currently allocated buffer */
int outBufSize; /* allocated size of buffer */
......@@ -291,10 +294,6 @@ struct pg_conn
/* Buffer for receiving various parts of messages */
PQExpBufferData workBuffer; /* expansible string */
int client_encoding; /* encoding id */
char *connect_timeout;
};
/* String descriptions of the ExecStatusTypes.
......@@ -330,6 +329,7 @@ extern void pqClearAsyncResult(PGconn *conn);
* for Get, EOF merely means the buffer is exhausted, not that there is
* necessarily any error.
*/
extern int pqCheckInBufferSpace(int bytes_needed, PGconn *conn);
extern int pqGetc(char *result, PGconn *conn);
extern int pqPutc(char c, PGconn *conn);
extern int pqGets(PQExpBuffer buf, PGconn *conn);
......
......@@ -995,7 +995,6 @@ copy test("........pg.dropped.1........") to stdout;
ERROR: Relation "test" has no column "........pg.dropped.1........"
copy test from stdin;
ERROR: copy: line 1, Extra data after last expected column
lost synchronization with server, resetting connection
SET autocommit TO 'on';
select * from test;
b | c
......
......@@ -35,17 +35,13 @@ ERROR: Attribute "d" specified more than once
-- missing data: should fail
COPY x from stdin;
ERROR: copy: line 1, pg_atoi: zero-length string
lost synchronization with server, resetting connection
COPY x from stdin;
ERROR: copy: line 1, Missing data for column "e"
lost synchronization with server, resetting connection
COPY x from stdin;
ERROR: copy: line 1, Missing data for column "e"
lost synchronization with server, resetting connection
-- extra data: should fail
COPY x from stdin;
ERROR: copy: line 1, Extra data after last expected column
lost synchronization with server, resetting connection
SET autocommit TO 'on';
-- various COPY options: delimiters, oids, NULL string
COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x';
......
......@@ -40,7 +40,6 @@ INSERT INTO basictest values ('88', 'haha', 'short', '123.1212'); -- Truncate
-- Test copy
COPY basictest (testvarchar) FROM stdin; -- fail
ERROR: copy: line 1, value too long for type character varying(5)
lost synchronization with server, resetting connection
SET autocommit TO 'on';
COPY basictest (testvarchar) FROM stdin;
select * from basictest;
......@@ -128,12 +127,10 @@ INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
-- Test copy
COPY nulltest FROM stdin; --fail
ERROR: copy: line 1, Domain dcheck does not allow NULL values
lost synchronization with server, resetting connection
SET autocommit TO 'on';
-- Last row is bad
COPY nulltest FROM stdin;
ERROR: copy: line 3, CopyFrom: rejected due to CHECK constraint "nulltest_col5" on "nulltest"
lost synchronization with server, resetting connection
select * from nulltest;
col1 | col2 | col3 | col4 | col5
------+------+------+------+------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment