diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 828f18e..b84e5ed 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -1801,6 +1801,10 @@ getCopyResult(PGconn *conn, ExecStatusType copytype)
 		return pqPrepareAsyncResult(conn);
 	}
 
+	/* If error has occured, return a PGRES_FATAL_ERROR result */
+	if (conn->result && conn->result->resultStatus == PGRES_FATAL_ERROR)
+		return pqPrepareAsyncResult(conn);
+
 	/* If we have an async result for the COPY, return that */
 	if (conn->result && conn->result->resultStatus == copytype)
 		return pqPrepareAsyncResult(conn);
@@ -1991,6 +1995,9 @@ PQexecFinish(PGconn *conn)
 	 * We have to stop if we see copy in/out/both, however. We will resume
 	 * parsing after application performs the data transfer.
 	 *
+	 * Stop if we are in copy mode and error has occurred, the pending results
+	 * will be discarded during next execution in PQexecStart.
+	 *
 	 * Also stop if the connection is lost (else we'll loop infinitely).
 	 */
 	lastResult = NULL;
@@ -2020,6 +2027,11 @@ PQexecFinish(PGconn *conn)
 			result->resultStatus == PGRES_COPY_BOTH ||
 			conn->status == CONNECTION_BAD)
 			break;
+		else if ((conn->asyncStatus == PGASYNC_COPY_IN ||
+				  conn->asyncStatus == PGASYNC_COPY_OUT  ||
+				  conn->asyncStatus == PGASYNC_COPY_BOTH) &&
+				 result->resultStatus == PGRES_FATAL_ERROR)
+			break;
 	}
 
 	return lastResult;
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index dbc0d89..05870a0 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -45,11 +45,13 @@
 
 static void handleSyncLoss(PGconn *conn, char id, int msgLength);
 static int	getRowDescriptions(PGconn *conn, int msgLength);
-static int	getParamDescriptions(PGconn *conn);
+static int	getParamDescriptions(PGconn *conn, int msgLength);
 static int	getAnotherTuple(PGconn *conn, int msgLength);
 static int	getParameterStatus(PGconn *conn);
 static int	getNotify(PGconn *conn);
-static int	getCopyStart(PGconn *conn, ExecStatusType copytype);
+static int	getCopyStart(PGconn *conn,
+						 ExecStatusType copytype,
+						 int msgLength);
 static int	getReadyForQuery(PGconn *conn);
 static void reportErrorPosition(PQExpBuffer msg, const char *query,
 					int loc, int encoding);
@@ -329,8 +331,11 @@ pqParseInput3(PGconn *conn)
 					}
 					break;
 				case 't':		/* Parameter Description */
-					if (getParamDescriptions(conn))
+					if (getParamDescriptions(conn, msgLength))
+					{
+						handleSyncLoss(conn, id, msgLength);
 						return;
+					}
 					break;
 				case 'D':		/* Data Row */
 					if (conn->result != NULL &&
@@ -362,19 +367,27 @@ pqParseInput3(PGconn *conn)
 					}
 					break;
 				case 'G':		/* Start Copy In */
-					if (getCopyStart(conn, PGRES_COPY_IN))
+					if (getCopyStart(conn, PGRES_COPY_IN, msgLength))
 						return;
+
+					/* getCopyStart() moves inStart itself */
 					conn->asyncStatus = PGASYNC_COPY_IN;
-					break;
+					continue;
 				case 'H':		/* Start Copy Out */
-					if (getCopyStart(conn, PGRES_COPY_OUT))
+					if (getCopyStart(conn, PGRES_COPY_OUT, msgLength))
 						return;
+
+					/* getCopyStart() moves inStart itself */
 					conn->asyncStatus = PGASYNC_COPY_OUT;
 					conn->copy_already_done = 0;
-					break;
+					continue;
 				case 'W':		/* Start Copy Both */
-					if (getCopyStart(conn, PGRES_COPY_BOTH))
-						return;
+					if (getCopyStart(conn, PGRES_COPY_BOTH, msgLength))
+					{
+						//handleSyncLoss(conn, id, msgLength);
+						//return;
+						continue;
+					}
 					conn->asyncStatus = PGASYNC_COPY_BOTH;
 					conn->copy_already_done = 0;
 					break;
@@ -630,27 +643,34 @@ advance_and_error:
 /*
  * parseInput subroutine to read a 't' (ParameterDescription) message.
  * We'll build a new PGresult structure containing the parameter data.
- * Returns: 0 if completed message, EOF if not enough data yet.
+ * Returns: 0 if completed message, EOF in case of error.
  *
  * Note that if we run out of data, we have to release the partially
  * constructed PGresult, and rebuild it again next time.  Fortunately,
  * that shouldn't happen often, since 't' messages usually fit in a packet.
  */
 static int
