pqGetErrorNotice3(PGconn *conn, bool isError)
{
	PGresult   *res = NULL;
	PQExpBufferData workBuf;
	char		id;
	const char *val;
	const char *querytext = NULL;
	int			querypos = 0;

	/*
	 * Since the fields 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.	We shouldn't use
	 * conn->errorMessage either, since this might be only a notice.
	 */
	initPQExpBuffer(&workBuf);

	/*
	 * Make a PGresult to hold the accumulated fields.	We temporarily lie
	 * about the result status, so that PQmakeEmptyPGresult doesn't uselessly
	 * copy conn->errorMessage.
	 */
	res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
	if (!res)
		goto fail;
	res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;

	/*
	 * Read the fields and save into res.
	 */
	for (;;)
	{
		if (pqGetc(&id, conn))
			goto fail;
		if (id == '\0')
			break;				/* terminator found */
		if (pqGets(&workBuf, conn))
			goto fail;
		pqSaveMessageField(res, id, workBuf.data);
	}

	/*
	 * Now build the "overall" error message for PQresultErrorMessage.
	 *
	 * Also, save the SQLSTATE in conn->last_sqlstate.
	 */
	resetPQExpBuffer(&workBuf);
	val = PQresultErrorField(res, PG_DIAG_SEVERITY);
	if (val)
		appendPQExpBuffer(&workBuf, "%s:  ", val);
	val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
	if (val)
	{
		if (strlen(val) < sizeof(conn->last_sqlstate))
			strcpy(conn->last_sqlstate, val);
		if (conn->verbosity == PQERRORS_VERBOSE)
			appendPQExpBuffer(&workBuf, "%s: ", val);
	}
	val = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
	if (val)
		appendPQExpBufferStr(&workBuf, val);
	val = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION);
	if (val)
	{
		if (conn->verbosity != PQERRORS_TERSE && conn->last_query != NULL)
		{
			/* emit position as a syntax cursor display */
			querytext = conn->last_query;
			querypos = atoi(val);
		}
		else
		{
			/* emit position as text addition to primary message */
			/* translator: %s represents a digit string */
			appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
							  val);
		}
	}
	else
	{
		val = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION);
		if (val)
		{
			querytext = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
			if (conn->verbosity != PQERRORS_TERSE && querytext != NULL)
			{
				/* emit position as a syntax cursor display */
				querypos = atoi(val);
			}
			else
			{
				/* emit position as text addition to primary message */
				/* translator: %s represents a digit string */
				appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
								  val);
			}
		}
	}
	appendPQExpBufferChar(&workBuf, '\n');
	if (conn->verbosity != PQERRORS_TERSE)
	{
		if (querytext && querypos > 0)
			reportErrorPosition(&workBuf, querytext, querypos,
								conn->client_encoding);
		val = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
		if (val)
			appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL:  %s\n"), val);
		val = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
		if (val)
			appendPQExpBuffer(&workBuf, libpq_gettext("HINT:  %s\n"), val);
		val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
		if (val)
			appendPQExpBuffer(&workBuf, libpq_gettext("QUERY:  %s\n"), val);
		val = PQresultErrorField(res, PG_DIAG_CONTEXT);
		if (val)
			appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT:  %s\n"), val);
	}
	if (conn->verbosity == PQERRORS_VERBOSE)
	{
		val = PQresultErrorField(res, PG_DIAG_SCHEMA_NAME);
		if (val)
			appendPQExpBuffer(&workBuf,
							  libpq_gettext("SCHEMA NAME:  %s\n"), val);
		val = PQresultErrorField(res, PG_DIAG_TABLE_NAME);
		if (val)
			appendPQExpBuffer(&workBuf,
							  libpq_gettext("TABLE NAME:  %s\n"), val);
		val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME);
		if (val)
			appendPQExpBuffer(&workBuf,
							  libpq_gettext("COLUMN NAME:  %s\n"), val);
		val = PQresultErrorField(res, PG_DIAG_DATATYPE_NAME);
		if (val)
			appendPQExpBuffer(&workBuf,
							  libpq_gettext("DATATYPE NAME:  %s\n"), val);
		val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_NAME);
		if (val)
			appendPQExpBuffer(&workBuf,
							  libpq_gettext("CONSTRAINT NAME:  %s\n"), val);
	}
	if (conn->verbosity == PQERRORS_VERBOSE)
	{
		const char *valf;
		const char *vall;

		valf = PQresultErrorField(res, PG_DIAG_SOURCE_FILE);
		vall = PQresultErrorField(res, PG_DIAG_SOURCE_LINE);
		val = PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION);
		if (val || valf || vall)
		{
			appendPQExpBufferStr(&workBuf, libpq_gettext("LOCATION:  "));
			if (val)
				appendPQExpBuffer(&workBuf, libpq_gettext("%s, "), val);
			if (valf && vall)	/* unlikely we'd have just one */
				appendPQExpBuffer(&workBuf, libpq_gettext("%s:%s"),
								  valf, vall);
			appendPQExpBufferChar(&workBuf, '\n');
		}
	}

	/*
	 * Either save error as current async result, or just emit the notice.
	 */
	if (isError)
	{
		res->errMsg = pqResultStrdup(res, workBuf.data);
		if (!res->errMsg)
			goto fail;
		pqClearAsyncResult(conn);
		conn->result = res;
		appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
	}
	else
	{
		/* We can cheat a little here and not copy the message. */
		res->errMsg = workBuf.data;
		if (res->noticeHooks.noticeRec != NULL)
			(*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
		PQclear(res);
	}

	termPQExpBuffer(&workBuf);
	return 0;

fail:
	PQclear(res);
	termPQExpBuffer(&workBuf);
	return EOF;
}