diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d9c5ec1a006f24ec35234a674da05d8d6108e316..746f2af2166dfd04514e25f74a56c029cb23659e 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -21,7 +21,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.83 1998/09/01 04:33:45 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.84 1998/09/03 02:10:36 momjian Exp $
  *
  * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
  *
@@ -255,7 +255,7 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids)
 			copydone = false;
 			while (!copydone)
 			{
-				ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
+				ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
 
 				if (copybuf[0] == '\\' &&
 					copybuf[1] == '.' &&
@@ -281,7 +281,7 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids)
 			}
 			fprintf(fout, "\\.\n");
 		}
-		ret = PQendcopy(res->conn);
+		ret = PQendcopy(g_conn);
 		if (ret != 0)
 		{
 			fprintf(stderr, "SQL query to dump the contents of Table '%s' "
diff --git a/src/bin/psql/psql.c b/src/bin/psql/psql.c
index ecb441fbc785f1dde517754e4eb134e0f25bc80f..054faab480a51caf603d4cbff7fbb73873288e21 100644
--- a/src/bin/psql/psql.c
+++ b/src/bin/psql/psql.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.158 1998/09/01 04:33:51 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.159 1998/09/03 02:10:38 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -148,7 +148,7 @@ struct winsize
 /* declarations for functions in this file */
 static void usage(char *progname);
 static void slashUsage();
-static bool handleCopyOut(PGresult *res, FILE *copystream);
+static bool handleCopyOut(PGconn *conn, FILE *copystream);
 static bool handleCopyIn(PGresult *res, const bool mustprompt,
 			 FILE *copystream);
 static int tableList(PsqlSettings *pset, bool deep_tablelist,
@@ -1125,20 +1125,20 @@ SendQuery(bool *success_p, PsqlSettings *pset, const char *query,
 				break;
 			case PGRES_COPY_OUT:
 				if (copy_out)
-					*success_p = handleCopyOut(results, copystream);
+					*success_p = handleCopyOut(pset->db, copystream);
 				else
 				{
 					if (!pset->quiet)
 						printf("Copy command returns...\n");
 
-					*success_p = handleCopyOut(results, stdout);
+					*success_p = handleCopyOut(pset->db, stdout);
 				}
 				break;
 			case PGRES_COPY_IN:
 				if (copy_in)
-					*success_p = handleCopyIn(results, false, copystream);
+					*success_p = handleCopyIn(pset->db, false, copystream);
 				else
-					*success_p = handleCopyIn(results,
+					*success_p = handleCopyIn(pset->db,
 											!pset->quiet && !pset->notty,
 											  stdin);
 				break;
@@ -1437,11 +1437,8 @@ do_connect(const char *new_dbname,
 		else
 			userparam = PQuser(olddb);
 
-		/*
-		 * libpq doesn't provide an accessor function for the password, so
-		 * we cheat here.
-		 */
-		pwparam = olddb->pgpass;
+		/* FIXME: if changing user, ought to prompt for a new password? */
+		pwparam = PQpass(olddb);
 
 		pset->db = PQsetdbLogin(PQhost(olddb), PQport(olddb),
 								NULL, NULL, dbparam, userparam, pwparam);
@@ -2915,7 +2912,7 @@ main(int argc, char **argv)
 #define COPYBUFSIZ	8192
 
 static bool
-handleCopyOut(PGresult *res, FILE *copystream)
+handleCopyOut(PGconn *conn, FILE *copystream)
 {
 	bool		copydone;
 	char		copybuf[COPYBUFSIZ];
@@ -2925,7 +2922,7 @@ handleCopyOut(PGresult *res, FILE *copystream)
 
 	while (!copydone)
 	{
-		ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
+		ret = PQgetline(conn, copybuf, COPYBUFSIZ);
 
 		if (copybuf[0] == '\\' &&
 			copybuf[1] == '.' &&
@@ -2950,13 +2947,13 @@ handleCopyOut(PGresult *res, FILE *copystream)
 		}
 	}
 	fflush(copystream);
-	return !PQendcopy(res->conn);
+	return ! PQendcopy(conn);
 }
 
 
 
 static bool
-handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream)
+handleCopyIn(PGconn *conn, const bool mustprompt, FILE *copystream)
 {
 	bool		copydone = false;
 	bool		firstload;
@@ -2991,12 +2988,12 @@ handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream)
 				*s++ = c;
 			if (c == EOF)
 			{
-				PQputline(res->conn, "\\.");
+				PQputline(conn, "\\.");
 				copydone = true;
 				break;
 			}
 			*s = '\0';
-			PQputline(res->conn, copybuf);
+			PQputline(conn, copybuf);
 			if (firstload)
 			{
 				if (!strcmp(copybuf, "\\."))
@@ -3004,9 +3001,9 @@ handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream)
 				firstload = false;
 			}
 		}
-		PQputline(res->conn, "\n");
+		PQputline(conn, "\n");
 	}
-	return !PQendcopy(res->conn);
+	return ! PQendcopy(conn);
 }
 
 
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
index 3804544514030f7c1a8ea2567425d5be7be7ce13..4b7ed87c1ffce3259aecb6d595e5966178e206c4 100644
--- a/src/interfaces/ecpg/lib/ecpglib.c
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -814,11 +814,11 @@ ECPGexecute(struct statement * stmt)
 				break;
 			case PGRES_COPY_OUT:
 				ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno);
-				PQendcopy(results->conn);
+				PQendcopy(actual_connection->connection);
 				break;
 			case PGRES_COPY_IN:
 				ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno);
-				PQendcopy(results->conn);
+				PQendcopy(actual_connection->connection);
 				break;
 			default:
 				ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
@@ -995,7 +995,7 @@ ECPGlog(const char *format,...)
 		if (!f)
 			return;
 
-		sprintf(f, "[%d]: %s", getpid(), format);
+		sprintf(f, "[%d]: %s", (int) getpid(), format);
 
 		va_start(ap, format);
 		vfprintf(debugstream, f, ap);
diff --git a/src/interfaces/libpgtcl/pgtclCmds.c b/src/interfaces/libpgtcl/pgtclCmds.c
index bd6641554d2fba6625626cda667364f1127cb8ec..a8d828c0167747cf382bbe5bcff17ea51f41a7be 100644
--- a/src/interfaces/libpgtcl/pgtclCmds.c
+++ b/src/interfaces/libpgtcl/pgtclCmds.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.31 1998/09/01 04:39:56 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.32 1998/09/03 02:10:42 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -358,15 +358,15 @@ Pg_connect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 		conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
 	}
 
