aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/printtup.c248
-rw-r--r--src/backend/commands/async.c3
-rw-r--r--src/backend/commands/copyfrom.c7
-rw-r--r--src/backend/commands/copyfromparse.c83
-rw-r--r--src/backend/commands/copyto.c127
-rw-r--r--src/backend/libpq/auth.c80
-rw-r--r--src/backend/libpq/pqcomm.c215
-rw-r--r--src/backend/libpq/pqmq.c18
-rw-r--r--src/backend/postmaster/postmaster.c42
-rw-r--r--src/backend/tcop/dest.c22
-rw-r--r--src/backend/tcop/fastpath.c165
-rw-r--r--src/backend/tcop/postgres.c71
-rw-r--r--src/backend/utils/error/elog.c64
-rw-r--r--src/backend/utils/misc/guc.c6
-rw-r--r--src/bin/psql/common.c10
-rw-r--r--src/bin/psql/copy.c4
-rw-r--r--src/include/commands/copyfrom_internal.h3
-rw-r--r--src/include/libpq/libpq.h7
-rw-r--r--src/include/libpq/pqcomm.h33
-rw-r--r--src/include/tcop/fastpath.h1
-rw-r--r--src/include/utils/elog.h2
-rw-r--r--src/interfaces/libpq/Makefile1
-rw-r--r--src/interfaces/libpq/fe-auth.c8
-rw-r--r--src/interfaces/libpq/fe-connect.c160
-rw-r--r--src/interfaces/libpq/fe-exec.c231
-rw-r--r--src/interfaces/libpq/fe-lobj.c50
-rw-r--r--src/interfaces/libpq/fe-misc.c21
-rw-r--r--src/interfaces/libpq/fe-protocol2.c1610
-rw-r--r--src/interfaces/libpq/fe-protocol3.c6
-rw-r--r--src/interfaces/libpq/libpq-fe.h2
-rw-r--r--src/interfaces/libpq/libpq-int.h36
-rw-r--r--src/interfaces/libpq/nls.mk2
32 files changed, 287 insertions, 3051 deletions
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 4468480e9b3..54b539f6fb6 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -27,16 +27,9 @@
static void printtup_startup(DestReceiver *self, int operation,
TupleDesc typeinfo);
static bool printtup(TupleTableSlot *slot, DestReceiver *self);
-static bool printtup_20(TupleTableSlot *slot, DestReceiver *self);
-static bool printtup_internal_20(TupleTableSlot *slot, DestReceiver *self);
static void printtup_shutdown(DestReceiver *self);
static void printtup_destroy(DestReceiver *self);
-static void SendRowDescriptionCols_2(StringInfo buf, TupleDesc typeinfo,
- List *targetlist, int16 *formats);
-static void SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo,
- List *targetlist, int16 *formats);
-
/* ----------------------------------------------------------------
* printtup / debugtup support
* ----------------------------------------------------------------
@@ -112,19 +105,6 @@ SetRemoteDestReceiverParams(DestReceiver *self, Portal portal)
myState->pub.mydest == DestRemoteExecute);
myState->portal = portal;
-
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- {
- /*
- * In protocol 2.0 the Bind message does not exist, so there is no way
- * for the columns to have different print formats; it's sufficient to
- * look at the first one.
- */
- if (portal->formats && portal->formats[0] != 0)
- myState->pub.receiveSlot = printtup_internal_20;
- else
- myState->pub.receiveSlot = printtup_20;
- }
}
static void
@@ -149,21 +129,6 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
"printtup",
ALLOCSET_DEFAULT_SIZES);
- 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.
- */
- const char *portalName = portal->name;
-
- if (portalName == NULL || portalName[0] == '\0')
- portalName = "blank";
-
- pq_puttextmessage('P', portalName);
- }
-
/*
* If we are supposed to emit row descriptions, then send the tuple
* descriptor of the tuples.
@@ -202,31 +167,14 @@ SendRowDescriptionMessage(StringInfo buf, TupleDesc typeinfo,
List *targetlist, int16 *formats)
{
int natts = typeinfo->natts;
- int proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
+ int i;
+ ListCell *tlist_item = list_head(targetlist);
/* tuple descriptor message type */
pq_beginmessage_reuse(buf, 'T');
/* # of attrs in tuples */
pq_sendint16(buf, natts);
- if (proto >= 3)
- SendRowDescriptionCols_3(buf, typeinfo, targetlist, formats);
- else
- SendRowDescriptionCols_2(buf, typeinfo, targetlist, formats);
-
- pq_endmessage_reuse(buf);
-}
-
-/*
- * Send description for each column when using v3+ protocol
- */
-static void
-SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo, List *targetlist, int16 *formats)
-{
- int natts = typeinfo->natts;
- int i;
- ListCell *tlist_item = list_head(targetlist);
-
/*
* Preallocate memory for the entire message to be sent. That allows to
* use the significantly faster inline pqformat.h functions and to avoid
@@ -291,33 +239,8 @@ SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo, List *targetlist, i
pq_writeint32(buf, atttypmod);
pq_writeint16(buf, format);
}
-}
-
-/*
- * Send description for each column when using v2 protocol
- */
-static void
-SendRowDescriptionCols_2(StringInfo buf, TupleDesc typeinfo, List *targetlist, int16 *formats)
-{
- int natts = typeinfo->natts;
- int i;
-
- for (i = 0; i < natts; ++i)
- {
- Form_pg_attribute att = TupleDescAttr(typeinfo, i);
- Oid atttypid = att->atttypid;
- int32 atttypmod = att->atttypmod;
- /* If column is a domain, send the base type and typmod instead */
- atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
-
- pq_sendstring(buf, NameStr(att->attname));
- /* column ID only info appears in protocol 3.0 and up */
- pq_sendint32(buf, atttypid);
- pq_sendint16(buf, att->attlen);
- pq_sendint32(buf, atttypmod);
- /* format info only appears in protocol 3.0 and up */
- }
+ pq_endmessage_reuse(buf);
}
/*
@@ -371,7 +294,7 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
}
/* ----------------
- * printtup --- print a tuple in protocol 3.0
+ * printtup --- send a tuple to the client
* ----------------
*/
static bool
@@ -456,84 +379,6 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
}
/* ----------------
- * printtup_20 --- print a tuple in protocol 2.0
- * ----------------
- */
-static bool
-printtup_20(TupleTableSlot *slot, DestReceiver *self)
-{
- TupleDesc typeinfo = slot->tts_tupleDescriptor;
- DR_printtup *myState = (DR_printtup *) self;
- MemoryContext oldcontext;
- StringInfo buf = &myState->buf;
- int natts = typeinfo->natts;
- int i,
- j,
- k;
-
- /* Set or update my derived attribute info, if needed */
- if (myState->attrinfo != typeinfo || myState->nattrs != natts)
- printtup_prepare_info(myState, typeinfo, natts);
-
- /* Make sure the tuple is fully deconstructed */
- slot_getallattrs(slot);
-
- /* Switch into per-row context so we can recover memory below */
- oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
-
- /*
- * tell the frontend to expect new tuple data (in ASCII style)
- */
- pq_beginmessage_reuse(buf, 'D');
-
- /*
- * send a bitmap of which attributes are not null
- */
- j = 0;
- k = 1 << 7;
- for (i = 0; i < natts; ++i)
- {
- if (!slot->tts_isnull[i])
- j |= k; /* set bit if not null */
- k >>= 1;
- if (k == 0) /* end of byte? */
- {
- pq_sendint8(buf, j);
- j = 0;
- k = 1 << 7;
- }
- }
- if (k != (1 << 7)) /* flush last partial byte */
- pq_sendint8(buf, j);
-
- /*
- * send the attributes of this tuple
- */
- for (i = 0; i < natts; ++i)
- {
- PrinttupAttrInfo *thisState = myState->myinfo + i;
- Datum attr = slot->tts_values[i];
- char *outputstr;
-
- if (slot->tts_isnull[i])
- continue;
-
- Assert(thisState->format == 0);
-
- outputstr = OutputFunctionCall(&thisState->finfo, attr);
- pq_sendcountedtext(buf, outputstr, strlen(outputstr), true);
- }
-
- pq_endmessage_reuse(buf);
-
- /* Return to caller's context, and flush row's temporary memory */
- MemoryContextSwitchTo(oldcontext);
- MemoryContextReset(myState->tmpcontext);
-
- return true;
-}
-
-/* ----------------
* printtup_shutdown
* ----------------
*/
@@ -638,88 +483,3 @@ debugtup(TupleTableSlot *slot, DestReceiver *self)
return true;
}
-
-/* ----------------
- * printtup_internal_20 --- print a binary tuple in protocol 2.0
- *
- * We use a different message type, i.e. 'B' instead of 'D' to
- * indicate a tuple in internal (binary) form.
- *
- * This is largely same as printtup_20, except we use binary formatting.
- * ----------------
- */
-static bool
-printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
-{
- TupleDesc typeinfo = slot->tts_tupleDescriptor;
- DR_printtup *myState = (DR_printtup *) self;
- MemoryContext oldcontext;
- StringInfo buf = &myState->buf;
- int natts = typeinfo->natts;
- int i,
- j,
- k;
-
- /* Set or update my derived attribute info, if needed */
- if (myState->attrinfo != typeinfo || myState->nattrs != natts)
- printtup_prepare_info(myState, typeinfo, natts);
-
- /* Make sure the tuple is fully deconstructed */
- slot_getallattrs(slot);
-
- /* Switch into per-row context so we can recover memory below */
- oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
-
- /*
- * tell the frontend to expect new tuple data (in binary style)
- */
- pq_beginmessage_reuse(buf, 'B');
-
- /*
- * send a bitmap of which attributes are not null
- */
- j = 0;
- k = 1 << 7;
- for (i = 0; i < natts; ++i)
- {
- if (!slot->tts_isnull[i])
- j |= k; /* set bit if not null */
- k >>= 1;
- if (k == 0) /* end of byte? */
- {
- pq_sendint8(buf, j);
- j = 0;
- k = 1 << 7;
- }
- }
- if (k != (1 << 7)) /* flush last partial byte */
- pq_sendint8(buf, j);
-
- /*
- * send the attributes of this tuple
- */
- for (i = 0; i < natts; ++i)
- {
- PrinttupAttrInfo *thisState = myState->myinfo + i;
- Datum attr = slot->tts_values[i];
- bytea *outputbytes;
-
- if (slot->tts_isnull[i])
- continue;
-
- Assert(thisState->format == 1);
-
- outputbytes = SendFunctionCall(&thisState->finfo, attr);
- pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
- pq_sendbytes(buf, VARDATA(outputbytes),
- VARSIZE(outputbytes) - VARHDRSZ);
- }
-
- pq_endmessage_reuse(buf);
-
- /* Return to caller's context, and flush row's temporary memory */
- MemoryContextSwitchTo(oldcontext);
- MemoryContextReset(myState->tmpcontext);
-
- return true;
-}
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 42b232d98b1..4b16fb56825 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2311,8 +2311,7 @@ NotifyMyFrontEnd(const char *channel, const char *payload, int32 srcPid)
pq_beginmessage(&buf, 'A');
pq_sendint32(&buf, srcPid);
pq_sendstring(&buf, channel);
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
- pq_sendstring(&buf, payload);
+ pq_sendstring(&buf, payload);
pq_endmessage(&buf);
/*
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 796ca7b3f7b..f05e2d23476 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -1126,13 +1126,6 @@ CopyFrom(CopyFromState cstate)
MemoryContextSwitchTo(oldcontext);
- /*
- * In the old protocol, tell pqcomm that we can process normal protocol
- * messages again.
- */
- if (cstate->copy_src == COPY_OLD_FE)
- pq_endmsgread();
-
/* Execute AFTER STATEMENT insertion triggers */
ExecASInsertTriggers(estate, target_resultRelInfo, cstate->transition_capture);
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 315b16fd7af..ce24a1528bd 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -124,35 +124,19 @@ static int CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
void
ReceiveCopyBegin(CopyFromState cstate)
{
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
- {
- /* new way */
- StringInfoData buf;
- int natts = list_length(cstate->attnumlist);
- int16 format = (cstate->opts.binary ? 1 : 0);
- int i;
-
- pq_beginmessage(&buf, 'G');
- pq_sendbyte(&buf, format); /* overall format */
- pq_sendint16(&buf, natts);
- for (i = 0; i < natts; i++)
- pq_sendint16(&buf, format); /* per-column formats */
- pq_endmessage(&buf);
- cstate->copy_src = COPY_NEW_FE;
- cstate->fe_msgbuf = makeStringInfo();
- }
- else
- {
- /* old way */
- if (cstate->opts.binary)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("COPY BINARY is not supported to stdout or from stdin")));
- pq_putemptymessage('G');
- /* any error in old protocol will make us lose sync */
- pq_startmsgread();
- cstate->copy_src = COPY_OLD_FE;
- }
+ StringInfoData buf;
+ int natts = list_length(cstate->attnumlist);
+ int16 format = (cstate->opts.binary ? 1 : 0);
+ int i;
+
+ pq_beginmessage(&buf, 'G');
+ pq_sendbyte(&buf, format); /* overall format */
+ pq_sendint16(&buf, natts);
+ for (i = 0; i < natts; i++)
+ pq_sendint16(&buf, format); /* per-column formats */
+ pq_endmessage(&buf);
+ cstate->copy_src = COPY_FRONTEND;
+ cstate->fe_msgbuf = makeStringInfo();
/* We *must* flush here to ensure FE knows it can send. */
pq_flush();
}
@@ -228,25 +212,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
if (bytesread == 0)
cstate->reached_eof = true;
break;
- case COPY_OLD_FE:
-
- /*
- * We cannot read more than minread bytes (which in practice is 1)
- * because old protocol doesn't have any clear way of separating
- * the COPY stream from following data. This is slow, but not any
- * slower than the code path was originally, and we don't care
- * much anymore about the performance of old protocol.
- */
- if (pq_getbytes((char *) databuf, minread))
- {
- /* Only a \. terminator is legal EOF in old protocol */
- ereport(ERROR,
- (errcode(ERRCODE_CONNECTION_FAILURE),
- errmsg("unexpected EOF on client connection with an open transaction")));
- }
- bytesread = minread;
- break;
- case COPY_NEW_FE:
+ case COPY_FRONTEND:
while (maxread > 0 && bytesread < minread && !cstate->reached_eof)
{
int avail;
@@ -619,21 +585,16 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
if (fld_count == -1)
{
/*
- * Received EOF marker. In a V3-protocol copy, wait for the
- * protocol-level EOF, and complain if it doesn't come
- * immediately. This ensures that we correctly handle CopyFail,
- * if client chooses to send that now.
- *
- * Note that we MUST NOT try to read more data in an old-protocol
- * copy, since there is no protocol-level EOF marker then. We
- * could go either way for copy from file, but choose to throw
- * error if there's data after the EOF marker, for consistency
- * with the new-protocol case.
+ * Received EOF marker. Wait for the protocol-level EOF, and
+ * complain if it doesn't come immediately. In COPY FROM STDIN,
+ * this ensures that we correctly handle CopyFail, if client
+ * chooses to send that now. When copying from file, we could
+ * ignore the rest of the file like in text mode, but we choose to
+ * be consistent with the COPY FROM STDIN case.
*/
char dummy;
- if (cstate->copy_src != COPY_OLD_FE &&
- CopyReadBinaryData(cstate, &dummy, 1) > 0)
+ if (CopyReadBinaryData(cstate, &dummy, 1) > 0)
ereport(ERROR,
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
errmsg("received copy data after EOF marker")));
@@ -712,7 +673,7 @@ CopyReadLine(CopyFromState cstate)
* after \. up to the protocol end of copy data. (XXX maybe better
* not to treat \. as special?)
*/
- if (cstate->copy_src == COPY_NEW_FE)
+ if (cstate->copy_src == COPY_FRONTEND)
{
do
{
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index e04ec1e331b..46155015cfd 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -50,8 +50,7 @@
typedef enum CopyDest
{
COPY_FILE, /* to file (or a piped program) */
- COPY_OLD_FE, /* to frontend (2.0 protocol) */
- COPY_NEW_FE, /* to frontend (3.0 protocol) */
+ COPY_FRONTEND, /* to frontend */
} CopyDest;
/*
@@ -116,7 +115,6 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
/* non-export function prototypes */
static void EndCopy(CopyToState cstate);
static void ClosePipeToProgram(CopyToState cstate);
-static uint64 CopyTo(CopyToState cstate);
static void CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot);
static void CopyAttributeOutText(CopyToState cstate, char *string);
static void CopyAttributeOutCSV(CopyToState cstate, char *string,
@@ -140,53 +138,27 @@ static void CopySendInt16(CopyToState cstate, int16 val);
static void
SendCopyBegin(CopyToState cstate)
{
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
- {
- /* new way */
- StringInfoData buf;
- int natts = list_length(cstate->attnumlist);
- int16 format = (cstate->opts.binary ? 1 : 0);
- int i;
-
- pq_beginmessage(&buf, 'H');
- pq_sendbyte(&buf, format); /* overall format */
- pq_sendint16(&buf, natts);
- for (i = 0; i < natts; i++)
- pq_sendint16(&buf, format); /* per-column formats */
- pq_endmessage(&buf);
- cstate->copy_dest = COPY_NEW_FE;
- }
- else
- {
- /* old way */
- if (cstate->opts.binary)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("COPY BINARY is not supported to stdout or from stdin")));
- pq_putemptymessage('H');
- /* grottiness needed for old COPY OUT protocol */
- pq_startcopyout();
- cstate->copy_dest = COPY_OLD_FE;
- }
+ StringInfoData buf;
+ int natts = list_length(cstate->attnumlist);
+ int16 format = (cstate->opts.binary ? 1 : 0);
+ int i;
+
+ pq_beginmessage(&buf, 'H');
+ pq_sendbyte(&buf, format); /* overall format */
+ pq_sendint16(&buf, natts);
+ for (i = 0; i < natts; i++)
+ pq_sendint16(&buf, format); /* per-column formats */
+ pq_endmessage(&buf);
+ cstate->copy_dest = COPY_FRONTEND;
}
static void
SendCopyEnd(CopyToState cstate)
{
- if (cstate->copy_dest == COPY_NEW_FE)
- {
- /* Shouldn't have any unsent data */
- Assert(cstate->fe_msgbuf->len == 0);
- /* Send Copy Done message */
- pq_putemptymessage('c');
- }
- else
- {
- CopySendData(cstate, "\\.", 2);
- /* Need to flush out the trailer (this also appends a newline) */
- CopySendEndOfRow(cstate);
- pq_endcopyout(false);
- }
+ /* Shouldn't have any unsent data */
+ Assert(cstate->fe_msgbuf->len == 0);
+ /* Send Copy Done message */
+ pq_putemptymessage('c');
}
/*----------
@@ -268,20 +240,7 @@ CopySendEndOfRow(CopyToState cstate)
errmsg("could not write to COPY file: %m")));
}
break;
- case COPY_OLD_FE:
- /* The FE/BE protocol uses \n as newline for all platforms */
- if (!cstate->opts.binary)
- CopySendChar(cstate, '\n');
-
- if (pq_putbytes(fe_msgbuf->data, fe_msgbuf->len))
- {
- /* no hope of recovering connection sync, so FATAL */
- ereport(FATAL,
- (errcode(ERRCODE_CONNECTION_FAILURE),
- errmsg("connection lost during COPY to stdout")));
- }
- break;
- case COPY_NEW_FE:
+ case COPY_FRONTEND:
/* The FE/BE protocol uses \n as newline for all platforms */
if (!cstate->opts.binary)
CopySendChar(cstate, '\n');
@@ -780,42 +739,6 @@ BeginCopyTo(ParseState *pstate,
}
/*
- * This intermediate routine exists mainly to localize the effects of setjmp
- * so we don't need to plaster a lot of variables with "volatile".
- */
-uint64
-DoCopyTo(CopyToState cstate)
-{
- bool pipe = (cstate->filename == NULL);
- bool fe_copy = (pipe && whereToSendOutput == DestRemote);
- uint64 processed;
-
- PG_TRY();
- {
- if (fe_copy)
- SendCopyBegin(cstate);
-
- processed = CopyTo(cstate);
-
- if (fe_copy)
- SendCopyEnd(cstate);
- }
- PG_CATCH();
- {
- /*
- * Make sure we turn off old-style COPY OUT mode upon error. It is
- * okay to do this in all cases, since it does nothing if the mode is
- * not on.
- */
- pq_endcopyout(true);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- return processed;
-}
-
-/*
* Clean up storage and release resources for COPY TO.
*/
void
@@ -837,14 +760,19 @@ EndCopyTo(CopyToState cstate)
/*
* Copy from relation or query TO file.
*/
-static uint64
-CopyTo(CopyToState cstate)
+uint64
+DoCopyTo(CopyToState cstate)
{
+ bool pipe = (cstate->filename == NULL);
+ bool fe_copy = (pipe && whereToSendOutput == DestRemote);
TupleDesc tupDesc;
int num_phys_attrs;
ListCell *cur;
uint64 processed;
+ if (fe_copy)
+ SendCopyBegin(cstate);
+
if (cstate->rel)
tupDesc = RelationGetDescr(cstate->rel);
else
@@ -977,11 +905,14 @@ CopyTo(CopyToState cstate)
MemoryContextDelete(cstate->rowcontext);
+ if (fe_copy)
+ SendCopyEnd(cstate);
+
return processed;
}
/*
- * Emit one row during CopyTo().
+ * Emit one row during DoCopyTo().
*/
static void
CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index baa0712c0f7..994251e7d9d 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -653,35 +653,26 @@ static char *
recv_password_packet(Port *port)
{
StringInfoData buf;
+ int mtype;
pq_startmsgread();
- if (PG_PROTOCOL_MAJOR(port->proto) >= 3)
- {
- /* Expect 'p' message type */
- int mtype;
- mtype = pq_getbyte();
- if (mtype != 'p')
- {
- /*
- * If the client just disconnects without offering a password,
- * don't make a log entry. This is legal per protocol spec and in
- * fact commonly done by psql, so complaining just clutters the
- * log.
- */
- if (mtype != EOF)
- ereport(ERROR,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("expected password response, got message type %d",
- mtype)));
- return NULL; /* EOF or bad message type */
- }
- }
- else
+ /* Expect 'p' message type */
+ mtype = pq_getbyte();
+ if (mtype != 'p')
{
- /* For pre-3.0 clients, avoid log entry if they just disconnect */
- if (pq_peekbyte() == EOF)
- return NULL; /* EOF */
+ /*
+ * If the client just disconnects without offering a password,
+ * don't make a log entry. This is legal per protocol spec and in
+ * fact commonly done by psql, so complaining just clutters the
+ * log.
+ */
+ if (mtype != EOF)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROTOCOL_VIOLATION),
+ errmsg("expected password response, got message type %d",
+ mtype)));
+ return NULL; /* EOF or bad message type */
}
initStringInfo(&buf);
@@ -880,19 +871,6 @@ CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail)
bool initial;
/*
- * SASL auth is not supported for protocol versions before 3, because it
- * relies on the overall message length word to determine the SASL payload
- * size in AuthenticationSASLContinue and PasswordMessage messages. (We
- * used to have a hard rule that protocol messages must be parsable
- * without relying on the length word, but we hardly care about older
- * protocol version anymore.)
- */
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- ereport(FATAL,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SASL authentication is not supported in protocol version 2")));
-
- /*
* Send the SASL authentication request to user. It includes the list of
* authentication mechanisms that are supported.
*/
@@ -1042,19 +1020,6 @@ pg_GSS_recvauth(Port *port)
gss_buffer_desc gbuf;
/*
- * GSS auth is not supported for protocol versions before 3, because it
- * relies on the overall message length word to determine the GSS payload
- * size in AuthenticationGSSContinue and PasswordMessage messages. (This
- * is, in fact, a design error in our GSS support, because protocol
- * messages are supposed to be parsable without relying on the length
- * word; but it's not worth changing it now.)
- */
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- ereport(FATAL,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("GSSAPI is not supported in protocol version 2")));
-
- /*
* Use the configured keytab, if there is one. Unfortunately, Heimdal
* doesn't support the cred store extensions, so use the env var.
*/
@@ -1324,19 +1289,6 @@ pg_SSPI_recvauth(Port *port)
QUERY_SECURITY_CONTEXT_TOKEN_FN _QuerySecurityContextToken;
/*
- * SSPI auth is not supported for protocol versions before 3, because it
- * relies on the overall message length word to determine the SSPI payload
- * size in AuthenticationGSSContinue and PasswordMessage messages. (This
- * is, in fact, a design error in our SSPI support, because protocol
- * messages are supposed to be parsable without relying on the length
- * word; but it's not worth changing it now.)
- */
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- ereport(FATAL,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SSPI is not supported in protocol version 2")));
-
- /*
* Acquire a handle to the server credentials.
*/
r = AcquireCredentialsHandle(NULL,
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 27a298f1101..4c7b1e7bfdf 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -5,23 +5,13 @@
*
* These routines handle the low-level details of communication between
* frontend and backend. They just shove data across the communication
- * channel, and are ignorant of the semantics of the data --- or would be,
- * except for major brain damage in the design of the old COPY OUT protocol.
- * Unfortunately, COPY OUT was designed to commandeer the communication
- * channel (it just transfers data without wrapping it into messages).
- * No other messages can be sent while COPY OUT is in progress; and if the
- * copy is aborted by an ereport(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. (New COPY-OUT is message-based and does *not*
- * set the DoingCopyOut flag.)
+ * channel, and are ignorant of the semantics of the data.
*
- * 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 ensures
- * that the channel will not be clogged by an incomplete message if execution
- * is aborted by ereport(ERROR) partway through the message. The only
- * non-libpq code that should call pq_putbytes directly is old-style COPY OUT.
+ * To emit an outgoing message, use the routines in pqformat.c to construct
+ * the message in a buffer and then emit it in one call to pq_putmessage.
+ * There are no functions to send raw bytes or partial messages; this
+ * ensures that the channel will not be clogged by an incomplete message if
+ * execution is aborted by ereport(ERROR) partway through the message.
*
* At one time, libpq was shared between frontend and backend, but now
* the backend's "backend/libpq" is quite separate from "interfaces/libpq".
@@ -49,20 +39,16 @@
*
* low-level I/O:
* pq_getbytes - get a known number of bytes from connection
- * pq_getstring - get a null terminated string from connection
* pq_getmessage - get a message with length word from connection
* pq_getbyte - get next byte from connection
* pq_peekbyte - peek at next byte from connection
- * pq_putbytes - send bytes to connection (not flushed until pq_flush)
* pq_flush - flush pending output
* pq_flush_if_writable - flush pending output if writable without blocking
* pq_getbyte_if_available - get a byte if available without blocking
*
- * message-level I/O (and old-style-COPY-OUT cruft):
+ * message-level I/O
* pq_putmessage - send a normal message (suppressed in COPY OUT mode)
* pq_putmessage_noblock - buffer a normal message (suppressed in COPY OUT)
- * pq_startcopyout - inform libpq that a COPY OUT transfer is beginning
- * pq_endcopyout - end a COPY OUT transfer
*
*------------------------
*/
@@ -146,7 +132,6 @@ static int PqRecvLength; /* End of data available in PqRecvBuffer */
*/
static bool PqCommBusy; /* busy sending data to the client */
static bool PqCommReadingMsg; /* in the middle of reading a message */
-static bool DoingCopyOut; /* in old-protocol COPY OUT processing */
/* Internal functions */
@@ -158,8 +143,6 @@ static int socket_flush_if_writable(void);
static bool socket_is_send_pending(void);
static int socket_putmessage(char msgtype, const char *s, size_t len);
static void socket_putmessage_noblock(char msgtype, const char *s, size_t len);
-static void socket_startcopyout(void);
-static void socket_endcopyout(bool errorAbort);
static int internal_putbytes(const char *s, size_t len);
static int internal_flush(void);
@@ -174,9 +157,7 @@ static const PQcommMethods PqCommSocketMethods = {
socket_flush_if_writable,
socket_is_send_pending,
socket_putmessage,
- socket_putmessage_noblock,
- socket_startcopyout,
- socket_endcopyout
+ socket_putmessage_noblock
};
const PQcommMethods *PqCommMethods = &PqCommSocketMethods;
@@ -200,7 +181,6 @@ pq_init(void)
PqSendPointer = PqSendStart = PqRecvPointer = PqRecvLength = 0;
PqCommBusy = false;
PqCommReadingMsg = false;
- DoingCopyOut = false;
/* set up process-exit hook to close the socket */
on_proc_exit(socket_close, 0);
@@ -250,8 +230,6 @@ socket_comm_reset(void)
{
/* Do not throw away pending data, but do reset the busy flag */
PqCommBusy = false;
- /* We can abort any old-style COPY OUT, too */
- pq_endcopyout(true);
}
/* --------------------------------
@@ -1158,58 +1136,6 @@ pq_discardbytes(size_t len)
return 0;
}
-/* --------------------------------
- * pq_getstring - get a null terminated string from connection
- *
- * The return value is placed in an expansible StringInfo, which has
- * already been initialized by the caller.
- *
- * This is used only for dealing with old-protocol clients. The idea
- * is to produce a StringInfo that looks the same as we would get from
- * pq_getmessage() with a newer client; we will then process it with
- * pq_getmsgstring. Therefore, no character set conversion is done here,
- * even though this is presumably useful only for text.
- *
- * returns 0 if OK, EOF if trouble
- * --------------------------------
- */
-int
-pq_getstring(StringInfo s)
-{
- int i;
-
- Assert(PqCommReadingMsg);
-
- resetStringInfo(s);
-
- /* Read until we get the terminating '\0' */
- for (;;)
- {
- while (PqRecvPointer >= PqRecvLength)
- {
- if (pq_recvbuf()) /* If nothing in buffer, then recv some */
- return EOF; /* Failed to recv data */
- }
-
- for (i = PqRecvPointer; i < PqRecvLength; i++)
- {
- if (PqRecvBuffer[i] == '\0')
- {
- /* include the '\0' in the copy */
- appendBinaryStringInfo(s, PqRecvBuffer + PqRecvPointer,
- i - PqRecvPointer + 1);
- PqRecvPointer = i + 1; /* advance past \0 */
- return 0;
- }
- }
-
- /* If we're here we haven't got the \0 in the buffer yet. */
- appendBinaryStringInfo(s, PqRecvBuffer + PqRecvPointer,
- PqRecvLength - PqRecvPointer);
- PqRecvPointer = PqRecvLength;
- }
-}
-
/* --------------------------------
* pq_startmsgread - begin reading a message from the client.
@@ -1236,9 +1162,9 @@ pq_startmsgread(void)
/* --------------------------------
* pq_endmsgread - finish reading message.
*
- * This must be called after reading a V2 protocol message with
- * pq_getstring() and friends, to indicate that we have read the whole
- * message. In V3 protocol, pq_getmessage() does this implicitly.
+ * This must be called after reading a message with pq_getbytes()
+ * and friends, to indicate that we have read the whole message.
+ * pq_getmessage() does this implicitly.
* --------------------------------
*/
void
@@ -1354,28 +1280,6 @@ pq_getmessage(StringInfo s, int maxlen)
}
-/* --------------------------------
- * pq_putbytes - send bytes to connection (not flushed until pq_flush)
- *
- * returns 0 if OK, EOF if trouble
- * --------------------------------
- */
-int
-pq_putbytes(const char *s, size_t len)
-{
- int res;
-
- /* Should only be called by old-style COPY OUT */
- Assert(DoingCopyOut);
- /* No-op if reentrant call */
- if (PqCommBusy)
- return 0;
- PqCommBusy = true;
- res = internal_putbytes(s, len);
- PqCommBusy = false;
- return res;
-}
-
static int
internal_putbytes(const char *s, size_t len)
{
@@ -1536,8 +1440,6 @@ socket_is_send_pending(void)
/* --------------------------------
* Message-level I/O routines begin here.
- *
- * These routines understand about the old-style COPY OUT protocol.
* --------------------------------
*/
@@ -1545,20 +1447,13 @@ socket_is_send_pending(void)
/* --------------------------------
* socket_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. If msgtype is '\0', then the message has no type
- * code (this is only valid in pre-3.0 protocols).
- *
- * 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.
+ * msgtype is a message type code to place before the message body.
*
- * 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.)
+ * len is the length of the message body data at *s. A message length
+ * word (equal to len+4 because it counts itself too) is inserted by this
+ * routine.
*
- * We also suppress messages generated while pqcomm.c is busy. This
+ * We suppress messages generated while pqcomm.c is busy. This
* avoids any possibility of messages being inserted within other
* messages. The only known trouble case arises if SIGQUIT occurs
* during a pqcomm.c routine --- quickdie() will try to send a warning
@@ -1570,20 +1465,20 @@ socket_is_send_pending(void)
static int
socket_putmessage(char msgtype, const char *s, size_t len)
{
- if (DoingCopyOut || PqCommBusy)
+ uint32 n32;
+
+ Assert(msgtype != 0);
+
+ if (PqCommBusy)
return 0;
PqCommBusy = true;
- if (msgtype)
- if (internal_putbytes(&msgtype, 1))
- goto fail;
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
- {
- uint32 n32;
+ if (internal_putbytes(&msgtype, 1))
+ goto fail;
+
+ n32 = pg_hton32((uint32) (len + 4));
+ if (internal_putbytes((char *) &n32, 4))
+ goto fail;
- n32 = pg_hton32((uint32) (len + 4));
- if (internal_putbytes((char *) &n32, 4))
- goto fail;
- }
if (internal_putbytes(s, len))
goto fail;
PqCommBusy = false;
@@ -1621,37 +1516,41 @@ socket_putmessage_noblock(char msgtype, const char *s, size_t len)
* buffer */
}
-
-/* --------------------------------
- * socket_startcopyout - inform libpq that an old-style COPY OUT transfer
- * is beginning
- * --------------------------------
- */
-static void
-socket_startcopyout(void)
-{
- DoingCopyOut = true;
-}
-
/* --------------------------------
- * socket_endcopyout - end an old-style COPY OUT transfer
+ * pq_putmessage_v2 - send a message in protocol version 2
+ *
+ * msgtype is a message type code to place before the message body.
*
- * 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...) Note that old-style COPY OUT does
- * not allow binary transfers, so a textual terminator is always correct.
+ * We no longer support protocol version 2, but we have kept this
+ * function so that if a client tries to connect with protocol version 2,
+ * as a courtesy we can still send the "unsupported protocol version"
+ * error to the client in the old format.
+ *
+ * Like in pq_putmessage(), we suppress messages generated while
+ * pqcomm.c is busy.
+ *
+ * returns 0 if OK, EOF if trouble
* --------------------------------
*/
-static void
-socket_endcopyout(bool errorAbort)
+int
+pq_putmessage_v2(char msgtype, const char *s, size_t len)
{
- if (!DoingCopyOut)
- return;
- if (errorAbort)
- pq_putbytes("\n\n\\.\n", 5);
- /* in non-error case, copyto.c will have emitted the terminator line */
- DoingCopyOut = false;
+ Assert(msgtype != 0);
+
+ if (PqCommBusy)
+ return 0;
+ PqCommBusy = true;
+ if (internal_putbytes(&msgtype, 1))
+ goto fail;
+
+ if (internal_putbytes(s, len))
+ goto fail;
+ PqCommBusy = false;
+ return 0;
+
+fail:
+ PqCommBusy = false;
+ return EOF;
}
/*
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index f468441b7a2..d1a1f47a788 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -33,8 +33,6 @@ static int mq_flush_if_writable(void);
static bool mq_is_send_pending(void);
static int mq_putmessage(char msgtype, const char *s, size_t len);
static void mq_putmessage_noblock(char msgtype, const char *s, size_t len);
-static void mq_startcopyout(void);
-static void mq_endcopyout(bool errorAbort);
static const PQcommMethods PqCommMqMethods = {
mq_comm_reset,
@@ -42,9 +40,7 @@ static const PQcommMethods PqCommMqMethods = {
mq_flush_if_writable,
mq_is_send_pending,
mq_putmessage,
- mq_putmessage_noblock,
- mq_startcopyout,
- mq_endcopyout
+ mq_putmessage_noblock
};
/*
@@ -195,18 +191,6 @@ mq_putmessage_noblock(char msgtype, const char *s, size_t len)
elog(ERROR, "not currently supported");
}
-static void
-mq_startcopyout(void)
-{
- /* Nothing to do. */
-}
-
-static void
-mq_endcopyout(bool errorAbort)
-{
- /* Nothing to do. */
-}
-
/*
* Parse an ErrorResponse or NoticeResponse payload and populate an ErrorData
* structure with the results.
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 3f1ce135a85..edab95a19e4 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1934,7 +1934,7 @@ static int
ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
{
int32 len;
- void *buf;
+ char *buf;
ProtocolVersion proto;
MemoryContext oldcontext;
@@ -1984,15 +1984,12 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
}
/*
- * Allocate at least the size of an old-style startup packet, plus one
- * extra byte, and make sure all are zeroes. This ensures we will have
- * null termination of all strings, in both fixed- and variable-length
- * packet layouts.
+ * Allocate space to hold the startup packet, plus one extra byte that's
+ * initialized to be zero. This ensures we will have null termination of
+ * all strings inside the packet.
*/
- if (len <= (int32) sizeof(StartupPacket))
- buf = palloc0(sizeof(StartupPacket) + 1);
- else
- buf = palloc0(len + 1);
+ buf = palloc(len + 1);
+ buf[len] = '\0';
if (pq_getbytes(buf, len) == EOF)
{
@@ -2115,7 +2112,7 @@ retry1:
*/
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- if (PG_PROTOCOL_MAJOR(proto) >= 3)
+ /* Handle protocol version 3 startup packet */
{
int32 offset = sizeof(ProtocolVersion);
List *unrecognized_protocol_options = NIL;
@@ -2129,7 +2126,7 @@ retry1:
while (offset < len)
{
- char *nameptr = ((char *) buf) + offset;
+ char *nameptr = buf + offset;
int32 valoffset;
char *valptr;
@@ -2138,7 +2135,7 @@ retry1:
valoffset = offset + strlen(nameptr) + 1;
if (valoffset >= len)
break; /* missing value, will complain below */
- valptr = ((char *) buf) + valoffset;
+ valptr = buf + valoffset;
if (strcmp(nameptr, "database") == 0)
port->database_name = pstrdup(valptr);
@@ -2223,27 +2220,6 @@ retry1:
unrecognized_protocol_options != NIL)
SendNegotiateProtocolVersion(unrecognized_protocol_options);
}
- else
- {
- /*
- * Get the parameters from the old-style, fixed-width-fields startup
- * packet as C strings. The packet destination was cleared first so a
- * short packet has zeros silently added. We have to be prepared to
- * truncate the pstrdup result for oversize fields, though.
- */
- StartupPacket *packet = (StartupPacket *) buf;
-
- port->database_name = pstrdup(packet->database);
- if (strlen(port->database_name) > sizeof(packet->database))
- port->database_name[sizeof(packet->database)] = '\0';
- port->user_name = pstrdup(packet->user);
- if (strlen(port->user_name) > sizeof(packet->user))
- port->user_name[sizeof(packet->user)] = '\0';
- port->cmdline_options = pstrdup(packet->options);
- if (strlen(port->cmdline_options) > sizeof(packet->options))
- port->cmdline_options[sizeof(packet->options)] = '\0';
- port->guc_options = NIL;
- }
/* Check a user name was given. */
if (port->user_name == NULL || port->user_name[0] == '\0')
diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c
index 4316137a9d3..1dfadfa8e1d 100644
--- a/src/backend/tcop/dest.c
+++ b/src/backend/tcop/dest.c
@@ -226,13 +226,8 @@ EndReplicationCommand(const char *commandTag)
/* ----------------
* NullCommand - tell dest that an empty query string was recognized
*
- * In FE/BE protocol version 1.0, this hack is necessary to support
- * 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. 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.
+ * This ensures that there will be a recognizable end to the response
+ * to an Execute message in the extended query protocol.
* ----------------
*/
void
@@ -244,14 +239,8 @@ NullCommand(CommandDest dest)
case DestRemoteExecute:
case DestRemoteSimple:
- /*
- * tell the fe that we saw an empty query string. In protocols
- * before 3.0 this has a useless empty-string message body.
- */
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
- pq_putemptymessage('I');
- else
- pq_putmessage('I', "", 1);
+ /* Tell the FE that we saw an empty query string */
+ pq_putemptymessage('I');
break;
case DestNone:
@@ -286,7 +275,6 @@ ReadyForQuery(CommandDest dest)
case DestRemote:
case DestRemoteExecute:
case DestRemoteSimple:
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
StringInfoData buf;
@@ -294,8 +282,6 @@ ReadyForQuery(CommandDest dest)
pq_sendbyte(&buf, TransactionBlockStatusCode());
pq_endmessage(&buf);
}
- else
- pq_putemptymessage('Z');
/* Flush output at end of cycle in any case. */
pq_flush();
break;
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 1b76653caa4..77d17ebca94 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -58,98 +58,24 @@ struct fp_info
static int16 parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
FunctionCallInfo fcinfo);
-static int16 parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
- FunctionCallInfo fcinfo);
-
-
-/* ----------------
- * GetOldFunctionMessage
- *
- * In pre-3.0 protocol, there is no length word on the message, so we have
- * to have code that understands the message layout to absorb the message
- * into a buffer. We want to do this before we start execution, so that
- * we do not lose sync with the frontend if there's an error.
- *
- * The caller should already have initialized buf to empty.
- * ----------------
- */
-int
-GetOldFunctionMessage(StringInfo buf)
-{
- int32 ibuf;
- int nargs;
-
- /* Dummy string argument */
- if (pq_getstring(buf))
- return EOF;
- /* Function OID */
- if (pq_getbytes((char *) &ibuf, 4))
- return EOF;
- appendBinaryStringInfo(buf, (char *) &ibuf, 4);
- /* Number of arguments */
- if (pq_getbytes((char *) &ibuf, 4))
- return EOF;
- appendBinaryStringInfo(buf, (char *) &ibuf, 4);
- nargs = pg_ntoh32(ibuf);
- /* For each argument ... */
- while (nargs-- > 0)
- {
- int argsize;
-
- /* argsize */
- if (pq_getbytes((char *) &ibuf, 4))
- return EOF;
- appendBinaryStringInfo(buf, (char *) &ibuf, 4);
- argsize = pg_ntoh32(ibuf);
- if (argsize < -1)
- {
- /* FATAL here since no hope of regaining message sync */
- ereport(FATAL,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid argument size %d in function call message",
- argsize)));
- }
- /* and arg contents */
- if (argsize > 0)
- {
- /* Allocate space for arg */
- enlargeStringInfo(buf, argsize);
- /* And grab it */
- if (pq_getbytes(buf->data + buf->len, argsize))
- return EOF;
- buf->len += argsize;
- /* Place a trailing null per StringInfo convention */
- buf->data[buf->len] = '\0';
- }
- }
- return 0;
-}
/* ----------------
* SendFunctionResult
- *
- * Note: although this routine doesn't check, the format had better be 1
- * (binary) when talking to a pre-3.0 client.
* ----------------
*/
static void
SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
{
- bool newstyle = (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3);
StringInfoData buf;
pq_beginmessage(&buf, 'V');
if (isnull)
{
- if (newstyle)
- pq_sendint32(&buf, -1);
+ pq_sendint32(&buf, -1);
}
else
{
- if (!newstyle)
- pq_sendbyte(&buf, 'G');
-
if (format == 0)
{
Oid typoutput;
@@ -180,9 +106,6 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
errmsg("unsupported format code: %d", format)));
}
- if (!newstyle)
- pq_sendbyte(&buf, '0');
-
pq_endmessage(&buf);
}
@@ -288,9 +211,6 @@ HandleFunctionRequest(StringInfo msgBuf)
/*
* Begin parsing the buffer contents.
*/
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- (void) pq_getmsgstring(msgBuf); /* dummy string */
-
fid = (Oid) pq_getmsgint(msgBuf, 4); /* function oid */
/*
@@ -334,10 +254,7 @@ HandleFunctionRequest(StringInfo msgBuf)
*/
InitFunctionCallInfoData(*fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
- rformat = parse_fcall_arguments(msgBuf, fip, fcinfo);
- else
- rformat = parse_fcall_arguments_20(msgBuf, fip, fcinfo);
+ rformat = parse_fcall_arguments(msgBuf, fip, fcinfo);
/* Verify we reached the end of the message where expected. */
pq_getmsgend(msgBuf);
@@ -533,81 +450,3 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
/* Return result format code */
return (int16) pq_getmsgint(msgBuf, 2);
}
-
-/*
- * Parse function arguments in a 2.0 protocol message
- *
- * Argument values are loaded into *fcinfo, and the desired result format
- * is returned.
- */
-static int16
-parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
- FunctionCallInfo fcinfo)
-{
- int nargs;
- int i;
- StringInfoData abuf;
-
- nargs = pq_getmsgint(msgBuf, 4); /* # of arguments */
-
- if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
- ereport(ERROR,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("function call message contains %d arguments but function requires %d",
- nargs, fip->flinfo.fn_nargs)));
-
- fcinfo->nargs = nargs;
-
- initStringInfo(&abuf);
-
- /*
- * Copy supplied arguments into arg vector. In protocol 2.0 these are
- * always assumed to be supplied in binary format.
- *
- * Note: although the original protocol 2.0 code did not have any way for
- * the frontend to specify a NULL argument, we now choose to interpret
- * length == -1 as meaning a NULL.
- */
- for (i = 0; i < nargs; ++i)
- {
- int argsize;
- Oid typreceive;
- Oid typioparam;
-
- getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
-
- argsize = pq_getmsgint(msgBuf, 4);
- if (argsize == -1)
- {
- fcinfo->args[i].isnull = true;
- fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, NULL,
- typioparam, -1);
- continue;
- }
- fcinfo->args[i].isnull = false;
- if (argsize < 0)
- ereport(ERROR,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid argument size %d in function call message",
- argsize)));
-
- /* Reset abuf to empty, and insert raw data into it */
- resetStringInfo(&abuf);
- appendBinaryStringInfo(&abuf,
- pq_getmsgbytes(msgBuf, argsize),
- argsize);
-
- fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, &abuf,
- typioparam, -1);
-
- /* Trouble if it didn't eat the whole buffer */
- if (abuf.cursor != abuf.len)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
- errmsg("incorrect binary data format in function argument %d",
- i + 1)));
- }
-
- /* Desired result format is always binary in protocol 2.0 */
- return 1;
-}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index bb5ccb4578b..8a0332dde9d 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -370,57 +370,10 @@ SocketBackend(StringInfo inBuf)
{
case 'Q': /* simple query */
doing_extended_query_message = false;
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- {
- /* old style without length word; convert */
- if (pq_getstring(inBuf))
- {
- if (IsTransactionState())
- ereport(COMMERROR,
- (errcode(ERRCODE_CONNECTION_FAILURE),
- errmsg("unexpected EOF on client connection with an open transaction")));
- else
- {
- /*
- * Can't send DEBUG log messages to client at this
- * point. Since we're disconnecting right away, we
- * don't need to restore whereToSendOutput.
- */
- whereToSendOutput = DestNone;
- ereport(DEBUG1,
- (errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST),
- errmsg_internal("unexpected EOF on client connection")));
- }
- return EOF;
- }
- }
break;
case 'F': /* fastpath function call */
doing_extended_query_message = false;
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- {
- if (GetOldFunctionMessage(inBuf))
- {
- if (IsTransactionState())
- ereport(COMMERROR,
- (errcode(ERRCODE_CONNECTION_FAILURE),
- errmsg("unexpected EOF on client connection with an open transaction")));
- else
- {
- /*
- * Can't send DEBUG log messages to client at this
- * point. Since we're disconnecting right away, we
- * don't need to restore whereToSendOutput.
- */
- whereToSendOutput = DestNone;
- ereport(DEBUG1,
- (errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST),
- errmsg_internal("unexpected EOF on client connection")));
- }
- return EOF;
- }
- }
break;
case 'X': /* terminate */
@@ -435,11 +388,6 @@ SocketBackend(StringInfo inBuf)
case 'H': /* flush */
case 'P': /* parse */
doing_extended_query_message = true;
- /* these are only legal in protocol 3 */
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- ereport(FATAL,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid frontend message type %d", qtype)));
break;
case 'S': /* sync */
@@ -447,22 +395,12 @@ SocketBackend(StringInfo inBuf)
ignore_till_sync = false;
/* mark not-extended, so that a new error doesn't begin skip */
doing_extended_query_message = false;
- /* only legal in protocol 3 */
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- ereport(FATAL,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid frontend message type %d", qtype)));
break;
case 'd': /* copy data */
case 'c': /* copy done */
case 'f': /* copy fail */
doing_extended_query_message = false;
- /* these are only legal in protocol 3 */
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
- ereport(FATAL,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid frontend message type %d", qtype)));
break;
default:
@@ -483,13 +421,8 @@ SocketBackend(StringInfo inBuf)
* after the type code; we can read the message contents independently of
* the type.
*/
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
- {
- if (pq_getmessage(inBuf, 0))
- return EOF; /* suitable message already logged */
- }
- else
- pq_endmsgread();
+ if (pq_getmessage(inBuf, 0))
+ return EOF; /* suitable message already logged */
RESUME_CANCEL_INTERRUPTS();
return qtype;
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 80c26724612..e729ebece7b 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -589,16 +589,6 @@ errfinish(const char *filename, int lineno, const char *funcname)
PG_RE_THROW();
}
- /*
- * If we are doing FATAL or PANIC, abort any old-style COPY OUT in
- * progress, so that we can report the message before dying. (Without
- * this, pq_putmessage will refuse to send the message at all, which is
- * what we want for NOTICE messages, but not for fatal exits.) This hack
- * is necessary because of poor design of old-style copy protocol.
- */
- if (elevel >= FATAL && whereToSendOutput == DestRemote)
- pq_endcopyout(true);
-
/* Emit the message to the right places */
EmitErrorReport();
@@ -1261,28 +1251,6 @@ errhidecontext(bool hide_ctx)
return 0; /* return value does not matter */
}
-
-/*
- * errfunction --- add reporting function name to the current error
- *
- * This is used when backwards compatibility demands that the function
- * name appear in messages sent to old-protocol clients. Note that the
- * passed string is expected to be a non-freeable constant string.
- */
-int
-errfunction(const char *funcname)
-{
- ErrorData *edata = &errordata[errordata_stack_depth];
-
- /* we don't bother incrementing recursion_depth */
- CHECK_STACK_DEPTH();
-
- edata->funcname = funcname;
- edata->show_funcname = true;
-
- return 0; /* return value does not matter */
-}
-
/*
* errposition --- add cursor position to the current error
*/
@@ -3291,10 +3259,14 @@ send_message_to_frontend(ErrorData *edata)
{
StringInfoData msgbuf;
- /* 'N' (Notice) is for nonfatal conditions, 'E' is for errors */
- pq_beginmessage(&msgbuf, (edata->elevel < ERROR) ? 'N' : 'E');
-
- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
+ /*
+ * We no longer support pre-3.0 FE/BE protocol, except here. If a client
+ * tries to connect using an older protocol version, it's nice to send the
+ * "protocol version not supported" error in a format the client
+ * understands. If protocol hasn't been set yet, early in backend
+ * startup, assume modern protocol.
+ */
+ if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3 || FrontendProtocol == 0)
{
/* New style with separate fields */
const char *sev;
@@ -3302,6 +3274,9 @@ send_message_to_frontend(ErrorData *edata)
int ssval;
int i;
+ /* 'N' (Notice) is for nonfatal conditions, 'E' is for errors */
+ pq_beginmessage(&msgbuf, (edata->elevel < ERROR) ? 'N' : 'E');
+
sev = error_severity(edata->elevel);
pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY);
err_sendstring(&msgbuf, _(sev));
@@ -3417,6 +3392,8 @@ send_message_to_frontend(ErrorData *edata)
}
pq_sendbyte(&msgbuf, '\0'); /* terminator */
+
+ pq_endmessage(&msgbuf);
}
else
{
@@ -3427,30 +3404,19 @@ send_message_to_frontend(ErrorData *edata)
appendStringInfo(&buf, "%s: ", _(error_severity(edata->elevel)));
- if (edata->show_funcname && edata->funcname)
- appendStringInfo(&buf, "%s: ", edata->funcname);
-
if (edata->message)
appendStringInfoString(&buf, edata->message);
else
appendStringInfoString(&buf, _("missing error text"));
- if (edata->cursorpos > 0)
- appendStringInfo(&buf, _(" at character %d"),
- edata->cursorpos);
- else if (edata->internalpos > 0)
- appendStringInfo(&buf, _(" at character %d"),
- edata->internalpos);
-
appendStringInfoChar(&buf, '\n');
- err_sendstring(&msgbuf, buf.data);
+ /* 'N' (Notice) is for nonfatal conditions, 'E' is for errors */
+ pq_putmessage_v2((edata->elevel < ERROR) ? 'N' : 'E', buf.data, buf.len + 1);
pfree(buf.data);
}
- pq_endmessage(&msgbuf);
-
/*
* This flush is normally not necessary, since postgres.c will flush out
* waiting data when control returns to the main loop. But it seems best
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 4bcf705a30d..3fd1a5fbe26 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -6306,11 +6306,9 @@ BeginReportingGUCOptions(void)
int i;
/*
- * Don't do anything unless talking to an interactive frontend of protocol
- * 3.0 or later.
+ * Don't do anything unless talking to an interactive frontend.
*/
- if (whereToSendOutput != DestRemote ||
- PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
+ if (whereToSendOutput != DestRemote)
return;
reporting_enabled = true;
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 925fe34a3fd..7a95465111a 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -2154,9 +2154,6 @@ is_select_command(const char *query)
/*
* Test if the current user is a database superuser.
- *
- * Note: this will correctly detect superuserness only with a protocol-3.0
- * or newer backend; otherwise it will always say "false".
*/
bool
is_superuser(void)
@@ -2177,9 +2174,6 @@ is_superuser(void)
/*
* Test if the current session uses standard string literals.
- *
- * Note: With a pre-protocol-3.0 connection this will always say "false",
- * which should be the right answer.
*/
bool
standard_strings(void)
@@ -2200,10 +2194,6 @@ standard_strings(void)
/*
* Return the session user of the current connection.
- *
- * Note: this will correctly detect the session user only with a
- * protocol-3.0 or newer backend; otherwise it will return the
- * connection user.
*/
const char *
session_username(void)
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 78f0dc5a507..e1fee8e0992 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -662,7 +662,9 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
/*
* Terminate data transfer. We can't send an error message if we're using
- * protocol version 2.
+ * protocol version 2. (libpq no longer supports protocol version 2, but
+ * keep the version checks just in case you're using a pre-v14 libpq.so at
+ * runtime)
*/
if (PQputCopyEnd(conn,
(OK || PQprotocolVersion(conn) < 3) ? NULL :
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index e37942df391..705f5b615be 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -24,8 +24,7 @@
typedef enum CopySource
{
COPY_FILE, /* from file (or a piped program) */
- COPY_OLD_FE, /* from frontend (2.0 protocol) */
- COPY_NEW_FE, /* from frontend (3.0 protocol) */
+ COPY_FRONTEND, /* from frontend */
COPY_CALLBACK /* from callback function */
} CopySource;
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index e4e5c215655..b20deeb5550 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -29,8 +29,6 @@ typedef struct
bool (*is_send_pending) (void);
int (*putmessage) (char msgtype, const char *s, size_t len);
void (*putmessage_noblock) (char msgtype, const char *s, size_t len);
- void (*startcopyout) (void);
- void (*endcopyout) (bool errorAbort);
} PQcommMethods;
extern const PGDLLIMPORT PQcommMethods *PqCommMethods;
@@ -43,8 +41,6 @@ extern const PGDLLIMPORT PQcommMethods *PqCommMethods;
(PqCommMethods->putmessage(msgtype, s, len))
#define pq_putmessage_noblock(msgtype, s, len) \
(PqCommMethods->putmessage_noblock(msgtype, s, len))
-#define pq_startcopyout() (PqCommMethods->startcopyout())
-#define pq_endcopyout(errorAbort) (PqCommMethods->endcopyout(errorAbort))
/*
* External functions.
@@ -67,7 +63,6 @@ extern void TouchSocketFiles(void);
extern void RemoveSocketFiles(void);
extern void pq_init(void);
extern int pq_getbytes(char *s, size_t len);
-extern int pq_getstring(StringInfo s);
extern void pq_startmsgread(void);
extern void pq_endmsgread(void);
extern bool pq_is_reading_msg(void);
@@ -75,7 +70,7 @@ extern int pq_getmessage(StringInfo s, int maxlen);
extern int pq_getbyte(void);
extern int pq_peekbyte(void);
extern int pq_getbyte_if_available(unsigned char *c);
-extern int pq_putbytes(const char *s, size_t len);
+extern int pq_putmessage_v2(char msgtype, const char *s, size_t len);
/*
* prototypes for functions in be-secure.c
diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h
index a86b895b268..be9d9705744 100644
--- a/src/include/libpq/pqcomm.h
+++ b/src/include/libpq/pqcomm.h
@@ -114,9 +114,12 @@ is_unixsock_path(const char *path)
#define PG_PROTOCOL_MINOR(v) ((v) & 0x0000ffff)
#define PG_PROTOCOL(m,n) (((m) << 16) | (n))
-/* The earliest and latest frontend/backend protocol version supported. */
+/*
+ * The earliest and latest frontend/backend protocol version supported.
+ * (Only protocol version 3 is currently supported)
+ */
-#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(2,0)
+#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(3,0)
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,0)
typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
@@ -132,32 +135,6 @@ typedef ProtocolVersion MsgType;
typedef uint32 PacketLen;
-
-/*
- * Old-style startup packet layout with fixed-width fields. This is used in
- * protocol 1.0 and 2.0, but not in later versions. Note that the fields
- * in this layout are '\0' terminated only if there is room.
- */
-
-#define SM_DATABASE 64
-#define SM_USER 32
-/* We append database name if db_user_namespace true. */
-#define SM_DATABASE_USER (SM_DATABASE+SM_USER+1) /* +1 for @ */
-#define SM_OPTIONS 64
-#define SM_UNUSED 64
-#define SM_TTY 64
-
-typedef struct StartupPacket
-{
- ProtocolVersion protoVersion; /* Protocol version */
- char database[SM_DATABASE]; /* Database name */
- /* Db_user_namespace appends dbname */
- char user[SM_USER]; /* User name */
- char options[SM_OPTIONS]; /* Optional additional args */
- char unused[SM_UNUSED]; /* Unused */
- char tty[SM_TTY]; /* Tty for debug output */
-} StartupPacket;
-
extern bool Db_user_namespace;
/*
diff --git a/src/include/tcop/fastpath.h b/src/include/tcop/fastpath.h
index b67c44fe69e..c4d7a47dd72 100644
--- a/src/include/tcop/fastpath.h
+++ b/src/include/tcop/fastpath.h
@@ -15,7 +15,6 @@
#include "lib/stringinfo.h"
-extern int GetOldFunctionMessage(StringInfo buf);
extern void HandleFunctionRequest(StringInfo msgBuf);
#endif /* FASTPATH_H */
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 3c0e57621fc..b59651289e4 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -207,7 +207,6 @@ extern int errhidecontext(bool hide_ctx);
extern int errbacktrace(void);
-extern int errfunction(const char *funcname);
extern int errposition(int cursorpos);
extern int internalerrposition(int cursorpos);
@@ -367,7 +366,6 @@ typedef struct ErrorData
int elevel; /* error level */
bool output_to_server; /* will report to server log? */
bool output_to_client; /* will report to client? */
- bool show_funcname; /* true to force funcname inclusion */
bool hide_stmt; /* true to prevent STATEMENT: inclusion */
bool hide_ctx; /* true to prevent CONTEXT: inclusion */
const char *filename; /* __FILE__ of ereport() call */
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index f74677eaf9b..2aca882a2be 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -37,7 +37,6 @@ OBJS = \
fe-lobj.o \
fe-misc.o \
fe-print.o \
- fe-protocol2.o \
fe-protocol3.o \
fe-secure.o \
legacy-pqsignal.o \
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 168b3df52bf..e8062647e60 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -579,7 +579,7 @@ pg_SASL_init(PGconn *conn, int payloadlen)
/*
* Build a SASLInitialResponse message, and send it.
*/
- if (pqPutMsgStart('p', true, conn))
+ if (pqPutMsgStart('p', conn))
goto error;
if (pqPuts(selected_mechanism, conn))
goto error;
@@ -798,11 +798,7 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
default:
return STATUS_ERROR;
}
- /* Packet has a message type as of protocol 3.0 */
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
- else
- ret = pqPacketSend(conn, 0, pwd_to_send, strlen(pwd_to_send) + 1);
+ ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
if (crypt_pwd)
free(crypt_pwd);
return ret;
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 9812a14662d..c16a7bd9f22 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -2289,10 +2289,6 @@ PQconnectPoll(PGconn *conn)
case CONNECTION_MADE:
break;
- /* We allow pqSetenvPoll to decide whether to proceed. */
- case CONNECTION_SETENV:
- break;
-
/* Special cases: proceed without waiting. */
case CONNECTION_SSL_STARTUP:
case CONNECTION_NEEDED:
@@ -2956,12 +2952,8 @@ keep_going: /* We will come back to here until there is
/*
* Build the startup packet.
*/
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- startpacket = pqBuildStartupPacket3(conn, &packetlen,
- EnvironmentOptions);
- else
- startpacket = pqBuildStartupPacket2(conn, &packetlen,
- EnvironmentOptions);
+ startpacket = pqBuildStartupPacket3(conn, &packetlen,
+ EnvironmentOptions);
if (!startpacket)
{
appendPQExpBufferStr(&conn->errorMessage,
@@ -3247,19 +3239,11 @@ keep_going: /* We will come back to here until there is
goto error_return;
}
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- {
- /* Read message length word */
- if (pqGetInt(&msgLength, 4, conn))
- {
- /* We'll come back when there is more data */
- return PGRES_POLLING_READING;
- }
- }
- else
+ /* Read message length word */
+ if (pqGetInt(&msgLength, 4, conn))
{
- /* Set phony message length to disable checks below */
- msgLength = 8;
+ /* We'll come back when there is more data */
+ return PGRES_POLLING_READING;
}
/*
@@ -3268,7 +3252,9 @@ keep_going: /* We will come back to here until there is
* auth requests may not be that small. 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.
+ * pre-3.0-protocol server; cope. (Before version 14, the
+ * server also used the old protocol for errors that happened
+ * before processing the startup packet.)
*/
if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
{
@@ -3296,25 +3282,11 @@ keep_going: /* We will come back to here until there is
*/
appendPQExpBufferChar(&conn->errorMessage, '\n');
- /*
- * If we tried to open the connection in 3.0 protocol,
- * fall back to 2.0 protocol.
- */
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- {
- conn->pversion = PG_PROTOCOL(2, 0);
- need_new_connection = true;
- goto keep_going;
- }
-
goto error_return;
}
/*
* Can't process if message body isn't all here yet.
- *
- * (In protocol 2.0 case, we are assuming messages carry at
- * least 4 bytes of data.)
*/
msgLength -= 4;
avail = conn->inEnd - conn->inCursor;
@@ -3335,21 +3307,10 @@ keep_going: /* We will come back to here until there is
/* Handle errors. */
if (beresp == 'E')
{
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
+ if (pqGetErrorNotice3(conn, true))
{
- if (pqGetErrorNotice3(conn, true))
- {
- /* We'll come back when there is more data */
- return PGRES_POLLING_READING;
- }
- }
- else
- {
- if (pqGets_append(&conn->errorMessage, conn))
- {
- /* We'll come back when there is more data */
- return PGRES_POLLING_READING;
- }
+ /* 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;
@@ -3434,33 +3395,6 @@ keep_going: /* We will come back to here until there is
msgLength -= 4;
/*
- * Ensure the password salt is in the input buffer, if it's an
- * MD5 request. All the other authentication methods that
- * contain extra data in the authentication request are only
- * supported in protocol version 3, in which case we already
- * read the whole message above.
- */
- if (areq == AUTH_REQ_MD5 && PG_PROTOCOL_MAJOR(conn->pversion) < 3)
- {
- msgLength += 4;
-
- avail = conn->inEnd - conn->inCursor;
- if (avail < 4)
- {
- /*
- * Before returning, try to enlarge the input buffer
- * if needed to hold the whole message; see notes in
- * pqParseInput3.
- */
- if (pqCheckInBufferSpace(conn->inCursor + (size_t) 4,
- conn))
- goto error_return;
- /* We'll come back when there is more data */
- return PGRES_POLLING_READING;
- }
- }
-
- /*
* Process the rest of the authentication request message, and
* respond to it if necessary.
*
@@ -3567,15 +3501,6 @@ keep_going: /* We will come back to here until there is
goto error_return;
}
- /* Fire up post-connection housekeeping if needed */
- if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
- {
- conn->status = CONNECTION_SETENV;
- conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_SEND;
- conn->next_eo = EnvironmentOptions;
- return PGRES_POLLING_WRITING;
- }
-
/* Almost there now ... */
conn->status = CONNECTION_CHECK_TARGET;
goto keep_going;
@@ -3596,17 +3521,9 @@ keep_going: /* We will come back to here until there is
* If the server didn't report
* "default_transaction_read_only" or "in_hot_standby" at
* startup, we must determine its state by sending the
- * query "SHOW transaction_read_only". Servers before 7.4
- * lack the transaction_read_only GUC, but by the same
- * token they don't have any read-only mode, so we may
- * just assume the results.
+ * query "SHOW transaction_read_only". This GUC exists in
+ * all server versions that support 3.0 protocol.
*/
- if (conn->sversion < 70400)
- {
- conn->default_transaction_read_only = PG_BOOL_NO;
- conn->in_hot_standby = PG_BOOL_NO;
- }
-
if (conn->default_transaction_read_only == PG_BOOL_UNKNOWN ||
conn->in_hot_standby == PG_BOOL_UNKNOWN)
{
@@ -3719,39 +3636,6 @@ keep_going: /* We will come back to here until there is
return PGRES_POLLING_OK;
}
- case CONNECTION_SETENV:
- {
- /*
- * Do post-connection housekeeping (only needed in protocol
- * 2.0).
- *
- * We pretend that the connection is OK for the duration of
- * these queries.
- */
- conn->status = CONNECTION_OK;
-
- switch (pqSetenvPoll(conn))
- {
- case PGRES_POLLING_OK: /* Success */
- break;
-
- case PGRES_POLLING_READING: /* Still going */
- conn->status = CONNECTION_SETENV;
- return PGRES_POLLING_READING;
-
- case PGRES_POLLING_WRITING: /* Still going */
- conn->status = CONNECTION_SETENV;
- return PGRES_POLLING_WRITING;
-
- default:
- goto error_return;
- }
-
- /* Almost there now ... */
- conn->status = CONNECTION_CHECK_TARGET;
- goto keep_going;
- }
-
case CONNECTION_CONSUME:
{
/*
@@ -4042,7 +3926,6 @@ makeEmptyPGconn(void)
conn->xactStatus = PQTRANS_IDLE;
conn->options_valid = false;
conn->nonblocking = false;
- conn->setenv_state = SETENV_STATE_IDLE;
conn->client_encoding = PG_SQL_ASCII;
conn->std_strings = false; /* unless server says differently */
conn->default_transaction_read_only = PG_BOOL_UNKNOWN;
@@ -4259,7 +4142,7 @@ sendTerminateConn(PGconn *conn)
* Try to send "close connection" message to backend. Ignore any
* error.
*/
- pqPutMsgStart('X', false, conn);
+ pqPutMsgStart('X', conn);
pqPutMsgEnd(conn);
(void) pqFlush(conn);
}
@@ -4652,16 +4535,13 @@ PQrequestCancel(PGconn *conn)
*
* RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
* SIDE_EFFECTS: may block.
- *
- * Note: all messages sent with this routine have a length word, whether
- * it's protocol 2.0 or 3.0.
*/
int
pqPacketSend(PGconn *conn, char pack_type,
const void *buf, size_t buf_len)
{
/* Start the message. */
- if (pqPutMsgStart(pack_type, true, conn))
+ if (pqPutMsgStart(pack_type, conn))
return STATUS_ERROR;
/* Send the message body. */
@@ -6917,13 +6797,9 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
else
{
/*
- * In protocol 2 we have to assume the setting will stick, and adjust
- * our state immediately. In protocol 3 and up we can rely on the
- * backend to report the parameter value, and we'll change state at
- * that time.
+ * We rely on the backend to report the parameter value, and we'll
+ * change state at that time.
*/
- if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
- pqSaveParameterStatus(conn, "client_encoding", encoding);
status = 0; /* everything is ok */
}
PQclear(res);
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index a5507538555..9a038043b2c 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -1221,7 +1221,7 @@ PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery)
}
/* construct the outgoing Query message */
- if (pqPutMsgStart('Q', false, conn) < 0 ||
+ if (pqPutMsgStart('Q', conn) < 0 ||
pqPuts(query, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
{
@@ -1255,7 +1255,7 @@ PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery)
/*
* PQsendQueryParams
- * Like PQsendQuery, but use protocol 3.0 so we can pass parameters
+ * Like PQsendQuery, but use extended query protocol so we can pass parameters
*/
int
PQsendQueryParams(PGconn *conn,
@@ -1330,16 +1330,8 @@ PQsendPrepare(PGconn *conn,
return 0;
}
- /* This isn't gonna work on a 2.0 server */
- if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("function requires at least protocol version 3.0\n"));
- return 0;
- }
-
/* construct the Parse message */
- if (pqPutMsgStart('P', false, conn) < 0 ||
+ if (pqPutMsgStart('P', conn) < 0 ||
pqPuts(stmtName, conn) < 0 ||
pqPuts(query, conn) < 0)
goto sendFailed;
@@ -1365,7 +1357,7 @@ PQsendPrepare(PGconn *conn,
goto sendFailed;
/* construct the Sync message */
- if (pqPutMsgStart('S', false, conn) < 0 ||
+ if (pqPutMsgStart('S', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
@@ -1397,7 +1389,7 @@ sendFailed:
/*
* PQsendQueryPrepared
* Like PQsendQuery, but execute a previously prepared statement,
- * using protocol 3.0 so we can pass parameters
+ * using extended query protocol so we can pass parameters
*/
int
PQsendQueryPrepared(PGconn *conn,
@@ -1478,7 +1470,7 @@ PQsendQueryStart(PGconn *conn, bool newQuery)
/*
* PQsendQueryGuts
- * Common code for protocol-3.0 query sending
+ * Common code for sending a query with extended query protocol
* PQsendQueryStart should be done already
*
* command may be NULL to indicate we use an already-prepared statement
@@ -1496,14 +1488,6 @@ PQsendQueryGuts(PGconn *conn,
{
int i;
- /* This isn't gonna work on a 2.0 server */
- if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("function requires at least protocol version 3.0\n"));
- return 0;
- }
-
/*
* We will send Parse (if needed), Bind, Describe Portal, Execute, Sync,
* using specified statement name and the unnamed portal.
@@ -1512,7 +1496,7 @@ PQsendQueryGuts(PGconn *conn,
if (command)
{
/* construct the Parse message */
- if (pqPutMsgStart('P', false, conn) < 0 ||
+ if (pqPutMsgStart('P', conn) < 0 ||
pqPuts(stmtName, conn) < 0 ||
pqPuts(command, conn) < 0)
goto sendFailed;
@@ -1536,7 +1520,7 @@ PQsendQueryGuts(PGconn *conn,
}
/* Construct the Bind message */
- if (pqPutMsgStart('B', false, conn) < 0 ||
+ if (pqPutMsgStart('B', conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPuts(stmtName, conn) < 0)
goto sendFailed;
@@ -1603,21 +1587,21 @@ PQsendQueryGuts(PGconn *conn,
goto sendFailed;
/* construct the Describe Portal message */
- if (pqPutMsgStart('D', false, conn) < 0 ||
+ if (pqPutMsgStart('D', conn) < 0 ||
pqPutc('P', conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Execute message */
- if (pqPutMsgStart('E', false, conn) < 0 ||
+ if (pqPutMsgStart('E', conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPutInt(0, 4, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Sync message */
- if (pqPutMsgStart('S', false, conn) < 0 ||
+ if (pqPutMsgStart('S', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
@@ -1718,10 +1702,7 @@ PQconsumeInput(PGconn *conn)
static void
parseInput(PGconn *conn)
{
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- pqParseInput3(conn);
- else
- pqParseInput2(conn);
+ pqParseInput3(conn);
}
/*
@@ -1926,7 +1907,7 @@ PQexec(PGconn *conn, const char *query)
/*
* PQexecParams
- * Like PQexec, but use protocol 3.0 so we can pass parameters
+ * Like PQexec, but use extended query protocol so we can pass parameters
*/
PGresult *
PQexecParams(PGconn *conn,
@@ -1949,7 +1930,7 @@ PQexecParams(PGconn *conn,
/*
* PQprepare
- * Creates a prepared statement by issuing a v3.0 parse message.
+ * Creates a prepared statement by issuing a Parse message.
*
* If the query was not even sent, return NULL; conn->errorMessage is set to
* a relevant message.
@@ -1973,7 +1954,7 @@ PQprepare(PGconn *conn,
/*
* PQexecPrepared
* Like PQexec, but execute a previously prepared statement,
- * using protocol 3.0 so we can pass parameters
+ * using extended query protocol so we can pass parameters
*/
PGresult *
PQexecPrepared(PGconn *conn,
@@ -2020,41 +2001,20 @@ PQexecStart(PGconn *conn)
PQclear(result); /* only need its status */
if (resultStatus == PGRES_COPY_IN)
{
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- {
- /* In protocol 3, we can get out of a COPY IN state */
- if (PQputCopyEnd(conn,
- libpq_gettext("COPY terminated by new PQexec")) < 0)
- return false;
- /* keep waiting to swallow the copy's failure message */
- }
- else
- {
- /* In older protocols we have to punt */
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("COPY IN state must be terminated first\n"));
+ /* get out of a COPY IN state */
+ if (PQputCopyEnd(conn,
+ libpq_gettext("COPY terminated by new PQexec")) < 0)
return false;
- }
+ /* keep waiting to swallow the copy's failure message */
}
else if (resultStatus == PGRES_COPY_OUT)
{
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- {
- /*
- * In protocol 3, we can get out of a COPY OUT state: we just
- * switch back to BUSY and allow the remaining COPY data to be
- * dropped on the floor.
- */
- conn->asyncStatus = PGASYNC_BUSY;
- /* keep waiting to swallow the copy's completion message */
- }
- else
- {
- /* In older protocols we have to punt */
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("COPY OUT state must be terminated first\n"));
- return false;
- }
+ /*
+ * Get out of a COPY OUT state: we just switch back to BUSY and
+ * allow the remaining COPY data to be dropped on the floor.
+ */
+ conn->asyncStatus = PGASYNC_BUSY;
+ /* keep waiting to swallow the copy's completion message */
}
else if (resultStatus == PGRES_COPY_BOTH)
{
@@ -2195,23 +2155,15 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
if (!PQsendQueryStart(conn, true))
return 0;
- /* This isn't gonna work on a 2.0 server */
- if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("function requires at least protocol version 3.0\n"));
- return 0;
- }
-
/* construct the Describe message */
- if (pqPutMsgStart('D', false, conn) < 0 ||
+ if (pqPutMsgStart('D', conn) < 0 ||
pqPutc(desc_type, conn) < 0 ||
pqPuts(desc_target, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Sync message */
- if (pqPutMsgStart('S', false, conn) < 0 ||
+ if (pqPutMsgStart('S', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
@@ -2311,8 +2263,7 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
* Try to flush any previously sent data in preference to growing the
* output buffer. If we can't enlarge the buffer enough to hold the
* data, return 0 in the nonblock case, else hard error. (For
- * simplicity, always assume 5 bytes of overhead even in protocol 2.0
- * case.)
+ * simplicity, always assume 5 bytes of overhead.)
*/
if ((conn->outBufSize - conn->outCount - 5) < nbytes)
{
@@ -2323,20 +2274,10 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
return pqIsnonblocking(conn) ? 0 : -1;
}
/* Send the data (too simple to delegate to fe-protocol files) */
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- {
- if (pqPutMsgStart('d', false, conn) < 0 ||
- pqPutnchar(buffer, nbytes, conn) < 0 ||
- pqPutMsgEnd(conn) < 0)
- return -1;
- }
- else
- {
- if (pqPutMsgStart(0, false, conn) < 0 ||
- pqPutnchar(buffer, nbytes, conn) < 0 ||
- pqPutMsgEnd(conn) < 0)
- return -1;
- }
+ if (pqPutMsgStart('d', conn) < 0 ||
+ pqPutnchar(buffer, nbytes, conn) < 0 ||
+ pqPutMsgEnd(conn) < 0)
+ return -1;
}
return 1;
}
@@ -2366,52 +2307,31 @@ PQputCopyEnd(PGconn *conn, const char *errormsg)
* Send the COPY END indicator. This is simple enough that we don't
* bother delegating it to the fe-protocol files.
*/
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
+ if (errormsg)
{
- if (errormsg)
- {
- /* Send COPY FAIL */
- if (pqPutMsgStart('f', false, conn) < 0 ||
- pqPuts(errormsg, conn) < 0 ||
- pqPutMsgEnd(conn) < 0)
- return -1;
- }
- else
- {
- /* Send COPY DONE */
- if (pqPutMsgStart('c', false, conn) < 0 ||
- pqPutMsgEnd(conn) < 0)
- return -1;
- }
-
- /*
- * If we sent the COPY command in extended-query mode, we must issue a
- * Sync as well.
- */
- if (conn->queryclass != PGQUERY_SIMPLE)
- {
- if (pqPutMsgStart('S', false, conn) < 0 ||
- pqPutMsgEnd(conn) < 0)
- return -1;
- }
+ /* Send COPY FAIL */
+ if (pqPutMsgStart('f', conn) < 0 ||
+ pqPuts(errormsg, conn) < 0 ||
+ pqPutMsgEnd(conn) < 0)
+ return -1;
}
else
{
- if (errormsg)
- {
- /* Oops, no way to do this in 2.0 */
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("function requires at least protocol version 3.0\n"));
+ /* Send COPY DONE */
+ if (pqPutMsgStart('c', conn) < 0 ||
+ pqPutMsgEnd(conn) < 0)
+ return -1;
+ }
+
+ /*
+ * If we sent the COPY command in extended-query mode, we must issue a
+ * Sync as well.
+ */
+ if (conn->queryclass != PGQUERY_SIMPLE)
+ {
+ if (pqPutMsgStart('S', conn) < 0 ||
+ pqPutMsgEnd(conn) < 0)
return -1;
- }
- else
- {
- /* Send old-style end-of-data marker */
- if (pqPutMsgStart(0, false, conn) < 0 ||
- pqPutnchar("\\.\n", 3, conn) < 0 ||
- pqPutMsgEnd(conn) < 0)
- return -1;
- }
}
/* Return to active duty */
@@ -2450,10 +2370,7 @@ PQgetCopyData(PGconn *conn, char **buffer, int async)
libpq_gettext("no COPY in progress\n"));
return -2;
}
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- return pqGetCopyData3(conn, buffer, async);
- else
- return pqGetCopyData2(conn, buffer, async);
+ return pqGetCopyData3(conn, buffer, async);
}
/*
@@ -2492,10 +2409,7 @@ PQgetline(PGconn *conn, char *s, int maxlen)
if (!conn)
return EOF;
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- return pqGetline3(conn, s, maxlen);
- else
- return pqGetline2(conn, s, maxlen);
+ return pqGetline3(conn, s, maxlen);
}
/*
@@ -2535,10 +2449,7 @@ PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)
if (!conn)
return -1;
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- return pqGetlineAsync3(conn, buffer, bufsize);
- else
- return pqGetlineAsync2(conn, buffer, bufsize);
+ return pqGetlineAsync3(conn, buffer, bufsize);
}
/*
@@ -2573,10 +2484,8 @@ PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
* After completing the data transfer portion of a copy in/out,
* the application must call this routine to finish the command protocol.
*
- * When using protocol 3.0 this is deprecated; it's cleaner to use PQgetResult
- * to get the transfer status. Note however that when using 2.0 protocol,
- * recovering from a copy failure often requires a PQreset. PQendcopy will
- * take care of that, PQgetResult won't.
+ * This is deprecated; it's cleaner to use PQgetResult to get the transfer
+ * status.
*
* RETURNS:
* 0 on success
@@ -2588,10 +2497,7 @@ PQendcopy(PGconn *conn)
if (!conn)
return 0;
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- return pqEndcopy3(conn);
- else
- return pqEndcopy2(conn);
+ return pqEndcopy3(conn);
}
@@ -2643,16 +2549,10 @@ PQfn(PGconn *conn,
return NULL;
}
- if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- return pqFunctionCall3(conn, fnid,
- result_buf, result_len,
- result_is_int,
- args, nargs);
- else
- return pqFunctionCall2(conn, fnid,
- result_buf, result_len,
- result_is_int,
- args, nargs);
+ return pqFunctionCall3(conn, fnid,
+ result_buf, result_len,
+ result_is_int,
+ args, nargs);
}
@@ -2701,13 +2601,6 @@ PQresultVerboseErrorMessage(const PGresult *res,
initPQExpBuffer(&workBuf);
- /*
- * Currently, we pass this off to fe-protocol3.c in all cases; it will
- * behave reasonably sanely with an error reported by fe-protocol2.c as
- * well. If necessary, we could record the protocol version in PGresults
- * so as to be able to invoke a version-specific message formatter, but
- * for now there's no need.
- */
pqBuildErrorMessage3(&workBuf, res, verbosity, show_context);
/* If insufficient memory to format the message, fail cleanly */
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index b9c52eb50c2..ffd9926dc4e 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -884,38 +884,26 @@ lo_initialize(PGconn *conn)
MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
/*
- * Execute the query to get all the functions at once. In 7.3 and later
- * we need to be schema-safe. lo_create only exists in 8.1 and up.
- * lo_truncate only exists in 8.3 and up.
+ * Execute the query to get all the functions at once. (Not all of them
+ * may exist in older server versions.)
*/
- if (conn->sversion >= 70300)
- query = "select proname, oid from pg_catalog.pg_proc "
- "where proname in ("
- "'lo_open', "
- "'lo_close', "
- "'lo_creat', "
- "'lo_create', "
- "'lo_unlink', "
- "'lo_lseek', "
- "'lo_lseek64', "
- "'lo_tell', "
- "'lo_tell64', "
- "'lo_truncate', "
- "'lo_truncate64', "
- "'loread', "
- "'lowrite') "
- "and pronamespace = (select oid from pg_catalog.pg_namespace "
- "where nspname = 'pg_catalog')";
- else
- query = "select proname, oid from pg_proc "
- "where proname = 'lo_open' "
- "or proname = 'lo_close' "
- "or proname = 'lo_creat' "
- "or proname = 'lo_unlink' "
- "or proname = 'lo_lseek' "
- "or proname = 'lo_tell' "
- "or proname = 'loread' "
- "or proname = 'lowrite'";
+ query = "select proname, oid from pg_catalog.pg_proc "
+ "where proname in ("
+ "'lo_open', "
+ "'lo_close', "
+ "'lo_creat', "
+ "'lo_create', "
+ "'lo_unlink', "
+ "'lo_lseek', "
+ "'lo_lseek64', "
+ "'lo_tell', "
+ "'lo_tell64', "
+ "'lo_truncate', "
+ "'lo_truncate64', "
+ "'loread', "
+ "'lowrite') "
+ "and pronamespace = (select oid from pg_catalog.pg_namespace "
+ "where nspname = 'pg_catalog')";
res = PQexec(conn, query);
if (res == NULL)
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 2bfb6acd895..ce2d24b91fc 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -484,9 +484,6 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
* msg_type is the message type byte, or 0 for a message without type byte
* (only startup messages have no type byte)
*
- * force_len forces the message to have a length word; otherwise, we add
- * a length word if protocol 3.
- *
* Returns 0 on success, EOF on error
*
* The idea here is that we construct the message in conn->outBuffer,
@@ -497,12 +494,11 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
*
* The state variable conn->outMsgStart points to the incomplete message's
* length word: it is either outCount or outCount+1 depending on whether
- * there is a type byte. If we are sending a message without length word
- * (pre protocol 3.0 only), then outMsgStart is -1. The state variable
- * conn->outMsgEnd is the end of the data collected so far.
+ * there is a type byte. The state variable conn->outMsgEnd is the end of
+ * the data collected so far.
*/
int
-pqPutMsgStart(char msg_type, bool force_len, PGconn *conn)
+pqPutMsgStart(char msg_type, PGconn *conn)
{
int lenPos;
int endPos;
@@ -514,14 +510,9 @@ pqPutMsgStart(char msg_type, bool force_len, PGconn *conn)
endPos = conn->outCount;
/* do we want a length word? */
- if (force_len || PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
- {
- lenPos = endPos;
- /* allow room for message length */
- endPos += 4;
- }
- else
- lenPos = -1;
+ lenPos = endPos;
+ /* allow room for message length */
+ endPos += 4;
/* make sure there is room for message header */
if (pqCheckOutBufferSpace(endPos, conn))
diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c
deleted file mode 100644
index 6efa53d8b71..00000000000
--- a/src/interfaces/libpq/fe-protocol2.c
+++ /dev/null
@@ -1,1610 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * fe-protocol2.c
- * functions that are specific to frontend/backend protocol version 2
- *
- * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * src/interfaces/libpq/fe-protocol2.c
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres_fe.h"
-
-#include <ctype.h>
-#include <fcntl.h>
-
-#ifdef WIN32
-#include "win32.h"
-#else
-#include <unistd.h>
-#ifdef HAVE_NETINET_TCP_H
-#include <netinet/tcp.h>
-#endif
-#endif
-
-#include "libpq-fe.h"
-#include "libpq-int.h"
-#include "port/pg_bswap.h"
-
-static int getRowDescriptions(PGconn *conn);
-static int getAnotherTuple(PGconn *conn, bool binary);
-static int pqGetErrorNotice2(PGconn *conn, bool isError);
-static void checkXactStatus(PGconn *conn, const char *cmdTag);
-static int getNotify(PGconn *conn);
-
-
-/*
- * pqSetenvPoll
- *
- * Polls the process of passing the values of a standard set of environment
- * variables to the backend.
- */
-PostgresPollingStatusType
-pqSetenvPoll(PGconn *conn)
-{
- PGresult *res;
-
- if (conn == NULL || conn->status == CONNECTION_BAD)
- return PGRES_POLLING_FAILED;
-
- /* Check whether there are any data for us */
- switch (conn->setenv_state)
- {
- /* These are reading states */
- case SETENV_STATE_CLIENT_ENCODING_WAIT:
- case SETENV_STATE_OPTION_WAIT:
- case SETENV_STATE_QUERY1_WAIT:
- case SETENV_STATE_QUERY2_WAIT:
- {
- /* Load waiting data */
- int n = pqReadData(conn);
-
- if (n < 0)
- goto error_return;
- if (n == 0)
- return PGRES_POLLING_READING;
-
- break;
- }
-
- /* These are writing states, so we just proceed. */
- case SETENV_STATE_CLIENT_ENCODING_SEND:
- case SETENV_STATE_OPTION_SEND:
- case SETENV_STATE_QUERY1_SEND:
- case SETENV_STATE_QUERY2_SEND:
- break;
-
- /* Should we raise an error if called when not active? */
- case SETENV_STATE_IDLE:
- return PGRES_POLLING_OK;
-
- default:
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("invalid setenv state %c, probably indicative of memory corruption\n"),
- conn->setenv_state);
- goto error_return;
- }
-
- /* We will loop here until there is nothing left to do in this call. */
- for (;;)
- {
- switch (conn->setenv_state)
- {
- /*
- * The _CLIENT_ENCODING_SEND code is slightly different from
- * _OPTION_SEND below (e.g., no getenv() call), which is why a
- * different state is used.
- */
- case SETENV_STATE_CLIENT_ENCODING_SEND:
- {
- char setQuery[100]; /* note length limit in
- * sprintf below */
- const char *val = conn->client_encoding_initial;
-
- if (val)
- {
- if (pg_strcasecmp(val, "default") == 0)
- sprintf(setQuery, "SET client_encoding = DEFAULT");
- else
- sprintf(setQuery, "SET client_encoding = '%.60s'",
- val);
-#ifdef CONNECTDEBUG
- fprintf(stderr,
- "Sending client_encoding with %s\n",
- setQuery);
-#endif
- if (!PQsendQuery(conn, setQuery))
- goto error_return;
-
- conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_WAIT;
- }
- else
- conn->setenv_state = SETENV_STATE_OPTION_SEND;
- break;
- }
-
- case SETENV_STATE_OPTION_SEND:
- {
- /*
- * Send SET commands for stuff directed by Environment
- * Options. Note: we assume that SET commands won't start
- * transaction blocks, even in a 7.3 server with
- * autocommit off.
- */
- char setQuery[100]; /* note length limit in
- * sprintf below */
-
- if (conn->next_eo->envName)
- {
- const char *val;
-
- if ((val = getenv(conn->next_eo->envName)))
- {
- if (pg_strcasecmp(val, "default") == 0)
- sprintf(setQuery, "SET %s = DEFAULT",
- conn->next_eo->pgName);
- else
- sprintf(setQuery, "SET %s = '%.60s'",
- conn->next_eo->pgName, val);
-#ifdef CONNECTDEBUG
- fprintf(stderr,
- "Use environment variable %s to send %s\n",
- conn->next_eo->envName, setQuery);
-#endif
- if (!PQsendQuery(conn, setQuery))
- goto error_return;
-
- conn->setenv_state = SETENV_STATE_OPTION_WAIT;
- }
- else
- conn->next_eo++;
- }
- else
- {
- /* No more options to send, so move on to querying */
- conn->setenv_state = SETENV_STATE_QUERY1_SEND;
- }
- break;
- }
-
- case SETENV_STATE_CLIENT_ENCODING_WAIT:
- {
- if (PQisBusy(conn))
- return PGRES_POLLING_READING;
-
- res = PQgetResult(conn);
-
- if (res)
- {
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- PQclear(res);
- goto error_return;
- }
- PQclear(res);
- /* Keep reading until PQgetResult returns NULL */
- }
- else
- {
- /* Query finished, so send the next option */
- conn->setenv_state = SETENV_STATE_OPTION_SEND;
- }
- break;
- }
-
- case SETENV_STATE_OPTION_WAIT:
- {
- if (PQisBusy(conn))
- return PGRES_POLLING_READING;
-
- res = PQgetResult(conn);
-
- if (res)
- {
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- PQclear(res);
- goto error_return;
- }
- PQclear(res);
- /* Keep reading until PQgetResult returns NULL */
- }
- else
- {
- /* Query finished, so send the next option */
- conn->next_eo++;
- conn->setenv_state = SETENV_STATE_OPTION_SEND;
- }
- break;
- }
-
- case SETENV_STATE_QUERY1_SEND:
- {
- /*
- * Issue query to get information we need. Here we must
- * use begin/commit in case autocommit is off by default
- * in a 7.3 server.
- *
- * Note: version() exists in all protocol-2.0-supporting
- * backends. In 7.3 it would be safer to write
- * pg_catalog.version(), but we can't do that without
- * causing problems on older versions.
- */
- if (!PQsendQuery(conn, "begin; select version(); end"))
- goto error_return;
-
- conn->setenv_state = SETENV_STATE_QUERY1_WAIT;
- return PGRES_POLLING_READING;
- }
-
- case SETENV_STATE_QUERY1_WAIT:
- {
- if (PQisBusy(conn))
- return PGRES_POLLING_READING;
-
- res = PQgetResult(conn);
-
- if (res)
- {
- char *val;
-
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- /* ignore begin/commit command results */
- PQclear(res);
- continue;
- }
-
- if (PQresultStatus(res) != PGRES_TUPLES_OK ||
- PQntuples(res) != 1)
- {
- PQclear(res);
- goto error_return;
- }
-
- /*
- * Extract server version and save as if
- * ParameterStatus
- */
- val = PQgetvalue(res, 0, 0);
- if (val && strncmp(val, "PostgreSQL ", 11) == 0)
- {
- char *ptr;
-
- /* strip off PostgreSQL part */
- val += 11;
-
- /*
- * strip off platform part (scribbles on result,
- * naughty naughty)
- */
- ptr = strchr(val, ' ');
- if (ptr)
- *ptr = '\0';
-
- pqSaveParameterStatus(conn, "server_version",
- val);
- }
-
- PQclear(res);
- /* Keep reading until PQgetResult returns NULL */
- }
- else
- {
- /* Query finished, move to next */
- conn->setenv_state = SETENV_STATE_QUERY2_SEND;
- }
- break;
- }
-
- case SETENV_STATE_QUERY2_SEND:
- {
- const char *query;
-
- /*
- * pg_client_encoding does not exist in pre-7.2 servers.
- * So we need to be prepared for an error here. Do *not*
- * start a transaction block, except in 7.3 servers where
- * we need to prevent autocommit-off from starting a
- * transaction anyway.
- */
- if (conn->sversion >= 70300 &&
- conn->sversion < 70400)
- query = "begin; select pg_catalog.pg_client_encoding(); end";
- else
- query = "select pg_client_encoding()";
- if (!PQsendQuery(conn, query))
- goto error_return;
-
- conn->setenv_state = SETENV_STATE_QUERY2_WAIT;
- return PGRES_POLLING_READING;
- }
-
- case SETENV_STATE_QUERY2_WAIT:
- {
- if (PQisBusy(conn))
- return PGRES_POLLING_READING;
-
- res = PQgetResult(conn);
-
- if (res)
- {
- const char *val;
-
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- /* ignore begin/commit command results */
- PQclear(res);
- continue;
- }
-
- if (PQresultStatus(res) == PGRES_TUPLES_OK &&
- PQntuples(res) == 1)
- {
- /* Extract client encoding and save it */
- val = PQgetvalue(res, 0, 0);
- if (val && *val) /* null should not happen, but */
- pqSaveParameterStatus(conn, "client_encoding",
- val);
- }
- else
- {
- /*
- * Error: presumably function not available, so
- * use PGCLIENTENCODING or SQL_ASCII as the
- * fallback.
- */
- val = getenv("PGCLIENTENCODING");
- if (val && *val)
- pqSaveParameterStatus(conn, "client_encoding",
- val);
- else
- pqSaveParameterStatus(conn, "client_encoding",
- "SQL_ASCII");
- }
-
- PQclear(res);
- /* Keep reading until PQgetResult returns NULL */
- }
- else
- {
- /* Query finished, so we're done */
- conn->setenv_state = SETENV_STATE_IDLE;
- return PGRES_POLLING_OK;
- }
- break;
- }
-
- default:
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("invalid state %c, "
- "probably indicative of memory corruption\n"),
- conn->setenv_state);
- goto error_return;
- }
- }
-
- /* Unreachable */
-
-error_return:
- conn->setenv_state = SETENV_STATE_IDLE;
- return PGRES_POLLING_FAILED;
-}
-
-
-/*
- * parseInput: if appropriate, parse input data from backend
- * until input is exhausted or a stopping state is reached.
- * Note that this function will NOT attempt to read more data from the backend.
- */
-void
-pqParseInput2(PGconn *conn)
-{
- char id;
-
- /*
- * Loop to parse successive complete messages available in the buffer.
- */
- for (;;)
- {
- /*
- * Quit if in COPY_OUT state: we expect raw data from the server until
- * PQendcopy is called. Don't try to parse it according to the normal
- * protocol. (This is bogus. The data lines ought to be part of the
- * protocol and have identifying leading characters.)
- */
- if (conn->asyncStatus == PGASYNC_COPY_OUT)
- return;
-
- /*
- * OK to try to read a message type code.
- */
- conn->inCursor = conn->inStart;
- if (pqGetc(&id, conn))
- return;
-
- /*
- * NOTIFY and NOTICE messages can happen in any state besides COPY
- * OUT; always process them right away.
- *
- * Most other messages should only be processed while in BUSY state.
- * (In particular, in READY state we hold off further parsing until
- * the application collects the current PGresult.)
- *
- * However, if the state is IDLE then we got trouble; we need to deal
- * with the unexpected message somehow.
- */
- if (id == 'A')
- {
- if (getNotify(conn))
- return;
- }
- else if (id == 'N')
- {
- if (pqGetErrorNotice2(conn, false))
- return;
- }
- else if (conn->asyncStatus != PGASYNC_BUSY)
- {
- /* If not IDLE state, just wait ... */
- if (conn->asyncStatus != PGASYNC_IDLE)
- return;
-
- /*
- * Unexpected message in IDLE state; need to recover somehow.
- * ERROR messages are displayed using the notice processor;
- * anything else is just dropped on the floor after displaying a
- * suitable warning notice. (An ERROR is very possibly the
- * backend telling us why it is about to close the connection, so
- * we don't want to just discard it...)
- */
- if (id == 'E')
- {
- if (pqGetErrorNotice2(conn, false /* treat as notice */ ))
- return;
- }
- else
- {
- pqInternalNotice(&conn->noticeHooks,
- "message type 0x%02x arrived from server while idle",
- id);
- /* Discard the unexpected message; good idea?? */
- conn->inStart = conn->inEnd;
- break;
- }
- }
- else
- {
- /*
- * In BUSY state, we can process everything.
- */
- switch (id)
- {
- case 'C': /* command complete */
- if (pqGets(&conn->workBuffer, conn))
- return;
- if (conn->result == NULL)
- {
- conn->result = PQmakeEmptyPGresult(conn,
- PGRES_COMMAND_OK);
- if (!conn->result)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("out of memory"));
- pqSaveErrorResult(conn);
- }
- }
- if (conn->result)
- {
- strlcpy(conn->result->cmdStatus, conn->workBuffer.data,
- CMDSTATUS_LEN);
- }
- checkXactStatus(conn, conn->workBuffer.data);
- conn->asyncStatus = PGASYNC_READY;
- break;
- case 'E': /* error return */
- if (pqGetErrorNotice2(conn, true))
- return;
- conn->asyncStatus = PGASYNC_READY;
- break;
- case 'Z': /* backend is ready for new query */
- conn->asyncStatus = PGASYNC_IDLE;
- break;
- case 'I': /* empty query */
- /* read and throw away the closing '\0' */
- if (pqGetc(&id, conn))
- return;
- if (id != '\0')
- pqInternalNotice(&conn->noticeHooks,
- "unexpected character %c following empty query response (\"I\" message)",
- id);
- if (conn->result == NULL)
- {
- conn->result = PQmakeEmptyPGresult(conn,
- PGRES_EMPTY_QUERY);
- if (!conn->result)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("out of memory"));
- pqSaveErrorResult(conn);
- }
- }
- conn->asyncStatus = PGASYNC_READY;
- break;
- case 'K': /* secret key data from the backend */
-
- /*
- * This is expected only during backend startup, but it's
- * just as easy to handle it as part of the main loop.
- * Save the data and continue processing.
- */
- if (pqGetInt(&(conn->be_pid), 4, conn))
- return;
- if (pqGetInt(&(conn->be_key), 4, conn))
- return;
- break;
- case 'P': /* synchronous (normal) portal */
- if (pqGets(&conn->workBuffer, conn))
- return;
- /* We pretty much ignore this message type... */
- break;
- case 'T': /* row descriptions (start of query results) */
- if (conn->result == NULL)
- {
- /* First 'T' in a query sequence */
- if (getRowDescriptions(conn))
- return;
- /* getRowDescriptions() moves inStart itself */
- continue;
- }
- else
- {
- /*
- * A new 'T' message is treated as the start of
- * another PGresult. (It is not clear that this is
- * really possible with the current backend.) We stop
- * parsing until the application accepts the current
- * result.
- */
- conn->asyncStatus = PGASYNC_READY;
- return;
- }
- break;
- case 'D': /* ASCII data tuple */
- if (conn->result != NULL)
- {
- /* Read another tuple of a normal query response */
- if (getAnotherTuple(conn, false))
- return;
- /* getAnotherTuple() moves inStart itself */
- continue;
- }
- else
- {
- pqInternalNotice(&conn->noticeHooks,
- "server sent data (\"D\" message) without prior row description (\"T\" message)");
- /* Discard the unexpected message; good idea?? */
- conn->inStart = conn->inEnd;
- return;
- }
- break;
- case 'B': /* Binary data tuple */
- if (conn->result != NULL)
- {
- /* Read another tuple of a normal query response */
- if (getAnotherTuple(conn, true))
- return;
- /* getAnotherTuple() moves inStart itself */
- continue;
- }
- else
- {
- pqInternalNotice(&conn->noticeHooks,
- "server sent binary data (\"B\" message) without prior row description (\"T\" message)");
- /* Discard the unexpected message; good idea?? */
- conn->inStart = conn->inEnd;
- return;
- }
- break;
- case 'G': /* Start Copy In */
- conn->asyncStatus = PGASYNC_COPY_IN;
- break;
- case 'H': /* Start Copy Out */
- conn->asyncStatus = PGASYNC_COPY_OUT;
- break;
-
- /*
- * Don't need to process CopyBothResponse here because it
- * never arrives from the server during protocol 2.0.
- */
- default:
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("unexpected response from server; first received character was \"%c\"\n"),
- id);
- /* build an error result holding the error message */
- pqSaveErrorResult(conn);
- /* Discard the unexpected message; good idea?? */
- conn->inStart = conn->inEnd;
- conn->asyncStatus = PGASYNC_READY;
- return;
- } /* switch on protocol character */
- }
- /* Successfully consumed this message */
- conn->inStart = conn->inCursor;
- }
-}
-
-/*
- * parseInput subroutine to read a 'T' (row descriptions) message.
- * We build a PGresult structure containing the attribute data.
- * Returns: 0 if completed message, EOF if error or not enough data
- * received yet.
- *
- * Note that if we run out of data, we have to suspend and reprocess
- * the message after more data is received. Otherwise, conn->inStart
- * must get advanced past the processed data.
- */
-static int
-getRowDescriptions(PGconn *conn)
-{
- PGresult *result;
- int nfields;
- const char *errmsg;
- int i;
-
- result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
- if (!result)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
-
- /* parseInput already read the 'T' label. */
- /* the next two bytes are the number of fields */
- if (pqGetInt(&(result->numAttributes), 2, conn))
- goto EOFexit;
- nfields = result->numAttributes;
-
- /* allocate space for the attribute descriptors */
- if (nfields > 0)
- {
- result->attDescs = (PGresAttDesc *)
- pqResultAlloc(result, nfields * sizeof(PGresAttDesc), true);
- if (!result->attDescs)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
- MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
- }
-
- /* get type info */
- for (i = 0; i < nfields; i++)
- {
- int typid;
- int typlen;
- int atttypmod;
-
- if (pqGets(&conn->workBuffer, conn) ||
- pqGetInt(&typid, 4, conn) ||
- pqGetInt(&typlen, 2, conn) ||
- pqGetInt(&atttypmod, 4, conn))
- goto EOFexit;
-
- /*
- * Since pqGetInt treats 2-byte integers as unsigned, we need to
- * coerce the result to signed form.
- */
- typlen = (int) ((int16) typlen);
-
- result->attDescs[i].name = pqResultStrdup(result,
- conn->workBuffer.data);
- if (!result->attDescs[i].name)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
- result->attDescs[i].tableid = 0;
- result->attDescs[i].columnid = 0;
- result->attDescs[i].format = 0;
- result->attDescs[i].typid = typid;
- result->attDescs[i].typlen = typlen;
- result->attDescs[i].atttypmod = atttypmod;
- }
-
- /* Success! */
- conn->result = result;
-
- /* Advance inStart to show that the "T" message has been processed. */
- conn->inStart = conn->inCursor;
-
- /*
- * We could perform additional setup for the new result set here, but for
- * now there's nothing else to do.
- */
-
- /* And we're done. */
- return 0;
-
-advance_and_error:
-
- /*
- * Discard the failed message. Unfortunately we don't know for sure where
- * the end is, so just throw away everything in the input buffer. This is
- * not very desirable but it's the best we can do in protocol v2.
- */
- conn->inStart = conn->inEnd;
-
- /*
- * Replace partially constructed result with an error result. First
- * discard the old result to try to win back some memory.
- */
- pqClearAsyncResult(conn);
-
- /*
- * If preceding code didn't provide an error message, assume "out of
- * memory" was meant. The advantage of having this special case is that
- * freeing the old result first greatly improves the odds that gettext()
- * will succeed in providing a translation.
- */
- if (!errmsg)
- errmsg = libpq_gettext("out of memory for query result");
-
- appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
-
- /*
- * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can
- * do to recover...
- */
- conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
- conn->asyncStatus = PGASYNC_READY;
-
-EOFexit:
- if (result && result != conn->result)
- PQclear(result);
- return EOF;
-}
-
-/*
- * parseInput subroutine to read a 'B' or 'D' (row data) message.
- * We fill rowbuf with column pointers and then call the row processor.
- * Returns: 0 if completed message, EOF if error or not enough data
- * received yet.
- *
- * Note that if we run out of data, we have to suspend and reprocess
- * the message after more data is received. Otherwise, conn->inStart
- * must get advanced past the processed data.
- */
-static int
-getAnotherTuple(PGconn *conn, bool binary)
-{
- PGresult *result = conn->result;
- int nfields = result->numAttributes;
- const char *errmsg;
- PGdataValue *rowbuf;
-
- /* the backend sends us a bitmap of which attributes are null */
- char std_bitmap[64]; /* used unless it doesn't fit */
- char *bitmap = std_bitmap;
- int i;
- size_t nbytes; /* the number of bytes in bitmap */
- char bmap; /* One byte of the bitmap */
- int bitmap_index; /* Its index */
- int bitcnt; /* number of bits examined in current byte */
- int vlen; /* length of the current field value */
-
- /* Resize row buffer if needed */
- rowbuf = conn->rowBuf;
- if (nfields > conn->rowBufLen)
- {
- rowbuf = (PGdataValue *) realloc(rowbuf,
- nfields * sizeof(PGdataValue));
- if (!rowbuf)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
- conn->rowBuf = rowbuf;
- conn->rowBufLen = nfields;
- }
-
- /* Save format specifier */
- result->binary = binary;
-
- /*
- * If it's binary, fix the column format indicators. We assume the
- * backend will consistently send either B or D, not a mix.
- */
- if (binary)
- {
- for (i = 0; i < nfields; i++)
- result->attDescs[i].format = 1;
- }
-
- /* Get the null-value bitmap */
- nbytes = (nfields + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
- /* malloc() only for unusually large field counts... */
- if (nbytes > sizeof(std_bitmap))
- {
- bitmap = (char *) malloc(nbytes);
- if (!bitmap)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
- }
-
- if (pqGetnchar(bitmap, nbytes, conn))
- goto EOFexit;
-
- /* Scan the fields */
- bitmap_index = 0;
- bmap = bitmap[bitmap_index];
- bitcnt = 0;
-
- for (i = 0; i < nfields; i++)
- {
- /* get the value length */
- if (!(bmap & 0200))
- vlen = NULL_LEN;
- else if (pqGetInt(&vlen, 4, conn))
- goto EOFexit;
- else
- {
- if (!binary)
- vlen = vlen - 4;
- if (vlen < 0)
- vlen = 0;
- }
- rowbuf[i].len = vlen;
-
- /*
- * rowbuf[i].value always points to the next address in the data
- * buffer even if the value is NULL. This allows row processors to
- * estimate data sizes more easily.
- */
- rowbuf[i].value = conn->inBuffer + conn->inCursor;
-
- /* Skip over the data value */
- if (vlen > 0)
- {
- if (pqSkipnchar(vlen, conn))
- goto EOFexit;
- }
-
- /* advance the bitmap stuff */
- bitcnt++;
- if (bitcnt == BITS_PER_BYTE)
- {
- bitmap_index++;
- bmap = bitmap[bitmap_index];
- bitcnt = 0;
- }
- else
- bmap <<= 1;
- }
-
- /* Release bitmap now if we allocated it */
- if (bitmap != std_bitmap)
- free(bitmap);
- bitmap = NULL;
-
- /* Advance inStart to show that the "D" message has been processed. */
- conn->inStart = conn->inCursor;
-
- /* Process the collected row */
- errmsg = NULL;
- if (pqRowProcessor(conn, &errmsg))
- return 0; /* normal, successful exit */
-
- goto set_error_result; /* pqRowProcessor failed, report it */
-
-advance_and_error:
-
- /*
- * Discard the failed message. Unfortunately we don't know for sure where
- * the end is, so just throw away everything in the input buffer. This is
- * not very desirable but it's the best we can do in protocol v2.
- */
- conn->inStart = conn->inEnd;
-
-set_error_result:
-
- /*
- * Replace partially constructed result with an error result. First
- * discard the old result to try to win back some memory.
- */
- pqClearAsyncResult(conn);
-
- /*
- * If preceding code didn't provide an error message, assume "out of
- * memory" was meant. The advantage of having this special case is that
- * freeing the old result first greatly improves the odds that gettext()
- * will succeed in providing a translation.
- */
- if (!errmsg)
- errmsg = libpq_gettext("out of memory for query result");
-
- appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
-
- /*
- * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can
- * do to recover...
- */
- conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
- conn->asyncStatus = PGASYNC_READY;
-
-EOFexit:
- if (bitmap != NULL && bitmap != std_bitmap)
- free(bitmap);
- return EOF;
-}
-
-
-/*
- * Attempt to read an Error or Notice response message.
- * This is possible in several places, so we break it out as a subroutine.
- * Entry: 'E' or 'N' message type has already been consumed.
- * Exit: returns 0 if successfully consumed message.
- * returns EOF if not enough data.
- */
-static int
-pqGetErrorNotice2(PGconn *conn, bool isError)
-{
- PGresult *res = NULL;
- PQExpBufferData workBuf;
- char *startp;
- char *splitp;
-
- /*
- * If this is an error message, pre-emptively clear any incomplete query
- * result we may have. We'd just throw it away below anyway, and
- * releasing it before collecting the error might avoid out-of-memory.
- */
- if (isError)
- pqClearAsyncResult(conn);
-
- /*
- * Since the message might be pretty long, we create a temporary
- * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended
- * for stuff that is expected to be short.
- */
- initPQExpBuffer(&workBuf);
- if (pqGets(&workBuf, conn))
- goto failure;
-
- /*
- * Make a PGresult to hold the message. We temporarily lie about the
- * result status, so that PQmakeEmptyPGresult doesn't uselessly copy
- * conn->errorMessage.
- *
- * NB: This allocation can fail, if you run out of memory. The rest of the
- * function handles that gracefully, and we still try to set the error
- * message as the connection's error message.
- */
- res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
- if (res)
- {
- res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
- res->errMsg = pqResultStrdup(res, workBuf.data);
- }
-
- /*
- * Break the message into fields. We can't do very much here, but we can
- * split the severity code off, and remove trailing newlines. Also, we use
- * the heuristic that the primary message extends only to the first
- * newline --- anything after that is detail message. (In some cases it'd
- * be better classed as hint, but we can hardly be expected to guess that
- * here.)
- */
- while (workBuf.len > 0 && workBuf.data[workBuf.len - 1] == '\n')
- workBuf.data[--workBuf.len] = '\0';
- splitp = strstr(workBuf.data, ": ");
- if (splitp)
- {
- /* what comes before the colon is severity */
- *splitp = '\0';
- pqSaveMessageField(res, PG_DIAG_SEVERITY, workBuf.data);
- startp = splitp + 3;
- }
- else
- {
- /* can't find a colon? oh well... */
- startp = workBuf.data;
- }
- splitp = strchr(startp, '\n');
- if (splitp)
- {
- /* what comes before the newline is primary message */
- *splitp++ = '\0';
- pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp);
- /* the rest is detail; strip any leading whitespace */
- while (*splitp && isspace((unsigned char) *splitp))
- splitp++;
- pqSaveMessageField(res, PG_DIAG_MESSAGE_DETAIL, splitp);
- }
- else
- {
- /* single-line message, so all primary */
- pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp);
- }
-
- /*
- * Either save error as current async result, or just emit the notice.
- * Also, if it's an error and we were in a transaction block, assume the
- * server has now gone to error-in-transaction state.
- */
- if (isError)
- {
- pqClearAsyncResult(conn); /* redundant, but be safe */
- conn->result = res;
- if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg)
- appendPQExpBufferStr(&conn->errorMessage, res->errMsg);
- else
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("out of memory"));
- if (conn->xactStatus == PQTRANS_INTRANS)
- conn->xactStatus = PQTRANS_INERROR;
- }
- else
- {
- if (res)
- {
- if (res->noticeHooks.noticeRec != NULL)
- res->noticeHooks.noticeRec(res->noticeHooks.noticeRecArg, res);
- PQclear(res);
- }
- }
-
- termPQExpBuffer(&workBuf);
- return 0;
-
-failure:
- if (res)
- PQclear(res);
- termPQExpBuffer(&workBuf);
- return EOF;
-}
-
-/*
- * checkXactStatus - attempt to track transaction-block status of server
- *
- * This is called each time we receive a command-complete message. By
- * watching for messages from BEGIN/COMMIT/ROLLBACK commands, we can do
- * a passable job of tracking the server's xact status. BUT: this does
- * not work at all on 7.3 servers with AUTOCOMMIT OFF. (Man, was that
- * feature ever a mistake.) Caveat user.
- *
- * The tags known here are all those used as far back as 7.0; is it worth
- * adding those from even-older servers?
- */
-static void
-checkXactStatus(PGconn *conn, const char *cmdTag)
-{
- if (strcmp(cmdTag, "BEGIN") == 0)
- conn->xactStatus = PQTRANS_INTRANS;
- else if (strcmp(cmdTag, "COMMIT") == 0)
- conn->xactStatus = PQTRANS_IDLE;
- else if (strcmp(cmdTag, "ROLLBACK") == 0)
- conn->xactStatus = PQTRANS_IDLE;
- else if (strcmp(cmdTag, "START TRANSACTION") == 0) /* 7.3 only */
- conn->xactStatus = PQTRANS_INTRANS;
-
- /*
- * Normally we get into INERROR state by detecting an Error message.
- * However, if we see one of these tags then we know for sure the server
- * is in abort state ...
- */
- else if (strcmp(cmdTag, "*ABORT STATE*") == 0) /* pre-7.3 only */
- conn->xactStatus = PQTRANS_INERROR;
-}
-
-/*
- * Attempt to read a Notify response message.
- * This is possible in several places, so we break it out as a subroutine.
- * Entry: 'A' message type and length have already been consumed.
- * Exit: returns 0 if successfully consumed Notify message.
- * returns EOF if not enough data.
- */
-static int
-getNotify(PGconn *conn)
-{
- int be_pid;
- int nmlen;
- PGnotify *newNotify;
-
- if (pqGetInt(&be_pid, 4, conn))
- return EOF;
- if (pqGets(&conn->workBuffer, conn))
- return EOF;
-
- /*
- * Store the relation name right after the PQnotify structure so it can
- * all be freed at once. We don't use NAMEDATALEN because we don't want
- * to tie this interface to a specific server name length.
- */
- nmlen = strlen(conn->workBuffer.data);
- newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + 1);
- if (newNotify)
- {
- newNotify->relname = (char *) newNotify + sizeof(PGnotify);
- strcpy(newNotify->relname, conn->workBuffer.data);
- /* fake up an empty-string extra field */
- newNotify->extra = newNotify->relname + nmlen;
- newNotify->be_pid = be_pid;
- newNotify->next = NULL;
- if (conn->notifyTail)
- conn->notifyTail->next = newNotify;
- else
- conn->notifyHead = newNotify;
- conn->notifyTail = newNotify;
- }
-
- return 0;
-}
-
-
-/*
- * PQgetCopyData - read a row of data from the backend during COPY OUT
- *
- * If successful, sets *buffer to point to a malloc'd row of data, and
- * returns row length (always > 0) as result.
- * Returns 0 if no row available yet (only possible if async is true),
- * -1 if end of copy (consult PQgetResult), or -2 if error (consult
- * PQerrorMessage).
- */
-int
-pqGetCopyData2(PGconn *conn, char **buffer, int async)
-{
- bool found;
- int msgLength;
-
- for (;;)
- {
- /*
- * Do we have a complete line of data?
- */
- conn->inCursor = conn->inStart;
- found = false;
- while (conn->inCursor < conn->inEnd)
- {
- char c = conn->inBuffer[conn->inCursor++];
-
- if (c == '\n')
- {
- found = true;
- break;
- }
- }
- if (!found)
- goto nodata;
- msgLength = conn->inCursor - conn->inStart;
-
- /*
- * If it's the end-of-data marker, consume it, exit COPY_OUT mode, and
- * let caller read status with PQgetResult().
- */
- if (msgLength == 3 &&
- strncmp(&conn->inBuffer[conn->inStart], "\\.\n", 3) == 0)
- {
- conn->inStart = conn->inCursor;
- conn->asyncStatus = PGASYNC_BUSY;
- return -1;
- }
-
- /*
- * Pass the line back to the caller.
- */
- *buffer = (char *) malloc(msgLength + 1);
- if (*buffer == NULL)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("out of memory\n"));
- return -2;
- }
- memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength);
- (*buffer)[msgLength] = '\0'; /* Add terminating null */
-
- /* Mark message consumed */
- conn->inStart = conn->inCursor;
-
- return msgLength;
-
-nodata:
- /* Don't block if async read requested */
- if (async)
- return 0;
- /* Need to load more data */
- if (pqWait(true, false, conn) ||
- pqReadData(conn) < 0)
- return -2;
- }
-}
-
-
-/*
- * PQgetline - gets a newline-terminated string from the backend.
- *
- * See fe-exec.c for documentation.
- */
-int
-pqGetline2(PGconn *conn, char *s, int maxlen)
-{
- int result = 1; /* return value if buffer overflows */
-
- if (conn->sock == PGINVALID_SOCKET ||
- conn->asyncStatus != PGASYNC_COPY_OUT)
- {
- *s = '\0';
- return EOF;
- }
-
- /*
- * Since this is a purely synchronous routine, we don't bother to maintain
- * conn->inCursor; there is no need to back up.
- */
- while (maxlen > 1)
- {
- if (conn->inStart < conn->inEnd)
- {
- char c = conn->inBuffer[conn->inStart++];
-
- if (c == '\n')
- {
- result = 0; /* success exit */
- break;
- }
- *s++ = c;
- maxlen--;
- }
- else
- {
- /* need to load more data */
- if (pqWait(true, false, conn) ||
- pqReadData(conn) < 0)
- {
- result = EOF;
- break;
- }
- }
- }
- *s = '\0';
-
- return result;
-}
-
-/*
- * PQgetlineAsync - gets a COPY data row without blocking.
- *
- * See fe-exec.c for documentation.
- */
-int
-pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize)
-{
- int avail;
-
- if (conn->asyncStatus != PGASYNC_COPY_OUT)
- return -1; /* we are not doing a copy... */
-
- /*
- * Move data from libpq's buffer to the caller's. We want to accept data
- * only in units of whole lines, not partial lines. This ensures that we
- * can recognize the terminator line "\\.\n". (Otherwise, if it happened
- * to cross a packet/buffer boundary, we might hand the first one or two
- * characters off to the caller, which we shouldn't.)
- */
-
- conn->inCursor = conn->inStart;
-
- avail = bufsize;
- while (avail > 0 && conn->inCursor < conn->inEnd)
- {
- char c = conn->inBuffer[conn->inCursor++];
-
- *buffer++ = c;
- --avail;
- if (c == '\n')
- {
- /* Got a complete line; mark the data removed from libpq */
- conn->inStart = conn->inCursor;
- /* Is it the endmarker line? */
- if (bufsize - avail == 3 && buffer[-3] == '\\' && buffer[-2] == '.')
- return -1;
- /* No, return the data line to the caller */
- return bufsize - avail;
- }
- }
-
- /*
- * We don't have a complete line. We'd prefer to leave it in libpq's
- * buffer until the rest arrives, but there is a special case: what if the
- * line is longer than the buffer the caller is offering us? In that case
- * we'd better hand over a partial line, else we'd get into an infinite
- * loop. Do this in a way that ensures we can't misrecognize a terminator
- * line later: leave last 3 characters in libpq buffer.
- */
- if (avail == 0 && bufsize > 3)
- {
- conn->inStart = conn->inCursor - 3;
- return bufsize - 3;
- }
- return 0;
-}
-
-/*
- * PQendcopy
- *
- * See fe-exec.c for documentation.
- */
-int
-pqEndcopy2(PGconn *conn)
-{
- PGresult *result;
-
- if (conn->asyncStatus != PGASYNC_COPY_IN &&
- conn->asyncStatus != PGASYNC_COPY_OUT)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("no COPY in progress\n"));
- return 1;
- }
-
- /*
- * make sure no data is waiting to be sent, abort if we are non-blocking
- * and the flush fails
- */
- if (pqFlush(conn) && pqIsnonblocking(conn))
- return 1;
-
- /* non blocking connections may have to abort at this point. */
- if (pqIsnonblocking(conn) && PQisBusy(conn))
- return 1;
-
- /* Return to active duty */
- conn->asyncStatus = PGASYNC_BUSY;
-
- /* Wait for the completion response */
- result = PQgetResult(conn);
-
- /* Expecting a successful result */
- if (result && result->resultStatus == PGRES_COMMAND_OK)
- {
- PQclear(result);
- return 0;
- }
-
- /*
- * Trouble. For backwards-compatibility reasons, we issue the error
- * message as if it were a notice (would be nice to get rid of this
- * silliness, but too many apps probably don't handle errors from
- * PQendcopy reasonably). Note that the app can still obtain the error
- * status from the PGconn object.
- */
- if (conn->errorMessage.len > 0)
- {
- /* We have to strip the trailing newline ... pain in neck... */
- char svLast = conn->errorMessage.data[conn->errorMessage.len - 1];
-
- if (svLast == '\n')
- conn->errorMessage.data[conn->errorMessage.len - 1] = '\0';
- pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data);
- conn->errorMessage.data[conn->errorMessage.len - 1] = svLast;
- }
-
- PQclear(result);
-
- /*
- * The worst case is that we've lost sync with the backend entirely due to
- * application screwup of the copy in/out protocol. To recover, reset the
- * connection (talk about using a sledgehammer...)
- */
- pqInternalNotice(&conn->noticeHooks,
- "lost synchronization with server, resetting connection");
-
- /*
- * Users doing non-blocking connections need to handle the reset
- * themselves, they'll need to check the connection status if we return an
- * error.
- */
- if (pqIsnonblocking(conn))
- PQresetStart(conn);
- else
- PQreset(conn);
-
- return 1;
-}
-
-
-/*
- * PQfn - Send a function call to the POSTGRES backend.
- *
- * See fe-exec.c for documentation.
- */
-PGresult *
-pqFunctionCall2(PGconn *conn, Oid fnid,
- int *result_buf, int *actual_result_len,
- int result_is_int,
- const PQArgBlock *args, int nargs)
-{
- bool needInput = false;
- ExecStatusType status = PGRES_FATAL_ERROR;
- char id;
- int i;
-
- /* PQfn already validated connection state */
-
- if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */
- pqPuts(" ", conn) < 0 || /* dummy string */
- pqPutInt(fnid, 4, conn) != 0 || /* function id */
- pqPutInt(nargs, 4, conn) != 0) /* # of args */
- {
- /* error message should be set up already */
- return NULL;
- }
-
- for (i = 0; i < nargs; ++i)
- { /* len.int4 + contents */
- if (pqPutInt(args[i].len, 4, conn))
- return NULL;
-
- if (args[i].isint)
- {
- if (pqPutInt(args[i].u.integer, 4, conn))
- return NULL;
- }
- else
- {
- if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn))
- return NULL;
- }
- }
-
- if (pqPutMsgEnd(conn) < 0 ||
- pqFlush(conn))
- return NULL;
-
- for (;;)
- {
- if (needInput)
- {
- /* Wait for some data to arrive (or for the channel to close) */
- if (pqWait(true, false, conn) ||
- pqReadData(conn) < 0)
- break;
- }
-
- /*
- * Scan the message. If we run out of data, loop around to try again.
- */
- conn->inCursor = conn->inStart;
- needInput = true;
-
- if (pqGetc(&id, conn))
- continue;
-
- /*
- * We should see V or E response to the command, but might get N
- * and/or A notices first. We also need to swallow the final Z before
- * returning.
- */
- switch (id)
- {
- case 'V': /* function result */
- if (pqGetc(&id, conn))
- continue;
- if (id == 'G')
- {
- /* function returned nonempty value */
- if (pqGetInt(actual_result_len, 4, conn))
- continue;
- if (result_is_int)
- {
- if (pqGetInt(result_buf, 4, conn))
- continue;
- }
- else
- {
- if (pqGetnchar((char *) result_buf,
- *actual_result_len,
- conn))
- continue;
- }
- if (pqGetc(&id, conn)) /* get the last '0' */
- continue;
- }
- if (id == '0')
- {
- /* correctly finished function result message */
- status = PGRES_COMMAND_OK;
- }
- else
- {
- /* The backend violates the protocol. */
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("protocol error: id=0x%x\n"),
- id);
- pqSaveErrorResult(conn);
- conn->inStart = conn->inCursor;
- return pqPrepareAsyncResult(conn);
- }
- break;
- case 'E': /* error return */
- if (pqGetErrorNotice2(conn, true))
- continue;
- status = PGRES_FATAL_ERROR;
- break;
- case 'A': /* notify message */
- /* handle notify and go back to processing return values */
- if (getNotify(conn))
- continue;
- break;
- case 'N': /* notice */
- /* handle notice and go back to processing return values */
- if (pqGetErrorNotice2(conn, false))
- continue;
- break;
- case 'Z': /* backend is ready for new query */
- /* consume the message and exit */
- conn->inStart = conn->inCursor;
- /* if we saved a result object (probably an error), use it */
- if (conn->result)
- return pqPrepareAsyncResult(conn);
- return PQmakeEmptyPGresult(conn, status);
- default:
- /* The backend violates the protocol. */
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("protocol error: id=0x%x\n"),
- id);
- pqSaveErrorResult(conn);
- conn->inStart = conn->inCursor;
- return pqPrepareAsyncResult(conn);
- }
- /* Completed this message, keep going */
- conn->inStart = conn->inCursor;
- needInput = false;
- }
-
- /*
- * We fall out of the loop only upon failing to read data.
- * conn->errorMessage has been set by pqWait or pqReadData. We want to
- * append it to any already-received error message.
- */
- pqSaveErrorResult(conn);
- return pqPrepareAsyncResult(conn);
-}
-
-
-/*
- * Construct startup packet
- *
- * Returns a malloc'd packet buffer, or NULL if out of memory
- */
-char *
-pqBuildStartupPacket2(PGconn *conn, int *packetlen,
- const PQEnvironmentOption *options)
-{
- StartupPacket *startpacket;
-
- *packetlen = sizeof(StartupPacket);
- startpacket = (StartupPacket *) malloc(sizeof(StartupPacket));
- if (!startpacket)
- return NULL;
-
- MemSet(startpacket, 0, sizeof(StartupPacket));
-
- startpacket->protoVersion = pg_hton32(conn->pversion);
-
- /* strncpy is safe here: postmaster will handle full fields correctly */
- strncpy(startpacket->user, conn->pguser, SM_USER);
- strncpy(startpacket->database, conn->dbName, SM_DATABASE);
- strncpy(startpacket->tty, conn->pgtty, SM_TTY);
-
- if (conn->pgoptions)
- strncpy(startpacket->options, conn->pgoptions, SM_OPTIONS);
-
- return (char *) startpacket;
-}
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index e4ee9d69d25..2ca8c057b9d 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -1843,7 +1843,7 @@ pqEndcopy3(PGconn *conn)
if (conn->asyncStatus == PGASYNC_COPY_IN ||
conn->asyncStatus == PGASYNC_COPY_BOTH)
{
- if (pqPutMsgStart('c', false, conn) < 0 ||
+ if (pqPutMsgStart('c', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return 1;
@@ -1853,7 +1853,7 @@ pqEndcopy3(PGconn *conn)
*/
if (conn->queryclass != PGQUERY_SIMPLE)
{
- if (pqPutMsgStart('S', false, conn) < 0 ||
+ if (pqPutMsgStart('S', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return 1;
}
@@ -1933,7 +1933,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid,
/* PQfn already validated connection state */
- if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */
+ if (pqPutMsgStart('F', conn) < 0 || /* function call msg */
pqPutInt(fnid, 4, conn) < 0 || /* function id */
pqPutInt(1, 2, conn) < 0 || /* # of format codes */
pqPutInt(1, 2, conn) < 0 || /* format code: BINARY */
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 47a098b4b93..fa9b62a8449 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -60,7 +60,7 @@ typedef enum
* postmaster. */
CONNECTION_AUTH_OK, /* Received authentication; waiting for
* backend startup. */
- CONNECTION_SETENV, /* Negotiating environment. */
+ CONNECTION_SETENV, /* This state is no longer used. */
CONNECTION_SSL_STARTUP, /* Negotiating SSL. */
CONNECTION_NEEDED, /* Internal state: connect() needed */
CONNECTION_CHECK_WRITABLE, /* Checking if session is read-write. */
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 0c9e95f1a7a..8d51e6ed9ff 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -252,22 +252,6 @@ typedef enum
PG_BOOL_NO /* No (false) */
} PGTernaryBool;
-/* PGSetenvStatusType defines the state of the pqSetenv state machine */
-
-/* (this is used only for 2.0-protocol connections) */
-typedef enum
-{
- SETENV_STATE_CLIENT_ENCODING_SEND, /* About to send an Environment Option */
- SETENV_STATE_CLIENT_ENCODING_WAIT, /* Waiting for above send to complete */
- SETENV_STATE_OPTION_SEND, /* About to send an Environment Option */
- SETENV_STATE_OPTION_WAIT, /* Waiting for above send to complete */
- SETENV_STATE_QUERY1_SEND, /* About to send a status query */
- SETENV_STATE_QUERY1_WAIT, /* Waiting for query to complete */
- SETENV_STATE_QUERY2_SEND, /* About to send a status query */
- SETENV_STATE_QUERY2_WAIT, /* Waiting for query to complete */
- SETENV_STATE_IDLE
-} PGSetenvStatusType;
-
/* Typedef for the EnvironmentOptions[] array */
typedef struct PQEnvironmentOption
{
@@ -446,8 +430,6 @@ struct pg_conn
struct addrinfo *addrlist; /* list of addresses for current connhost */
struct addrinfo *addr_cur; /* the one currently being tried */
int addrlist_family; /* needed to know how to free addrlist */
- PGSetenvStatusType setenv_state; /* for 2.0 protocol only */
- const PQEnvironmentOption *next_eo;
bool send_appname; /* okay to send application_name? */
/* Miscellaneous stuff */
@@ -639,22 +621,6 @@ extern void pqSaveParameterStatus(PGconn *conn, const char *name,
extern int pqRowProcessor(PGconn *conn, const char **errmsgp);
extern int PQsendQueryContinue(PGconn *conn, const char *query);
-/* === in fe-protocol2.c === */
-
-extern PostgresPollingStatusType pqSetenvPoll(PGconn *conn);
-
-extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen,
- const PQEnvironmentOption *options);
-extern void pqParseInput2(PGconn *conn);
-extern int pqGetCopyData2(PGconn *conn, char **buffer, int async);
-extern int pqGetline2(PGconn *conn, char *s, int maxlen);
-extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize);
-extern int pqEndcopy2(PGconn *conn);
-extern PGresult *pqFunctionCall2(PGconn *conn, Oid fnid,
- int *result_buf, int *actual_result_len,
- int result_is_int,
- const PQArgBlock *args, int nargs);
-
/* === in fe-protocol3.c === */
extern char *pqBuildStartupPacket3(PGconn *conn, int *packetlen,
@@ -691,7 +657,7 @@ extern int pqSkipnchar(size_t len, PGconn *conn);
extern int pqPutnchar(const char *s, size_t len, PGconn *conn);
extern int pqGetInt(int *result, size_t bytes, PGconn *conn);
extern int pqPutInt(int value, size_t bytes, PGconn *conn);
-extern int pqPutMsgStart(char msg_type, bool force_len, PGconn *conn);
+extern int pqPutMsgStart(char msg_type, PGconn *conn);
extern int pqPutMsgEnd(PGconn *conn);
extern int pqReadData(PGconn *conn);
extern int pqFlush(PGconn *conn);
diff --git a/src/interfaces/libpq/nls.mk b/src/interfaces/libpq/nls.mk
index 3175ae3e1c3..f64101b2a6a 100644
--- a/src/interfaces/libpq/nls.mk
+++ b/src/interfaces/libpq/nls.mk
@@ -1,6 +1,6 @@
# src/interfaces/libpq/nls.mk
CATALOG_NAME = libpq
AVAIL_LANGUAGES = cs de es fr he it ja ko pl pt_BR ru sv tr uk zh_CN zh_TW
-GETTEXT_FILES = fe-auth.c fe-auth-scram.c fe-connect.c fe-exec.c fe-gssapi-common.c fe-lobj.c fe-misc.c fe-protocol2.c fe-protocol3.c fe-secure.c fe-secure-common.c fe-secure-gssapi.c fe-secure-openssl.c win32.c
+GETTEXT_FILES = fe-auth.c fe-auth-scram.c fe-connect.c fe-exec.c fe-gssapi-common.c fe-lobj.c fe-misc.c fe-protocol3.c fe-secure.c fe-secure-common.c fe-secure-gssapi.c fe-secure-openssl.c win32.c
GETTEXT_TRIGGERS = libpq_gettext pqInternalNotice:2
GETTEXT_FLAGS = libpq_gettext:1:pass-c-format pqInternalNotice:2:c-format