diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c
index 6a12dc9ff51ab1c8668cdc4ea2641b0abc072af9..5865a2e4b6efb3fe1e96308e05dc3eb20fad7f7a 100644
--- a/src/bin/psql/input.c
+++ b/src/bin/psql/input.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.64 2008/01/01 19:45:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.65 2008/11/26 00:26:23 tgl Exp $
  */
 #include "postgres_fe.h"
 
@@ -184,7 +184,8 @@ gets_fromFile(FILE *source)
 		{
 			if (ferror(source))
 			{
-				psql_error("could not read from input file: %s\n", strerror(errno));
+				psql_error("could not read from input file: %s\n",
+						   strerror(errno));
 				return NULL;
 			}
 			break;
@@ -192,6 +193,12 @@ gets_fromFile(FILE *source)
 
 		appendPQExpBufferStr(buffer, line);
 
+		if (PQExpBufferBroken(buffer))
+		{
+			psql_error("out of memory\n");
+			return NULL;
+		}
+
 		/* EOL? */
 		if (buffer->data[buffer->len - 1] == '\n')
 		{
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index 526674c8181dd2ebcf5e0be775af219f4bdbccbb..16532e2d420c28f29abbedeb3370d5a3d342019e 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.92 2008/06/10 20:58:19 neilc Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.93 2008/11/26 00:26:23 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "mainloop.h"
@@ -26,9 +26,9 @@ int
 MainLoop(FILE *source)
 {
 	PsqlScanState scan_state;	/* lexer working state */
-	PQExpBuffer query_buf;		/* buffer for query being accumulated */
-	PQExpBuffer previous_buf;	/* if there isn't anything in the new buffer
-								 * yet, use this one for \e, etc. */
+	volatile PQExpBuffer query_buf;	/* buffer for query being accumulated */
+	volatile PQExpBuffer previous_buf;	/* if there isn't anything in the new
+								 * buffer yet, use this one for \e, etc. */
 	PQExpBuffer history_buf;	/* earlier lines of a multi-line command, not
 								 * yet saved to readline history */
 	char	   *line;			/* current line of input */
@@ -62,7 +62,9 @@ MainLoop(FILE *source)
 	query_buf = createPQExpBuffer();
 	previous_buf = createPQExpBuffer();
 	history_buf = createPQExpBuffer();
-	if (!query_buf || !previous_buf || !history_buf)
+	if (PQExpBufferBroken(query_buf) ||
+		PQExpBufferBroken(previous_buf) ||
+		PQExpBufferBroken(history_buf))
 	{
 		psql_error("out of memory\n");
 		exit(EXIT_FAILURE);
@@ -220,6 +222,12 @@ MainLoop(FILE *source)
 			scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
 			prompt_status = prompt_tmp;
 
+			if (PQExpBufferBroken(query_buf))
+			{
+				psql_error("out of memory\n");
+				exit(EXIT_FAILURE);
+			}
+
 			/*
 			 * Send command if semicolon found, or if end of line and we're in
 			 * single-line mode.
@@ -242,9 +250,15 @@ MainLoop(FILE *source)
 				success = SendQuery(query_buf->data);
 				slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
 
-				resetPQExpBuffer(previous_buf);
-				appendPQExpBufferStr(previous_buf, query_buf->data);
+				/* transfer query to previous_buf by pointer-swapping */
+				{
+					PQExpBuffer swap_buf = previous_buf;
+
+					previous_buf = query_buf;
+					query_buf = swap_buf;
+				}
 				resetPQExpBuffer(query_buf);
+
 				added_nl_pos = -1;
 				/* we need not do psql_scan_reset() here */
 			}
@@ -294,8 +308,13 @@ MainLoop(FILE *source)
 				{
 					success = SendQuery(query_buf->data);
 
-					resetPQExpBuffer(previous_buf);
-					appendPQExpBufferStr(previous_buf, query_buf->data);
+					/* transfer query to previous_buf by pointer-swapping */
+					{
+						PQExpBuffer swap_buf = previous_buf;
+
+						previous_buf = query_buf;
+						query_buf = swap_buf;
+					}
 					resetPQExpBuffer(query_buf);
 
 					/* flush any paren nesting info after forced send */
diff --git a/src/bin/psql/psqlscan.l b/src/bin/psql/psqlscan.l
index 02329b9e7578fe97a6a1ae2db3568f01b2653c0c..45dfba8d665515d7293af7410b559c61adbb1a97 100644
--- a/src/bin/psql/psqlscan.l
+++ b/src/bin/psql/psqlscan.l
@@ -33,7 +33,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.26 2008/10/29 08:04:53 petere Exp $
+ *	  $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.27 2008/11/26 00:26:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1453,6 +1453,12 @@ psql_scan_slash_option(PsqlScanState state,
 					error = true;
 				}
 
+				if (PQExpBufferBroken(&output))
+				{
+					psql_error("%s: out of memory\n", cmd);
+					error = true;
+				}
+
 				/* Now done with cmd, transfer result to mybuf */
 				resetPQExpBuffer(&mybuf);
 
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 2cfe36e3a22052988903302617fcec1ec965312a..ce6af2bcd328f4149dbd4409e351843a68a51dd8 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.369 2008/11/25 19:30:42 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.370 2008/11/26 00:26:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -585,7 +585,7 @@ PQconndefaults(void)
 	PQconninfoOption *connOptions;
 
 	initPQExpBuffer(&errorBuf);
-	if (errorBuf.data == NULL)
+	if (PQExpBufferBroken(&errorBuf))
 		return NULL;			/* out of memory already :-( */
 	connOptions = conninfo_parse("", &errorBuf, true);
 	termPQExpBuffer(&errorBuf);
@@ -1970,8 +1970,8 @@ makeEmptyPGconn(void)
 
 	if (conn->inBuffer == NULL ||
 		conn->outBuffer == NULL ||
-		conn->errorMessage.data == NULL ||
-		conn->workBuffer.data == NULL)
+		PQExpBufferBroken(&conn->errorMessage) ||
+		PQExpBufferBroken(&conn->workBuffer))
 	{
 		/* out of memory already :-( */
 		freePGconn(conn);
@@ -3151,7 +3151,7 @@ PQconninfoParse(const char *conninfo, char **errmsg)
 	if (errmsg)
 		*errmsg = NULL;			/* default */
 	initPQExpBuffer(&errorBuf);
-	if (errorBuf.data == NULL)
+	if (PQExpBufferBroken(&errorBuf))
 		return NULL;			/* out of memory already :-( */
 	connOptions = conninfo_parse(conninfo, &errorBuf, false);
 	if (connOptions == NULL && errmsg)
diff --git a/src/interfaces/libpq/pqexpbuffer.c b/src/interfaces/libpq/pqexpbuffer.c
index c8e80498d1f1c817708c68f7fcaa578760507fb0..aeb3a21a387cc69e1eebc3dc226322e9ec81b938 100644
--- a/src/interfaces/libpq/pqexpbuffer.c
+++ b/src/interfaces/libpq/pqexpbuffer.c
@@ -17,7 +17,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.24 2008/01/01 19:46:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.25 2008/11/26 00:26:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,6 +32,32 @@
 #include "win32.h"
 #endif
 
+
+/* All "broken" PQExpBuffers point to this string. */
+static const char oom_buffer[1] = "";
+
+
+/*
+ * markPQExpBufferBroken
+ *
+ * Put a PQExpBuffer in "broken" state if it isn't already.
+ */
+static void
+markPQExpBufferBroken(PQExpBuffer str)
+{
+	if (str->data != oom_buffer)
+		free(str->data);
+	/*
+	 * Casting away const here is a bit ugly, but it seems preferable to
+	 * not marking oom_buffer const.  We want to do that to encourage the
+	 * compiler to put oom_buffer in read-only storage, so that anyone who
+	 * tries to scribble on a broken PQExpBuffer will get a failure.
+	 */
+	str->data = (char *) oom_buffer;
+	str->len = 0;
+	str->maxlen = 0;
+}
+
 /*
  * createPQExpBuffer
  *
@@ -61,6 +87,7 @@ initPQExpBuffer(PQExpBuffer str)
 	str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
 	if (str->data == NULL)
 	{
+		str->data = (char *) oom_buffer;		/* see comment above */
 		str->maxlen = 0;
 		str->len = 0;
 	}
@@ -96,12 +123,10 @@ destroyPQExpBuffer(PQExpBuffer str)
 void
 termPQExpBuffer(PQExpBuffer str)
 {
-	if (str->data)
-	{
+	if (str->data != oom_buffer)
 		free(str->data);
-		str->data = NULL;
-	}
 	/* just for luck, make the buffer validly empty. */
+	str->data = (char *) oom_buffer;		/* see comment above */
 	str->maxlen = 0;
 	str->len = 0;
 }
@@ -109,15 +134,24 @@ termPQExpBuffer(PQExpBuffer str)
 /*
  * resetPQExpBuffer
  *		Reset a PQExpBuffer to empty
+ *
+ * Note: if possible, a "broken" PQExpBuffer is returned to normal.
  */
 void
 resetPQExpBuffer(PQExpBuffer str)
 {
 	if (str)
 	{
-		str->len = 0;
-		if (str->data)
+		if (str->data != oom_buffer)
+		{
+			str->len = 0;
 			str->data[0] = '\0';
+		}
+		else
+		{
+			/* try to reinitialize to valid state */
+			initPQExpBuffer(str);
+		}
 	}
 }
 
@@ -126,7 +160,8 @@ resetPQExpBuffer(PQExpBuffer str)
  * Make sure there is enough space for 'needed' more bytes in the buffer
  * ('needed' does not include the terminating null).
  *
- * Returns 1 if OK, 0 if failed to enlarge buffer.
+ * Returns 1 if OK, 0 if failed to enlarge buffer.  (In the latter case
+ * the buffer is left in "broken" state.)
  */
 int
 enlargePQExpBuffer(PQExpBuffer str, size_t needed)
@@ -134,13 +169,19 @@ enlargePQExpBuffer(PQExpBuffer str, size_t needed)
 	size_t		newlen;
 	char	   *newdata;
 
+	if (PQExpBufferBroken(str))
+		return 0;				/* already failed */
+
 	/*
 	 * Guard against ridiculous "needed" values, which can occur if we're fed
 	 * bogus data.	Without this, we can get an overflow or infinite loop in
 	 * the following.
 	 */
 	if (needed >= ((size_t) INT_MAX - str->len))
+	{
+		markPQExpBufferBroken(str);
 		return 0;
+	}
 
 	needed += str->len + 1;		/* total space required now */
 
@@ -173,6 +214,8 @@ enlargePQExpBuffer(PQExpBuffer str, size_t needed)
 		str->maxlen = newlen;
 		return 1;
 	}
+
+	markPQExpBufferBroken(str);
 	return 0;
 }
 
@@ -192,6 +235,9 @@ printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
 
 	resetPQExpBuffer(str);
 
+	if (PQExpBufferBroken(str))
+		return;					/* already failed */
+
 	for (;;)
 	{
 		/*
@@ -240,6 +286,9 @@ appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
 	size_t		avail;
 	int			nprinted;
 
+	if (PQExpBufferBroken(str))
+		return;					/* already failed */
+
 	for (;;)
 	{
 		/*
diff --git a/src/interfaces/libpq/pqexpbuffer.h b/src/interfaces/libpq/pqexpbuffer.h
index b834ac48082e84cc3cb820833a849bd6af8026fe..3acca24b56967dfa740230ef8fde3eea3bdd0e4c 100644
--- a/src/interfaces/libpq/pqexpbuffer.h
+++ b/src/interfaces/libpq/pqexpbuffer.h
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.h,v 1.19 2008/01/01 19:46:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.h,v 1.20 2008/11/26 00:26:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,6 +35,10 @@
  *				string size (including the terminating '\0' char) that we can
  *				currently store in 'data' without having to reallocate
  *				more space.  We must always have maxlen > len.
+ *
+ * An exception occurs if we failed to allocate enough memory for the string
+ * buffer.  In that case data points to a statically allocated empty string,
+ * and len = maxlen = 0.
  *-------------------------
  */
 typedef struct PQExpBufferData
@@ -46,6 +50,15 @@ typedef struct PQExpBufferData
 
 typedef PQExpBufferData *PQExpBuffer;
 
+/*------------------------
+ * Test for a broken (out of memory) PQExpBuffer.
+ * When a buffer is "broken", all operations except resetting or deleting it
+ * are no-ops.
+ *------------------------
+ */
+#define PQExpBufferBroken(str)  \
+	(!(str) || (str)->maxlen == 0)
+
 /*------------------------
  * Initial size of the data buffer in a PQExpBuffer.
  * NB: this must be large enough to hold error messages that might
@@ -103,6 +116,8 @@ extern void termPQExpBuffer(PQExpBuffer str);
 /*------------------------
  * resetPQExpBuffer
  *		Reset a PQExpBuffer to empty
+ *
+ * Note: if possible, a "broken" PQExpBuffer is returned to normal.
  */
 extern void resetPQExpBuffer(PQExpBuffer str);
 
@@ -111,7 +126,8 @@ extern void resetPQExpBuffer(PQExpBuffer str);
  * Make sure there is enough space for 'needed' more bytes in the buffer
  * ('needed' does not include the terminating null).
  *
- * Returns 1 if OK, 0 if failed to enlarge buffer.
+ * Returns 1 if OK, 0 if failed to enlarge buffer.  (In the latter case
+ * the buffer is left in "broken" state.)
  */
 extern int	enlargePQExpBuffer(PQExpBuffer str, size_t needed);