-	if (conn->status == CONNECTION_OK)
+    if (PQstatus(conn) == CONNECTION_OK) {
 	{
 		PgSetConnectionId(interp, conn);
 		return TCL_OK;
 	}
 	else
 	{
-		Tcl_AppendResult(interp, "Connection to database failed\n", 0);
-		Tcl_AppendResult(interp, conn->errorMessage, 0);
+		Tcl_AppendResult(interp, "Connection to database failed\n",
+			PQerrorMessage(conn), 0);
 		PQfinish(conn);
 		return TCL_ERROR;
 	}
@@ -423,7 +423,6 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 	Pg_ConnectionId *connid;
 	PGconn	   *conn;
 	PGresult   *result;
-	int			connStatus;
 
 	if (argc != 3)
 	{
@@ -442,7 +441,6 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 		return TCL_ERROR;
 	}
 
-	connStatus = conn->status;
 	result = PQexec(conn, argv[2]);
 
 	/* Transfer any notify events from libpq to Tcl event queue. */
@@ -452,8 +450,8 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 	{
 		int			rId = PgSetResultId(interp, argv[1], result);
 
-		if (result->resultStatus == PGRES_COPY_IN ||
-			result->resultStatus == PGRES_COPY_OUT)
+		ExecStatusType rStat = PQresultStatus(result);
+		if (rStat == PGRES_COPY_IN || rStat == PGRES_COPY_OUT)
 		{
 			connid->res_copyStatus = RES_COPY_INPROGRESS;
 			connid->res_copy = rId;
@@ -463,7 +461,7 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 	else
 	{
 		/* error occurred during the query */
-		Tcl_SetResult(interp, conn->errorMessage, TCL_VOLATILE);
+		Tcl_SetResult(interp, PQerrorMessage(conn), TCL_VOLATILE);
 		return TCL_ERROR;
 	}
 }
@@ -481,9 +479,12 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
  -conn
  the connection that produced the result
  -assign arrayName
- assign the results to an array
- -assignbyidx arrayName
- assign the results to an array using the first field as a key
+ assign the results to an array, using subscripts of the form
+ (tupno,attributeName)
+ -assignbyidx arrayName ?appendstr?
+ assign the results to an array using the first field's value as a key.
+ All but the first field of each tuple are stored, using subscripts of the form
+ (field0value,attributeNameappendstr)
  -numTuples
  the number of tuples in the query
  -attributes
@@ -509,6 +510,7 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 	int			tupno;
 	char	   *arrVar;
 	char		nameBuffer[256];
+    const char *appendstr;
 
 	if (argc < 3 || argc > 5)
 	{
@@ -564,8 +566,9 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 
 		/*
 		 * this assignment assigns the table of result tuples into a giant
-		 * array with the name given in the argument, the indices of the
-		 * array or (tupno,attrName). Note we expect field names not to
+		 * array with the name given in the argument.
+		 * The indices of the array are of the form (tupno,attrName).
+		 * Note we expect field names not to
 		 * exceed a few dozen characters, so truncating to prevent buffer
 		 * overflow shouldn't be a problem.
 		 */
@@ -589,28 +592,32 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 	}
 	else if (strcmp(opt, "-assignbyidx") == 0)
 	{
-		if (argc != 4)
+		if (argc != 4 && argc != 5)
 		{
-			Tcl_AppendResult(interp, "-assignbyidx option must be followed by a variable name", 0);
+			Tcl_AppendResult(interp, "-assignbyidx option requires an array name and optionally an append string",0);
 			return TCL_ERROR;
 		}
 		arrVar = argv[3];
+		appendstr = (argc == 5) ? (const char *) argv[4] : "";
 
 		/*
 		 * this assignment assigns the table of result tuples into a giant
-		 * array with the name given in the argument, the indices of the
-		 * array or (tupno,attrName). Here, we still assume PQfname won't
-		 * exceed 200 characters, but we dare not make the same assumption
-		 * about the data in field 0.
+		 * array with the name given in the argument.  The indices of the array
+		 * are of the form (field0Value,attrNameappendstr).
+		 * Here, we still assume PQfname won't exceed 200 characters,
+		 * but we dare not make the same assumption about the data in field 0
+		 * nor the append string.
 		 */
 		for (tupno = 0; tupno < PQntuples(result); tupno++)
 		{
 			const char *field0 = PQgetvalue(result, tupno, 0);
-			char	   *workspace = malloc(strlen(field0) + 210);
+			char * workspace = malloc(strlen(field0) + strlen(appendstr) + 210);
 
 			for (i = 1; i < PQnfields(result); i++)
 			{
-				sprintf(workspace, "%s,%.200s", field0, PQfname(result, i));
+				sprintf(workspace, "%s,%.200s%s", field0, PQfname(result,i),
+					appendstr);
+				sprintf(workspace, "%s,%.200s", field0, PQfname(result,i));
 				if (Tcl_SetVar2(interp, arrVar, workspace,
 								PQgetvalue(result, tupno, i),
 								TCL_LEAVE_ERR_MSG) == NULL)
@@ -701,7 +708,7 @@ Pg_result_errReturn:
 					 "\t-status\n",
 					 "\t-conn\n",
 					 "\t-assign arrayVarName\n",
-					 "\t-assignbyidx arrayVarName\n",
+					 "\t-assignbyidx arrayVarName ?appendstr?\n",
 					 "\t-numTuples\n",
 					 "\t-numAttrs\n"
 					 "\t-attributes\n"
@@ -1238,7 +1245,7 @@ Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
 	if ((result = PQexec(conn, argv[2])) == 0)
 	{
 		/* error occurred during the query */
-		Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
+		Tcl_SetResult(interp, PQerrorMessage(conn), TCL_STATIC);
 		return TCL_ERROR;
 	}
 
@@ -1406,11 +1413,10 @@ Pg_listen(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 			ckfree(cmd);
 			/* Transfer any notify events from libpq to Tcl event queue. */
 			PgNotifyTransferEvents(connid);
-			if (!result || (result->resultStatus != PGRES_COMMAND_OK))
+			if (PQresultStatus(result) != PGRES_COMMAND_OK) {
 			{
 				/* Error occurred during the execution of command */
-				if (result)
-					PQclear(result);
+				PQclear(result);
 				ckfree(callback);
 				ckfree(caserelname);
 				Tcl_DeleteHashEntry(entry);
diff --git a/src/interfaces/libpgtcl/pgtclId.c b/src/interfaces/libpgtcl/pgtclId.c
index 9377e322e7e2099afef7a00071e313d1651734c9..8853c1fdbeaf1a8fc8cc7d5aa442c3db19f435a0 100644
--- a/src/interfaces/libpgtcl/pgtclId.c
+++ b/src/interfaces/libpgtcl/pgtclId.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.14 1998/09/01 04:39:58 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.15 1998/09/03 02:10:44 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,98 +33,62 @@ PgEndCopy(Pg_ConnectionId * connid, int *errorCodePtr)
 	connid->res_copyStatus = RES_COPY_NONE;
 	if (PQendcopy(connid->conn))
 	{
-		connid->results[connid->res_copy]->resultStatus = PGRES_BAD_RESPONSE;
+		PQclear(connid->results[connid->res_copy]);
+		connid->results[connid->res_copy] =
+		PQmakeEmptyPGresult(connid->conn, PGRES_BAD_RESPONSE);
 		connid->res_copy = -1;
 		*errorCodePtr = EIO;
 		return -1;
 	}
 	else
 	{
-		connid->results[connid->res_copy]->resultStatus = PGRES_COMMAND_OK;
+		PQclear(connid->results[connid->res_copy]);
+		connid->results[connid->res_copy] =
+		PQmakeEmptyPGresult(connid->conn, PGRES_COMMAND_OK);
 		connid->res_copy = -1;
 		return 0;
 	}
 }
 
 /*
- *	Called when reading data (via gets) for a copy <rel> to stdout.
- *
- *	NOTE: this routine knows way more than it ought to about libpq's
- *	internal buffering mechanisms.
+ *  Called when reading data (via gets) for a copy <rel> to stdout.
  */
-int
-PgInputProc(DRIVER_INPUT_PROTO)
+int PgInputProc(DRIVER_INPUT_PROTO)
 {
-	Pg_ConnectionId *connid;
-	PGconn	   *conn;
-	char		c;
-	int			avail;
+    Pg_ConnectionId	*connid;
+    PGconn		*conn;
+    int			avail;
 
-	connid = (Pg_ConnectionId *) cData;
-	conn = connid->conn;
+    connid = (Pg_ConnectionId *)cData;
+    conn = connid->conn;
 
-	if (connid->res_copy < 0 ||
-		connid->results[connid->res_copy]->resultStatus != PGRES_COPY_OUT)
+    if (connid->res_copy < 0 ||
+	PQresultStatus(connid->results[connid->res_copy]) != PGRES_COPY_OUT)
 	{
 		*errorCodePtr = EBUSY;
 		return -1;
-	}
+    }
 
-	/* Try to load any newly arrived data */
-	conn->errorMessage[0] = '\0';
-	PQconsumeInput(conn);
-	if (conn->errorMessage[0])
+    /* Read any newly arrived data into libpq's buffer,
+     * thereby clearing the socket's read-ready condition.
+     */
+    if (! PQconsumeInput(conn))
 	{
 		*errorCodePtr = EIO;
 		return -1;
-	}
+    }
 
-	/*
-	 * Move data from libpq's buffer to Tcl'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 Tcl, which we shouldn't.)
-	 */
+    /* Move data from libpq's buffer to Tcl's. */
 
-	conn->inCursor = conn->inStart;
+    avail = PQgetlineAsync(conn, buf, bufSize);
 
-	avail = bufSize;
-	while (avail > 0 && conn->inCursor < conn->inEnd)
+    if (avail < 0)
 	{
-		c = conn->inBuffer[conn->inCursor++];
-		*buf++ = 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 && buf[-3] == '\\' && buf[-2] == '.')
-			{
-				/* Yes, change state and return 0 */
-				return PgEndCopy(connid, errorCodePtr);
-			}
-			/* No, return the data to Tcl */
-			/* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
-			return bufSize - avail;
-		}
-	}
+      /* Endmarker detected, change state and return 0 */
+      return PgEndCopy(connid, errorCodePtr);
+    }
 
-	/*
-	 * 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 Tcl 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;
+    return avail;
 }
 
 /*
@@ -140,17 +104,13 @@ PgOutputProc(DRIVER_OUTPUT_PROTO)
 	conn = connid->conn;
 
 	if (connid->res_copy < 0 ||
-		connid->results[connid->res_copy]->resultStatus != PGRES_COPY_IN)
+		PQresultStatus(connid->results[connid->res_copy]) != PGRES_COPY_IN)
 	{
 		*errorCodePtr = EBUSY;
 		return -1;
 	}
 
-	conn->errorMessage[0] = '\0';
-
-	PQputnbytes(conn, buf, bufSize);
-
-	if (conn->errorMessage[0])
+    if (PQputnbytes(conn, buf, bufSize))
 	{
 		*errorCodePtr = EIO;
 		return -1;
@@ -398,7 +358,7 @@ getresid(Tcl_Interp * interp, char *id, Pg_ConnectionId ** connid_p)
 
 	connid = (Pg_ConnectionId *) Tcl_GetChannelInstanceData(conn_chan);
 
-	if (resid < 0 || resid > connid->res_max || connid->results[resid] == NULL)
+    if (resid < 0 || resid >= connid->res_max || connid->results[resid] == NULL)
 	{
 		Tcl_SetResult(interp, "Invalid result handle", TCL_STATIC);
 		return -1;
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 85a95c9727a30667e295dab9037df5a08f8aa179..5d244fa838fee7d9e6e3948b4a598c53c161865f 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.80 1998/09/01 04:40:04 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.81 1998/09/03 02:10:46 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1384,6 +1384,14 @@ PQuser(PGconn *conn)
 	return conn->pguser;
 }
 
+char *
+PQpass(PGconn *conn)
+{
+	if (!conn)
+		return (char *) NULL;
+	return conn->pgpass;
+}
+
 char *
 PQhost(PGconn *conn)
 {
@@ -1393,11 +1401,11 @@ PQhost(PGconn *conn)
 }
 
 char *
-PQoptions(PGconn *conn)
+PQport(PGconn *conn)
 {
 	if (!conn)
 		return (char *) NULL;
-	return conn->pgoptions;
+	return conn->pgport;
 }
 
 char *
@@ -1409,11 +1417,11 @@ PQtty(PGconn *conn)
 }
 
 char *
-PQport(PGconn *conn)
+PQoptions(PGconn *conn)
 {
 	if (!conn)
 		return (char *) NULL;
-	return conn->pgport;
+	return conn->pgoptions;
 }
 
 ConnStatusType
@@ -1442,6 +1450,14 @@ PQsocket(PGconn *conn)
 	return conn->sock;
 }
 
+int
+PQbackendPID(PGconn *conn)
+{
+	if (!conn || conn->status != CONNECTION_OK)
+		return 0;
+	return conn->be_pid;
+}
+
 void
 PQtrace(PGconn *conn, FILE *debug_port)
 {
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 9f2651365b54c5af5bbd1506ad1a7ca447d85ba4..fe5e7e037debb8d71468d71c66ed460dfe5e0760 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.65 1998/09/01 04:40:05 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.66 1998/09/03 02:10:47 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,7 +49,6 @@ const char *const pgresStatus[] = {
 	((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
 
 
-static PGresult *makeEmptyPGresult(PGconn *conn, ExecStatusType status);
 static void freeTuple(PGresAttValue *tuple, int numAttributes);
 static void addTuple(PGresult *res, PGresAttValue *tup);
 static void parseInput(PGconn *conn);
@@ -60,13 +59,16 @@ static int	getNotice(PGconn *conn);
 
 
 /*
- * PGresult -
- *	 returns a newly allocated, initialized PGresult
+ * PQmakeEmptyPGresult
+ *	 returns a newly allocated, initialized PGresult with given status
  *
+ * Note this is exported --- you wouldn't think an application would need
+ * to build its own PGresults, but this has proven useful in both libpgtcl
+ * and the Perl5 interface, so maybe it's not so unreasonable.
  */
 
-static PGresult *
-makeEmptyPGresult(PGconn *conn, ExecStatusType status)
+PGresult *
+PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
 {
 	PGresult   *result;
 
@@ -252,13 +254,15 @@ PQsendQuery(PGconn *conn, const char *query)
 
 /*
  * Consume any available input from the backend
+ * 0 return: some kind of trouble
+ * 1 return: no problem
  */
 
-void
+int
 PQconsumeInput(PGconn *conn)
 {
 	if (!conn)
-		return;
+		return 0;
 
 	/*
 	 * Load more data, if available. We do this no matter what state we
@@ -266,9 +270,12 @@ PQconsumeInput(PGconn *conn)
 	 * application wants to get rid of a read-select condition. Note that
 	 * we will NOT block waiting for more input.
 	 */
-	if (pqReadData(conn) < 0)
+	if (pqReadData(conn) < 0) {
 		strcpy(conn->asyncErrorMessage, conn->errorMessage);
+		return 0;
+	}
 	/* Parsing of the data waits till later. */
+	return 1;
 }
 
 
@@ -346,8 +353,8 @@ parseInput(PGconn *conn)
 			{
 				case 'C':		/* command complete */
 					if (conn->result == NULL)
-						conn->result = makeEmptyPGresult(conn,
-													   PGRES_COMMAND_OK);
+						conn->result = PQmakeEmptyPGresult(conn,
+														   PGRES_COMMAND_OK);
 					if (pqGets(conn->result->cmdStatus, CMDSTATUS_LEN, conn))
 						return;
 					conn->asyncStatus = PGASYNC_READY;
@@ -379,8 +386,8 @@ parseInput(PGconn *conn)
 						DONOTICE(conn, conn->errorMessage);
 					}
 					if (conn->result == NULL)
-						conn->result = makeEmptyPGresult(conn,
-													  PGRES_EMPTY_QUERY);
+						conn->result = PQmakeEmptyPGresult(conn,
+														   PGRES_EMPTY_QUERY);
 					conn->asyncStatus = PGASYNC_READY;
 					break;
 				case 'K':		/* secret key data from the backend */
@@ -499,7 +506,7 @@ getRowDescriptions(PGconn *conn)
 	int			nfields;
 	int			i;
 
-	result = makeEmptyPGresult(conn, PGRES_TUPLES_OK);
+	result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
 
 	/* parseInput already read the 'T' label. */
 	/* the next two bytes are the number of fields	*/
@@ -536,7 +543,7 @@ getRowDescriptions(PGconn *conn)
 		}
 		result->attDescs[i].name = strdup(typName);
 		result->attDescs[i].typid = typid;
-		result->attDescs[i].typlen = (short) typlen;
+		result->attDescs[i].typlen = typlen;
 		result->attDescs[i].atttypmod = atttypmod;
 	}
 
@@ -695,7 +702,7 @@ PQgetResult(PGconn *conn)
 			pqClearAsyncResult(conn);
 			conn->asyncStatus = PGASYNC_IDLE;
 			/* conn->errorMessage has been set by pqWait or pqReadData. */
-			return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+			return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
 		}
 		/* Parse it. */
 		parseInput(conn);
@@ -719,22 +726,22 @@ PQgetResult(PGconn *conn)
 			conn->result = NULL;/* handing over ownership to caller */
 			conn->curTuple = NULL;		/* just in case */
 			if (!res)
-				res = makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+				res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
 			strcpy(conn->errorMessage, conn->asyncErrorMessage);
 			/* Set the state back to BUSY, allowing parsing to proceed. */
 			conn->asyncStatus = PGASYNC_BUSY;
 			break;
 		case PGASYNC_COPY_IN:
-			res = makeEmptyPGresult(conn, PGRES_COPY_IN);
+			res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN);
 			break;
 		case PGASYNC_COPY_OUT:
-			res = makeEmptyPGresult(conn, PGRES_COPY_OUT);
+			res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);
 			break;
 		default:
 			sprintf(conn->errorMessage,
 					"PQgetResult: Unexpected asyncStatus %d\n",
 					(int) conn->asyncStatus);
-			res = makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+			res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
 			break;
 	}
 