-getParamDescriptions(PGconn *conn)
+getParamDescriptions(PGconn *conn, int msgLength)
 {
 	PGresult   *result;
 	int			nparams;
 	int			i;
+	const char *errmsg;
 
 	result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
 	if (!result)
-		goto failure;
+	{
+		errmsg = NULL;
+		goto advance_and_error;
+	}
 
 	/* parseInput already read the 't' label and message length. */
 	/* the next two bytes are the number of parameters */
-	if (pqGetInt(&(result->numParameters), 2, conn))
-		goto failure;
+	if (pqGetInt(&result->numParameters, 2, conn))
+	{
+		errmsg = libpq_gettext("extraneous data in \"t\" message");
+		goto advance_and_error;
+	}
 	nparams = result->numParameters;
 
 	/* allocate space for the parameter descriptors */
@@ -659,7 +679,10 @@ getParamDescriptions(PGconn *conn)
 		result->paramDescs = (PGresParamDesc *)
 			pqResultAlloc(result, nparams * sizeof(PGresParamDesc), TRUE);
 		if (!result->paramDescs)
-			goto failure;
+		{
+			errmsg = NULL;
+			goto advance_and_error;
+		}
 		MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc));
 	}
 
@@ -669,7 +692,10 @@ getParamDescriptions(PGconn *conn)
 		int			typid;
 
 		if (pqGetInt(&typid, 4, conn))
-			goto failure;
+		{
+			errmsg = libpq_gettext("extraneous data in \"t\" message");
+			goto advance_and_error;
+		}
 		result->paramDescs[i].typid = typid;
 	}
 
@@ -677,8 +703,31 @@ getParamDescriptions(PGconn *conn)
 	conn->result = result;
 	return 0;
 
-failure:
-	PQclear(result);
+advance_and_error:
+	/* Discard unsaved result, if any */
+	if (result && result != conn->result)
+		PQclear(result);
+
+	/* Discard the failed message by pretending we read it */
+	conn->inStart += 5 + msgLength;
+
+	/*
+	 * 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");
+
+	printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
+	pqSaveErrorResult(conn);
 	return EOF;
 }
 
@@ -1338,31 +1387,45 @@ getNotify(PGconn *conn)
  * parseInput already read the message type and length.
  */
 static int
-getCopyStart(PGconn *conn, ExecStatusType copytype)
+getCopyStart(PGconn *conn, ExecStatusType copytype, int msgLength)
 {
 	PGresult   *result;
 	int			nfields;
 	int			i;
+	const char *errmsg;
 
 	result = PQmakeEmptyPGresult(conn, copytype);
 	if (!result)
-		goto failure;
+	{
+		errmsg = NULL;
+		goto advance_and_error;
+	}
 
 	if (pqGetc(&conn->copy_is_binary, conn))
-		goto failure;
+	{
+		errmsg = libpq_gettext("extraneous data in COPY start message");
+		goto advance_and_error;
+	}
 	result->binary = conn->copy_is_binary;
+
 	/* the next two bytes are the number of fields	*/
-	if (pqGetInt(&(result->numAttributes), 2, conn))
-		goto failure;
+	if (pqGetInt(&result->numAttributes, 2, conn))
+	{
+		errmsg = libpq_gettext("extraneous data in COPY start message");
+		goto advance_and_error;
+	}
 	nfields = result->numAttributes;
 
 	/* allocate space for the attribute descriptors */
-	if (nfields > 0)
+	if (result && nfields > 0)
 	{
 		result->attDescs = (PGresAttDesc *)
 			pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
 		if (!result->attDescs)
-			goto failure;
+		{
+			errmsg = NULL;
+			goto advance_and_error;
+		}
 		MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
 	}
 
@@ -1371,23 +1434,57 @@ getCopyStart(PGconn *conn, ExecStatusType copytype)
 		int			format;
 
 		if (pqGetInt(&format, 2, conn))
-			goto failure;
+		{
+			errmsg = libpq_gettext("extraneous data in COPY start message");
+			goto advance_and_error;
+		}
 
 		/*
 		 * Since pqGetInt treats 2-byte integers as unsigned, we need to
 		 * coerce these results to signed form.
 		 */
 		format = (int) ((int16) format);
-		result->attDescs[i].format = format;
+		if (result && result->attDescs)
+			result->attDescs[i].format = format;
 	}
 
 	/* Success! */
 	conn->result = result;
+
+	/*
+	 * Advance inStart to show that the copy related message has been
+	 * processed.
+	 */
+	conn->inStart = conn->inCursor;
+
 	return 0;
 
-failure:
-	PQclear(result);
-	return EOF;
+advance_and_error:
+	/* Discard unsaved result, if any */
+	if (result && result != conn->result)
+		PQclear(result);
+
+	/* Discard the failed message by pretending we read it */
+	conn->inStart += 5 + msgLength;
+
+	/*
+	 * 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");
+	printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
+	pqSaveErrorResult(conn);
+
+	return 0;
 }
 
 /*