@@ -880,6 +887,9 @@ PQnotifies(PGconn *conn)
  * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
  * the terminating \n (like gets(3)).
  *
+ * CAUTION: the caller is responsible for detecting the end-of-copy signal
+ * (a line containing just "\.") when using this routine.
+ *
  * RETURNS:
  *		EOF if it is detected or invalid arguments are given
  *		0 if EOL is reached (i.e., \n has been read)
@@ -936,26 +946,114 @@ PQgetline(PGconn *conn, char *s, int maxlen)
 	return result;
 }
 
+/*
+ * PQgetlineAsync - gets a newline-terminated string without blocking.
+ *
+ * This routine is for applications that want to do "COPY <rel> to stdout"
+ * asynchronously, that is without blocking.  Having issued the COPY command
+ * and gotten a PGRES_COPY_OUT response, the app should call PQconsumeInput
+ * and this routine until the end-of-data signal is detected.  Unlike
+ * PQgetline, this routine takes responsibility for detecting end-of-data.
+ *
+ * On each call, PQgetlineAsync will return data if a complete newline-
+ * terminated data line is available in libpq's input buffer, or if the
+ * incoming data line is too long to fit in the buffer offered by the caller.
+ * Otherwise, no data is returned until the rest of the line arrives.
+ *
+ * If -1 is returned, the end-of-data signal has been recognized (and removed
+ * from libpq's input buffer).  The caller *must* next call PQendcopy and
+ * then return to normal processing.
+ *
+ * RETURNS:
+ *   -1    if the end-of-copy-data marker has been recognized
+ *   0     if no data is available
+ *   >0    the number of bytes returned.
+ * The data returned will not extend beyond a newline character.  If possible
+ * a whole line will be returned at one time.  But if the buffer offered by
+ * the caller is too small to hold a line sent by the backend, then a partial
+ * data line will be returned.  This can be detected by testing whether the
+ * last returned byte is '\n' or not.
+ * The returned string is *not* null-terminated.
+ */
+
+int
+PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)
+{
+    int		avail;
+
+	if (!conn || 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;
+}
+
 /*
  * PQputline -- sends a string to the backend.
+ * Returns 0 if OK, EOF if not.
  *
  * Chiefly here so that applications can use "COPY <rel> from stdin".
  */
-void
+int
 PQputline(PGconn *conn, const char *s)
 {
-	if (conn && conn->sock >= 0)
-		(void) pqPutnchar(s, strlen(s), conn);
+	if (!conn || conn->sock < 0)
+		return EOF;
+	return pqPutnchar(s, strlen(s), conn);
 }
 
 /*
  * PQputnbytes -- like PQputline, but buffer need not be null-terminated.
+ * Returns 0 if OK, EOF if not.
  */
-void
+int
 PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
 {
-	if (conn && conn->sock >= 0)
-		(void) pqPutnchar(buffer, nbytes, conn);
+	if (!conn || conn->sock < 0)
+		return EOF;
+	return pqPutnchar(buffer, nbytes, conn);
 }
 
 /*
@@ -1155,7 +1253,7 @@ PQfn(PGconn *conn,
 					sprintf(conn->errorMessage,
 							"FATAL: PQfn: protocol error: id=%x\n", id);
 					conn->inStart = conn->inCursor;
-					return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+					return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
 				}
 				break;
 			case 'E':			/* error return */
@@ -1176,13 +1274,13 @@ PQfn(PGconn *conn,
 			case 'Z':			/* backend is ready for new query */
 				/* consume the message and exit */
 				conn->inStart = conn->inCursor;
-				return makeEmptyPGresult(conn, status);
+				return PQmakeEmptyPGresult(conn, status);
 			default:
 				/* The backend violates the protocol. */
 				sprintf(conn->errorMessage,
 						"FATAL: PQfn: protocol error: id=%x\n", id);
 				conn->inStart = conn->inCursor;
-				return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+				return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
 		}
 		/* Completed this message, keep going */
 		conn->inStart = conn->inCursor;
@@ -1190,7 +1288,7 @@ PQfn(PGconn *conn,
 	}
 
 	/* we fall out of the loop only upon failing to read data */
-	return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+	return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
 }
 
 
@@ -1220,6 +1318,14 @@ PQnfields(PGresult *res)
 	return res->numAttributes;
 }
 
+int
+PQbinaryTuples(PGresult *res)
+{
+	if (!res)
+		return 0;
+	return res->binary;
+}
+
 /*
  * Helper routines to range-check field numbers and tuple numbers.
  * Return TRUE if OK, FALSE if not
@@ -1332,7 +1438,7 @@ PQftype(PGresult *res, int field_num)
 		return InvalidOid;
 }
 
-short
+int
 PQfsize(PGresult *res, int field_num)
 {
 	if (!check_field_number("PQfsize", res, field_num))
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index d091f6e6dbc71b3c3e1083278077ae5e5b1ca03d..2a844167a779bd4f68dca4e6eef03a21d43a3239 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -24,7 +24,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.20 1998/09/01 04:40:08 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.21 1998/09/03 02:10:50 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -174,15 +174,14 @@ pqGetnchar(char *s, int len, PGconn *conn)
 	conn->inCursor += len;
 
 	if (conn->Pfdebug)
-		fprintf(conn->Pfdebug, "From backend (%d)> %s\n", len, s);
+		fprintf(conn->Pfdebug, "From backend (%d)> %.*s\n", len, len, s);
 
 	return 0;
 }
 
 /* --------------------------------------------------------------------- */
 /* pqPutnchar:
-   send a string of exactly len bytes
-   The buffer should have a terminating null, but it's not sent.
+   send a string of exactly len bytes, no null termination needed
 */
 int
 pqPutnchar(const char *s, int len, PGconn *conn)
@@ -191,7 +190,7 @@ pqPutnchar(const char *s, int len, PGconn *conn)
 		return EOF;
 
 	if (conn->Pfdebug)
-		fprintf(conn->Pfdebug, "To backend> %s\n", s);
+		fprintf(conn->Pfdebug, "To backend> %.*s\n", len, s);
 
 	return 0;
 }
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 993536023b84efacfedc51cc3498fdc475b87fc1..1f07baba119405eebb928e86840dcd192deb6585 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq-fe.h,v 1.40 1998/09/01 04:40:10 momjian Exp $
+ * $Id: libpq-fe.h,v 1.41 1998/09/03 02:10:51 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,20 +20,10 @@ extern		"C"
 #endif
 
 #include <stdio.h>
-/* these wouldn't need to be included if PGSockAddr weren't exported: */
-#ifdef WIN32
-#include <winsock.h>
-#else
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#endif
-/* ----------------
- *		include stuff common to fe and be
- * ----------------
+/* postgres_ext.h defines the backend's externally visible types,
+ * such as Oid.
  */
 #include "postgres_ext.h"
-#include "lib/dllist.h"
 
 /* Application-visible enum types */
 
@@ -46,11 +36,11 @@ extern		"C"
 	typedef enum
 	{
 		PGRES_EMPTY_QUERY = 0,
-		PGRES_COMMAND_OK,		/* a query command that doesn't return */
-		/* anything was executed properly by the backend */
-		PGRES_TUPLES_OK,		/* a query command that returns tuples */
-		/* was executed properly by the backend, PGresult */
-		/* contains the result tuples */
+		PGRES_COMMAND_OK,		/* a query command that doesn't return anything
+								 * was executed properly by the backend */
+		PGRES_TUPLES_OK,		/* a query command that returns tuples
+								 * was executed properly by the backend,
+								 * PGresult contains the result tuples */
 		PGRES_COPY_OUT,			/* Copy Out data transfer in progress */
 		PGRES_COPY_IN,			/* Copy In data transfer in progress */
 		PGRES_BAD_RESPONSE,		/* an unexpected response was recv'd from
@@ -59,193 +49,45 @@ extern		"C"
 		PGRES_FATAL_ERROR
 	} ExecStatusType;
 
-/* string descriptions of the ExecStatusTypes */
-	extern const char *const pgresStatus[];
+/* String descriptions of the ExecStatusTypes */
+	extern const char * const pgresStatus[];
 
-/*
- * POSTGRES backend dependent Constants.
+/* PGconn encapsulates a connection to the backend.
+ * The contents of this struct are not supposed to be known to applications.
  */
+	typedef struct pg_conn PGconn;
 
-/* ERROR_MSG_LENGTH should really be the same as ELOG_MAXLEN in utils/elog.h*/
-#define ERROR_MSG_LENGTH 4096
-#define CMDSTATUS_LEN 40
-
-/* PGresult and the subsidiary types PGresAttDesc, PGresAttValue
- * represent the result of a query (or more precisely, of a single SQL
- * command --- a query string given to PQexec can contain multiple commands).
- * Note we assume that a single command can return at most one tuple group,
- * hence there is no need for multiple descriptor sets.
+/* PGresult encapsulates the result of a query (or more precisely, of a single
+ * SQL command --- a query string given to PQsendQuery can contain multiple
+ * commands and thus return multiple PGresult objects).
+ * The contents of this struct are not supposed to be known to applications.
  */
+	typedef struct pg_result PGresult;
 
-	typedef struct pgresAttDesc
-	{
-		char	   *name;		/* type name */
-		Oid			typid;		/* type id */
-		short		typlen;		/* type size */
-		int			atttypmod;	/* type-specific modifier info */
-	} PGresAttDesc;
-
-/* use char* for Attribute values,
-   ASCII tuples are guaranteed to be null-terminated
-   For binary tuples, the first four bytes of the value is the size,
-   and the bytes afterwards are the value.	The binary value is
-   not guaranteed to be null-terminated.  In fact, it can have embedded nulls
+/* PGnotify represents the occurrence of a NOTIFY message.
+ * Ideally this would be an opaque typedef, but it's so simple that it's
+ * unlikely to change.
  */
-
-#define NULL_LEN		(-1)	/* pg_result len for NULL value */
-
-	typedef struct pgresAttValue
-	{
-		int			len;		/* length in bytes of the value */
-		char	   *value;		/* actual value */
-	} PGresAttValue;
-
-	struct pg_conn;				/* forward reference */
-
-	typedef struct pg_result
-	{
-		int			ntups;
-		int			numAttributes;
-		PGresAttDesc *attDescs;
-		PGresAttValue **tuples; /* each PGresTuple is an array of
-								 * PGresAttValue's */
-		int			tupArrSize; /* size of tuples array allocated */
-		ExecStatusType resultStatus;
-		char		cmdStatus[CMDSTATUS_LEN];	/* cmd status from the
-												 * last insert query */
-		int			binary;		/* binary tuple values if binary == 1,
-								 * otherwise ASCII */
-		struct pg_conn *conn;	/* connection we did the query on */
-	} PGresult;
-
-/* PGnotify represents the occurrence of a NOTIFY message */
 	typedef struct pgNotify
 	{
 		char		relname[NAMEDATALEN];		/* name of relation
 												 * containing data */
-		int			be_pid;		/* process id of backend */
+		int			be_pid;						/* process id of backend */
 	} PGnotify;
 
-/* PQnoticeProcessor is a typedef for a callback function type */
-	typedef void (*PQnoticeProcessor) (void *arg, const char *message);
-
-/* PGAsyncStatusType is private to libpq, really shouldn't be seen by users */
-	typedef enum
-	{
-		PGASYNC_IDLE,			/* nothing's happening, dude */
-		PGASYNC_BUSY,			/* query in progress */
-		PGASYNC_READY,			/* result ready for PQgetResult */
-		PGASYNC_COPY_IN,		/* Copy In data transfer in progress */
-		PGASYNC_COPY_OUT		/* Copy Out data transfer in progress */
-	}			PGAsyncStatusType;
-
-/* generic socket address type for PGconn connection information.
- * Really shouldn't be visible to users */
-	typedef union PGSockAddr
-	{
-		struct sockaddr sa;
-		struct sockaddr_in in;
-#ifndef WIN32
-		struct sockaddr_un un;
-#endif
-	}			PGSockAddr;
-
-/* large-object-access data ... allocated only if large-object code is used.
- * Really shouldn't be visible to users */
-	typedef struct pgLobjfuncs
-	{
-		Oid			fn_lo_open; /* OID of backend function lo_open		*/
-		Oid			fn_lo_close;/* OID of backend function lo_close		*/
-		Oid			fn_lo_creat;/* OID of backend function lo_creat		*/
-		Oid			fn_lo_unlink;		/* OID of backend function
-										 * lo_unlink	*/
-		Oid			fn_lo_lseek;/* OID of backend function lo_lseek		*/
-		Oid			fn_lo_tell; /* OID of backend function lo_tell		*/
-		Oid			fn_lo_read; /* OID of backend function LOread		*/
-		Oid			fn_lo_write;/* OID of backend function LOwrite		*/
-	} PGlobjfuncs;
-
-/* PGconn encapsulates a connection to the backend.
- * XXX contents of this struct really shouldn't be visible to applications,
- * but we might break some existing applications if we tried to make it
- * completely opaque.
+/* PQnoticeProcessor is the function type for the notice-message callback.
  */
-	typedef struct pg_conn
-	{
-		/* Saved values of connection options */
-		char	   *pghost;		/* the machine on which the server is
-								 * running */
-		char	   *pgport;		/* the server's communication port */
-		char	   *pgtty;		/* tty on which the backend messages is
-								 * displayed (NOT ACTUALLY USED???) */
-		char	   *pgoptions;	/* options to start the backend with */
-		char	   *dbName;		/* database name */
-		char	   *pguser;		/* Postgres username and password, if any */
-		char	   *pgpass;
-
-		/* Optional file to write trace info to */
-		FILE	   *Pfdebug;
-
-		/* Callback procedure for notice/error message processing */
-		PQnoticeProcessor noticeHook;
-		void	   *noticeArg;
-
-		/* Status indicators */
-		ConnStatusType status;
-		PGAsyncStatusType asyncStatus;
-		Dllist	   *notifyList; /* Notify msgs not yet handed to
-								 * application */
-
-		/* Connection data */
-		int			sock;		/* Unix FD for socket, -1 if not connected */
-		PGSockAddr	laddr;		/* Local address */
-		PGSockAddr	raddr;		/* Remote address */
-		int			raddr_len;	/* Length of remote address */
-
-		/* Miscellaneous stuff */
-		int			be_pid;		/* PID of backend --- needed for cancels */
-		int			be_key;		/* key of backend --- needed for cancels */
-		char		salt[2];	/* password salt received from backend */
-		PGlobjfuncs *lobjfuncs; /* private state for large-object access
-								 * fns */
-
-		/* Buffer for data received from backend and not yet processed */
-		char	   *inBuffer;	/* currently allocated buffer */
-		int			inBufSize;	/* allocated size of buffer */
-		int			inStart;	/* offset to first unconsumed data in
-								 * buffer */
-		int			inCursor;	/* next byte to tentatively consume */
-		int			inEnd;		/* offset to first position after avail
-								 * data */
-
-		/* Buffer for data not yet sent to backend */
-		char	   *outBuffer;	/* currently allocated buffer */
-		int			outBufSize; /* allocated size of buffer */
-		int			outCount;	/* number of chars waiting in buffer */
-
-		/* Status for asynchronous result construction */
-		PGresult   *result;		/* result being constructed */
-		PGresAttValue *curTuple;/* tuple currently being read */
-
-		/*
-		 * Message space.  Placed last for code-size reasons. errorMessage
-		 * is the message last returned to the application. When
-		 * asyncStatus=READY, asyncErrorMessage is the pending message
-		 * that will be put in errorMessage by PQgetResult.
-		 */
-		char		errorMessage[ERROR_MSG_LENGTH];
-		char		asyncErrorMessage[ERROR_MSG_LENGTH];
-	} PGconn;
 
-	/*
-	 * We can't use the conventional "bool", because we are designed to be
-	 * included in a user's program, and user may already have that type
-	 * defined.  Pqbool, on the other hand, is unlikely to be used.
-	 */
-
-	typedef char pqbool;
+typedef void (*PQnoticeProcessor) (void * arg, const char * message);
 
 /* Print options for PQprint() */
+  
+  	/*
+  	 * We can't use the conventional "bool", because we are designed to be
+  	 * included in a user's program, and user may already have that type
+  	 * defined.  Pqbool, on the other hand, is unlikely to be used.
+  	 */
+  	typedef char pqbool;
 
 	typedef struct _PQprintOpt
 	{
@@ -263,21 +105,6 @@ extern		"C"
 								 * field names */
 	} PQprintOpt;
 
-/* ----------------
- * PQArgBlock -- structure for PQfn() arguments
- * ----------------
- */
-	typedef struct
-	{
-		int			len;
-		int			isint;
-		union
-		{
-			int		   *ptr;	/* can't use void (dec compiler barfs)	 */
-			int			integer;
-		}			u;
-	} PQArgBlock;
-
 /* ----------------
  * Structure for the conninfo parameter definitions returned by PQconndefaults
  * ----------------
@@ -290,14 +117,29 @@ extern		"C"
 		char	   *val;		/* Options value						*/
 		char	   *label;		/* Label for field in connect dialog	*/
 		char	   *dispchar;	/* Character to display for this field	*/
-		/* in a connect dialog. Values are:		*/
-		/* ""	Display entered value as is  */
-		/* "*"	Password field - hide value  */
-		/* "D"	Debug options - don't 	 */
-		/* create a field by default	*/
+								/* in a connect dialog. Values are:		*/
+								/* ""	Display entered value as is  */
+								/* "*"	Password field - hide value  */
+								/* "D"	Debug options - don't 	 */
+								/* create a field by default	*/
 		int			dispsize;	/* Field size in characters for dialog	*/
 	} PQconninfoOption;
 
+/* ----------------
+ * PQArgBlock -- structure for PQfn() arguments
+ * ----------------
+ */
+	typedef struct
+	{
+		int			len;
+		int			isint;
+		union
+		{
+			int		   *ptr;	/* can't use void (dec compiler barfs)	 */
+			int			integer;
+		}			u;
+	} PQArgBlock;
+
 /* ----------------
  * Exported functions of libpq
  * ----------------
@@ -332,13 +174,16 @@ extern		"C"
 	/* Accessor functions for PGconn objects */
 	extern char *PQdb(PGconn *conn);
 	extern char *PQuser(PGconn *conn);
+	extern char *PQpass(PGconn *conn);
 	extern char *PQhost(PGconn *conn);
-	extern char *PQoptions(PGconn *conn);
 	extern char *PQport(PGconn *conn);
 	extern char *PQtty(PGconn *conn);
+	extern char *PQoptions(PGconn *conn);
 	extern ConnStatusType PQstatus(PGconn *conn);
 	extern char *PQerrorMessage(PGconn *conn);
 	extern int	PQsocket(PGconn *conn);
+	extern int	PQsocket(PGconn *conn);
+	extern int	PQbackendPID(PGconn *conn);
 
 	/* Enable/disable tracing */
 	extern void PQtrace(PGconn *conn, FILE *debug_port);
@@ -361,12 +206,13 @@ extern		"C"
 
 	/* Routines for managing an asychronous query */
 	extern int	PQisBusy(PGconn *conn);
-	extern void PQconsumeInput(PGconn *conn);
+	extern int	PQconsumeInput(PGconn *conn);
 
 	/* Routines for copy in/out */
 	extern int	PQgetline(PGconn *conn, char *string, int length);
-	extern void PQputline(PGconn *conn, const char *string);
-	extern void PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
+	extern int	PQputline(PGconn *conn, const char *string);
+	extern int	PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
+	extern int	PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
 	extern int	PQendcopy(PGconn *conn);
 
 	/*
@@ -385,10 +231,11 @@ extern		"C"
 	extern ExecStatusType PQresultStatus(PGresult *res);
 	extern int	PQntuples(PGresult *res);
 	extern int	PQnfields(PGresult *res);
+	extern int	PQbinaryTuples(PGresult *res);
 	extern char *PQfname(PGresult *res, int field_num);
 	extern int	PQfnumber(PGresult *res, const char *field_name);
 	extern Oid	PQftype(PGresult *res, int field_num);
-	extern short PQfsize(PGresult *res, int field_num);
+	extern int	PQfsize(PGresult *res, int field_num);
 	extern int	PQfmod(PGresult *res, int field_num);
 	extern char *PQcmdStatus(PGresult *res);
 	extern const char *PQoidStatus(PGresult *res);
@@ -400,6 +247,9 @@ extern		"C"
 	/* Delete a PGresult */
 	extern void PQclear(PGresult *res);
 
+	/* Make an empty PGresult with given status (some apps find this useful) */
+	extern PGresult * PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
+
 /* === in fe-print.c === */
 
 	extern void PQprint(FILE *fout,		/* output stream */
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index c338fa92332055c293372cf594fbc7e9a99c725e..4c877de2d2e8895af23da79fb14cef3d5ee635e9 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -4,9 +4,14 @@
  *	  This file contains internal definitions meant to be used only by
  *	  the frontend libpq library, not by applications that call it.
  *
+ *	  An application can include this file if it wants to bypass the
+ *	  official API defined by libpq-fe.h, but code that does so is much
+ *	  more likely to break across PostgreSQL releases than code that uses
+ *	  only the official API.
+ *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq-int.h,v 1.2 1998/09/01 04:40:12 momjian Exp $
+ * $Id: libpq-int.h,v 1.3 1998/09/03 02:10:53 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +26,7 @@
  * ----------------
  */
 #include "libpq/pqcomm.h"
+#include "lib/dllist.h"
 
 /* libpq supports this version of the frontend/backend protocol.
  *
@@ -35,6 +41,147 @@
 
 #define PG_PROTOCOL_LIBPQ	PG_PROTOCOL(2,0)
 
+/*
+ * POSTGRES backend dependent Constants.
+ */
+
+/* ERROR_MSG_LENGTH should really be the same as ELOG_MAXLEN in utils/elog.h*/
+#define ERROR_MSG_LENGTH 4096
+#define CMDSTATUS_LEN 40
+
+/* PGresult and the subsidiary types PGresAttDesc, PGresAttValue
+ * represent the result of a query (or more precisely, of a single SQL
+ * command --- a query string given to PQexec can contain multiple commands).
+ * Note we assume that a single command can return at most one tuple group,
+ * hence there is no need for multiple descriptor sets.
+ */
+	typedef struct pgresAttDesc
+	{
+		char	   *name;		/* type name */
+		Oid			typid;		/* type id */
+		int			typlen;		/* type size */
+		int			atttypmod;	/* type-specific modifier info */
+	} PGresAttDesc;
+
+/* use char* for Attribute values,
+   ASCII tuples are guaranteed to be null-terminated
+   For binary tuples, the first four bytes of the value is the size,
+   and the bytes afterwards are the value.	The binary value is
+   not guaranteed to be null-terminated.  In fact, it can have embedded nulls
+ */
+
+#define NULL_LEN		(-1)	/* pg_result len for NULL value */
+
+	typedef struct pgresAttValue
+	{
+		int			len;		/* length in bytes of the value */
+		char	   *value;		/* actual value */
+	} PGresAttValue;
+
+ struct pg_result
+	{
+		int			ntups;
+		int			numAttributes;
+		PGresAttDesc *attDescs;
+		PGresAttValue **tuples; /* each PGresTuple is an array of
+								 * PGresAttValue's */
+		int			tupArrSize; /* size of tuples array allocated */
+		ExecStatusType resultStatus;
+		char		cmdStatus[CMDSTATUS_LEN];	/* cmd status from the
+												 * last insert query */
+		int			binary;		/* binary tuple values if binary == 1,
+								 * otherwise ASCII */
+		PGconn		*conn;		/* connection we did the query on */
+	};
+
+/* PGAsyncStatusType defines the state of the query-execution state machine */
+	typedef enum
+	{
+		PGASYNC_IDLE,			/* nothing's happening, dude */
+		PGASYNC_BUSY,			/* query in progress */
+		PGASYNC_READY,			/* result ready for PQgetResult */
+		PGASYNC_COPY_IN,		/* Copy In data transfer in progress */
+		PGASYNC_COPY_OUT		/* Copy Out data transfer in progress */
+	} PGAsyncStatusType;
+
+/* large-object-access data ... allocated only if large-object code is used. */
+	typedef struct pgLobjfuncs
+	{
+		Oid			fn_lo_open; /* OID of backend function lo_open		*/
+		Oid			fn_lo_close;/* OID of backend function lo_close		*/
+		Oid			fn_lo_creat;/* OID of backend function lo_creat		*/
+		Oid			fn_lo_unlink;		/* OID of backend function
+										 * lo_unlink	*/
+		Oid			fn_lo_lseek;/* OID of backend function lo_lseek		*/
+		Oid			fn_lo_tell; /* OID of backend function lo_tell		*/
+		Oid			fn_lo_read; /* OID of backend function LOread		*/
+		Oid			fn_lo_write;/* OID of backend function LOwrite		*/
+	} PGlobjfuncs;
+
+/* PGconn stores all the state data associated with a single connection
+ * to a backend.
+ */
+	struct pg_conn
+	{
+		/* Saved values of connection options */
+		char	   *pghost;		/* the machine on which the server is
+								 * running */
+		char	   *pgport;		/* the server's communication port */
+		char	   *pgtty;		/* tty on which the backend messages is
+								 * displayed (NOT ACTUALLY USED???) */
+		char	   *pgoptions;	/* options to start the backend with */
+		char	   *dbName;		/* database name */
+		char	   *pguser;		/* Postgres username and password, if any */
+		char	   *pgpass;
+
+		/* Optional file to write trace info to */
+		FILE	   *Pfdebug;
+
+		/* Callback procedure for notice/error message processing */
+		PQnoticeProcessor	noticeHook;
+		void	   *noticeArg;
+
+		/* Status indicators */
+		ConnStatusType		status;
+		PGAsyncStatusType	asyncStatus;
+		Dllist	   *notifyList;	/* Notify msgs not yet handed to application */
+
+		/* Connection data */
+		int			sock;		/* Unix FD for socket, -1 if not connected */
+		SockAddr	laddr;		/* Local address */
+		SockAddr	raddr;		/* Remote address */
+		int			raddr_len;	/* Length of remote address */
+
+		/* Miscellaneous stuff */
+		int			be_pid;		/* PID of backend --- needed for cancels */
+		int			be_key;		/* key of backend --- needed for cancels */
+		char		salt[2];	/* password salt received from backend */
+		PGlobjfuncs *lobjfuncs; /* private state for large-object access fns */
+
+		/* Buffer for data received from backend and not yet processed */
+		char		*inBuffer;	/* currently allocated buffer */
+		int			inBufSize;	/* allocated size of buffer */
+		int			inStart;	/* offset to first unconsumed data in buffer */
+		int			inCursor;	/* next byte to tentatively consume */
+		int			inEnd;		/* offset to first position after avail data */
+
+		/* Buffer for data not yet sent to backend */
+		char		*outBuffer;	/* currently allocated buffer */
+		int			outBufSize;	/* allocated size of buffer */
+		int			outCount;	/* number of chars waiting in buffer */
+
+		/* Status for asynchronous result construction */
+		PGresult		*result;	/* result being constructed */
+		PGresAttValue	*curTuple;	/* tuple currently being read */
+
+		/* Message space.  Placed last for code-size reasons.
+		 * errorMessage is the message last returned to the application.
+		 * When asyncStatus=READY, asyncErrorMessage is the pending message
+		 * that will be put in errorMessage by PQgetResult. */
+		char		errorMessage[ERROR_MSG_LENGTH];
+		char		asyncErrorMessage[ERROR_MSG_LENGTH];
+	};
+
 /* ----------------
  * Internal functions of libpq
  * Functions declared here need to be visible across files of libpq,
diff --git a/src/interfaces/libpq/libpqdll.def b/src/interfaces/libpq/libpqdll.def
index f1a0b324d1a857d751980dcc330abb1cb0c8ab58..fee6f217d6020612a85bc5efddd7fe29e6f127db 100644
--- a/src/interfaces/libpq/libpqdll.def
+++ b/src/interfaces/libpq/libpqdll.def
@@ -9,52 +9,57 @@ EXPORTS
 	PQrequestCancel		@ 6
 	PQdb			@ 7
 	PQuser			@ 8
-	PQhost			@ 9
-	PQoptions		@ 10
+	PQpass			@ 9
+	PQhost			@ 10
 	PQport			@ 11
 	PQtty			@ 12
-	PQstatus		@ 13
-	PQerrorMessage		@ 14
-	PQsocket		@ 15
-	PQtrace			@ 16
-	PQuntrace		@ 17
-	PQsetNoticeProcessor	@ 18
-	PQexec			@ 19
-	PQnotifies		@ 20
-	PQsendQuery		@ 21
-	PQgetResult		@ 22
-	PQisBusy		@ 23
-	PQconsumeInput		@ 24
-	PQgetline		@ 25
-	PQputline		@ 26
-	PQputnbytes		@ 27
-	PQendcopy		@ 28
-	PQfn			@ 29
-	PQresultStatus		@ 30
-	PQntuples		@ 31
-	PQnfields		@ 32
-	PQfname			@ 33
-	PQfnumber		@ 34
-	PQftype			@ 35
-	PQfsize			@ 36
-	PQfmod			@ 37
-	PQcmdStatus		@ 38
-	PQoidStatus		@ 39
-	PQcmdTuples		@ 40
-	PQgetvalue		@ 41
-	PQgetlength		@ 42
-	PQgetisnull		@ 43
-	PQclear			@ 44
-	PQprint			@ 45
-	PQdisplayTuples		@ 46
-	PQprintTuples		@ 47
-	lo_open			@ 48
-	lo_close		@ 49
-	lo_read			@ 50
-	lo_write		@ 51
-	lo_lseek		@ 52
-	lo_creat		@ 53
-	lo_tell			@ 54
-	lo_unlink		@ 55
-	lo_import		@ 56
-	lo_export		@ 57
+	PQoptions		@ 13
+	PQstatus		@ 14
+	PQerrorMessage		@ 15
+	PQsocket		@ 16
+	PQbackendPID		@ 17
+	PQtrace			@ 18
+	PQuntrace		@ 19
+	PQsetNoticeProcessor	@ 20
+	PQexec			@ 21
+	PQnotifies		@ 22
+	PQsendQuery		@ 23
+	PQgetResult		@ 24
+	PQisBusy		@ 25
+	PQconsumeInput		@ 26
+	PQgetline		@ 27
+	PQputline		@ 28
+	PQgetlineAsync		@ 29
+	PQputnbytes		@ 30
+	PQendcopy		@ 31
+	PQfn			@ 32
+	PQresultStatus		@ 33
+	PQntuples		@ 34
+	PQnfields		@ 35
+	PQbinaryTuples		@ 36
+	PQfname			@ 37
+	PQfnumber		@ 38
+	PQftype			@ 39
+	PQfsize			@ 40
+	PQfmod			@ 41
+	PQcmdStatus		@ 42
+	PQoidStatus		@ 43
+	PQcmdTuples		@ 44
+	PQgetvalue		@ 45
+	PQgetlength		@ 46
+	PQgetisnull		@ 47
+	PQclear			@ 48
+	PQmakeEmptyPGresult	@ 49
+	PQprint			@ 50
+	PQdisplayTuples		@ 51
+	PQprintTuples		@ 52
+	lo_open			@ 53
+	lo_close		@ 54
+	lo_read			@ 55
+	lo_write		@ 56
+	lo_lseek		@ 57
+	lo_creat		@ 58
+	lo_tell			@ 59
+	lo_unlink		@ 60
+	lo_import		@ 61
+	lo_export		@ 62
diff --git a/src/interfaces/perl5/Pg.xs b/src/interfaces/perl5/Pg.xs
index 2de5e0107395eeac546c99ff655bef4983ac68c4..f66936cbc1958ca1d5e3bd36ac6e45ed9a4041ee 100644
--- a/src/interfaces/perl5/Pg.xs
+++ b/src/interfaces/perl5/Pg.xs
@@ -1,6 +1,6 @@
 /*-------------------------------------------------------
  *
- * $Id: Pg.xs,v 1.7 1998/06/01 16:41:19 mergl Exp $
+ * $Id: Pg.xs,v 1.8 1998/09/03 02:10:56 momjian Exp $
  *
  * Copyright (c) 1997, 1998  Edmund Mergl
  *
@@ -318,7 +318,7 @@ PQexec(conn, query)
 	char *	query
 	CODE:
 		RETVAL = PQexec(conn, query);
-                if (! RETVAL) { RETVAL = (PGresult *)calloc(1, sizeof(PGresult)); }
+                if (! RETVAL) { RETVAL = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); }
 	OUTPUT:
 		RETVAL
 
@@ -752,7 +752,7 @@ PQexec(conn, query)
 		if (RETVAL) {
 			RETVAL->result = PQexec((PGconn *)conn, query);
 			if (!RETVAL->result) {
-				RETVAL->result = (PG_result)calloc(1, sizeof(PGresult));
+				RETVAL->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
 			}
 		}
 	OUTPUT: