diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 3e5e573c6054b9a604f36652b63e1eb0a51efe1f..1d33b78cde72d6cf57caf1c22fa3758ca3a22a31 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.74 2008/05/12 20:01:59 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.75 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -68,7 +68,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
 		RequireTransactionChain(isTopLevel, "DECLARE CURSOR");
 
 	/*
-	 * Create a portal and copy the plan into its memory context.
+	 * Create a portal and copy the plan and queryString into its memory.
 	 */
 	portal = CreatePortal(cstmt->portalname, false, false);
 
@@ -77,8 +77,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
 	stmt = copyObject(stmt);
 	stmt->utilityStmt = NULL;	/* make it look like plain SELECT */
 
-	if (queryString)			/* copy the source text too for safety */
-		queryString = pstrdup(queryString);
+	queryString = pstrdup(queryString);
 
 	PortalDefineQuery(portal,
 					  NULL,
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 8361fc67554db87bdbb759b3df58895922714af6..bf6aad1ac148cb678445ddad024637c94cc345a5 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
  * Copyright (c) 2002-2008, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.87 2008/05/12 20:01:59 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.88 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -174,6 +174,7 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
 	ParamListInfo paramLI = NULL;
 	EState	   *estate = NULL;
 	Portal		portal;
+	char	   *query_string;
 
 	/* Look it up in the hash table */
 	entry = FetchPreparedStatement(stmt->name, true);
@@ -203,6 +204,10 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
 	/* Don't display the portal in pg_cursors, it is for internal use only */
 	portal->visible = false;
 
+	/* Copy the plan's saved query string into the portal's memory */
+	query_string = MemoryContextStrdup(PortalGetHeapMemory(portal),
+									   entry->plansource->query_string);
+
 	/*
 	 * For CREATE TABLE / AS EXECUTE, we must make a copy of the stored query
 	 * so that we can modify its destination (yech, but this has always been
@@ -249,13 +254,9 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
 		plan_list = cplan->stmt_list;
 	}
 
-	/*
-	 * Note: we don't bother to copy the source query string into the portal.
-	 * Any errors it might be useful for will already have been reported.
-	 */
 	PortalDefineQuery(portal,
 					  NULL,
-					  NULL,
+					  query_string,
 					  entry->plansource->commandTag,
 					  plan_list,
 					  cplan);
@@ -777,12 +778,7 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			values[0] = CStringGetTextDatum(prep_stmt->stmt_name);
-
-			if (prep_stmt->plansource->query_string == NULL)
-				nulls[1] = true;
-			else
-				values[1] = CStringGetTextDatum(prep_stmt->plansource->query_string);
-
+			values[1] = CStringGetTextDatum(prep_stmt->plansource->query_string);
 			values[2] = TimestampTzGetDatum(prep_stmt->prepare_time);
 			values[3] = build_regtype_array(prep_stmt->plansource->param_types,
 										  prep_stmt->plansource->num_params);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index cc9fd5d08da95aeec69c6396ab0921348d9dc44b..44f13df36148112ae5b6b0bfc1eacaad072ede97 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.235 2008/07/13 20:45:47 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.236 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -728,7 +728,8 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
 
 		/* ... and execute it */
 		ProcessUtility((Node *) atstmt,
-					   NULL, NULL, false, None_Receiver, NULL);
+					   "(generated ALTER TABLE ADD FOREIGN KEY command)",
+					   NULL, false, None_Receiver, NULL);
 
 		/* Remove the matched item from the list */
 		info_list = list_delete_ptr(info_list, info);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 32e53265d975c6320219120a3e9955ae79db4c5a..443ee57e682929e8b8d72b62a546a2682a6bacf2 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.196 2008/06/01 17:32:48 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.197 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1057,10 +1057,8 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
 	 */
 	oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
-	/* Copy the plan's query string, if available, into the portal */
-	query_string = plansource->query_string;
-	if (query_string)
-		query_string = pstrdup(query_string);
+	/* Copy the plan's query string into the portal */
+	query_string = pstrdup(plansource->query_string);
 
 	/* If the plan has parameters, copy them into the portal */
 	if (plan->nargs > 0)
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 831a7899188bea775fac7ffdca7e39bd3af27c01..520b503725550910d7fe494d39479b03bcdef524 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.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/backend/parser/analyze.c,v 1.372 2008/06/19 00:46:04 alvherre Exp $
+ *	$PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.373 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,9 +72,6 @@ static bool check_parameter_resolution_walker(Node *node,
  * parse_analyze
  *		Analyze a raw parse tree and transform it to Query form.
  *
- * If available, pass the source text from which the raw parse tree was
- * generated; it's OK to pass NULL if this is not available.
- *
  * Optionally, information about $n parameter types can be supplied.
  * References to $n indexes not defined by paramTypes[] are disallowed.
  *
@@ -89,6 +86,8 @@ parse_analyze(Node *parseTree, const char *sourceText,
 	ParseState *pstate = make_parsestate(NULL);
 	Query	   *query;
 
+	Assert(sourceText != NULL);				/* required as of 8.4 */
+
 	pstate->p_sourcetext = sourceText;
 	pstate->p_paramtypes = paramTypes;
 	pstate->p_numparams = numParams;
@@ -115,6 +114,8 @@ parse_analyze_varparams(Node *parseTree, const char *sourceText,
 	ParseState *pstate = make_parsestate(NULL);
 	Query	   *query;
 
+	Assert(sourceText != NULL);				/* required as of 8.4 */
+
 	pstate->p_sourcetext = sourceText;
 	pstate->p_paramtypes = *paramTypes;
 	pstate->p_numparams = *numParams;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index c6d6e1b55d9d6158e3e78f25a6b7b1593d81c78e..242388f2cb06571c7b18e53d53a6bec6616b2d98 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.553 2008/05/15 00:17:40 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.554 2008/07/18 20:26:06 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -1388,9 +1388,9 @@ exec_bind_message(StringInfo input_message)
 	/*
 	 * Report query to various monitoring facilities.
 	 */
-	debug_query_string = psrc->query_string ? psrc->query_string : "<BIND>";
+	debug_query_string = psrc->query_string;
 
-	pgstat_report_activity(debug_query_string);
+	pgstat_report_activity(psrc->query_string);
 
 	set_ps_display("BIND", false);
 
@@ -1466,10 +1466,8 @@ exec_bind_message(StringInfo input_message)
 	 */
 	oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
-	/* Copy the plan's query string, if available, into the portal */
-	query_string = psrc->query_string;
-	if (query_string)
-		query_string = pstrdup(query_string);
+	/* Copy the plan's query string into the portal */
+	query_string = pstrdup(psrc->query_string);
 
 	/* Likewise make a copy of the statement name, unless it's unnamed */
 	if (stmt_name[0])
@@ -1714,7 +1712,7 @@ exec_bind_message(StringInfo input_message)
 							*stmt_name ? stmt_name : "<unnamed>",
 							*portal_name ? "/" : "",
 							*portal_name ? portal_name : "",
-			psrc->query_string ? psrc->query_string : "<source not stored>"),
+							psrc->query_string),
 					 errhidestmt(true),
 					 errdetail_params(params)));
 			break;
@@ -1780,7 +1778,7 @@ exec_execute_message(const char *portal_name, long max_rows)
 	 */
 	if (is_xact_command)
 	{
-		sourceText = portal->sourceText ? pstrdup(portal->sourceText) : NULL;
+		sourceText = pstrdup(portal->sourceText);
 		if (portal->prepStmtName)
 			prepStmtName = pstrdup(portal->prepStmtName);
 		else
@@ -1805,9 +1803,9 @@ exec_execute_message(const char *portal_name, long max_rows)
 	/*
 	 * Report query to various monitoring facilities.
 	 */
-	debug_query_string = sourceText ? sourceText : "<EXECUTE>";
+	debug_query_string = sourceText;
 
-	pgstat_report_activity(debug_query_string);
+	pgstat_report_activity(sourceText);
 
 	set_ps_display(portal->commandTag, false);
 
@@ -1840,15 +1838,14 @@ exec_execute_message(const char *portal_name, long max_rows)
 	if (check_log_statement(portal->stmts))
 	{
 		ereport(LOG,
-				(errmsg("%s %s%s%s%s%s",
+				(errmsg("%s %s%s%s: %s",
 						execute_is_fetch ?
 						_("execute fetch from") :
 						_("execute"),
 						prepStmtName,
 						*portal_name ? "/" : "",
 						*portal_name ? portal_name : "",
-						sourceText ? ": " : "",
-						sourceText ? sourceText : ""),
+						sourceText),
 				 errhidestmt(true),
 				 errdetail_params(portalParams)));
 		was_logged = true;
@@ -1924,7 +1921,7 @@ exec_execute_message(const char *portal_name, long max_rows)
 			break;
 		case 2:
 			ereport(LOG,
-					(errmsg("duration: %s ms  %s %s%s%s%s%s",
+					(errmsg("duration: %s ms  %s %s%s%s: %s",
 							msec_str,
 							execute_is_fetch ?
 							_("execute fetch from") :
@@ -1932,8 +1929,7 @@ exec_execute_message(const char *portal_name, long max_rows)
 							prepStmtName,
 							*portal_name ? "/" : "",
 							*portal_name ? portal_name : "",
-							sourceText ? ": " : "",
-							sourceText ? sourceText : ""),
+							sourceText),
 					 errhidestmt(true),
 					 errdetail_params(portalParams)));
 			break;
@@ -2049,7 +2045,7 @@ errdetail_execute(List *raw_parsetree_list)
 			PreparedStatement *pstmt;
 
 			pstmt = FetchPreparedStatement(stmt->name, false);
-			if (pstmt && pstmt->plansource->query_string)
+			if (pstmt)
 			{
 				errdetail("prepare: %s", pstmt->plansource->query_string);
 				return 0;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 1922ffc960d8d70d0996cdfcaaf4752979bb9f69..3b8d5249f579b1346d6d7b3b428d1a26d90039ef 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.294 2008/06/15 01:25:54 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.295 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -218,13 +218,17 @@ check_xact_readonly(Node *parsetree)
  *		general utility function invoker
  *
  *	parsetree: the parse tree for the utility statement
- *	queryString: original source text of command (NULL if not available)
+ *	queryString: original source text of command
  *	params: parameters to use during execution
  *	isTopLevel: true if executing a "top level" (interactively issued) command
  *	dest: where to send results
  *	completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
  *		in which to store a command completion status string.
  *
+ * Notes: as of PG 8.4, caller MUST supply a queryString; it is not
+ * allowed anymore to pass NULL.  (If you really don't have source text,
+ * you can pass a constant string, perhaps "(query not available)".)
+ *
  * completionTag is only set nonempty if we want to return a nondefault status.
  *
  * completionTag may be NULL if caller doesn't want a status string.
@@ -237,6 +241,8 @@ ProcessUtility(Node *parsetree,
 			   DestReceiver *dest,
 			   char *completionTag)
 {
+	Assert(queryString != NULL);				/* required as of 8.4 */
+
 	check_xact_readonly(parsetree);
 
 	if (completionTag)
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index dbe889cb6cec7bf4706c4d164b61154726611b6e..fd0433bb3796387d84029b2cec9f77f03f57ca0c 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -33,7 +33,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.18 2008/05/12 20:02:02 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.19 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -104,8 +104,7 @@ InitPlanCache(void)
  * about all that we do here is copy it into permanent storage.
  *
  * raw_parse_tree: output of raw_parser()
- * query_string: original query text (can be NULL if not available, but
- *		that is discouraged because it degrades error message quality)
+ * query_string: original query text (as of PG 8.4, must not be NULL)
  * commandTag: compile-time-constant tag for query, or NULL if empty query
  * param_types: array of parameter type OIDs, or NULL if none
  * num_params: number of parameters
@@ -130,6 +129,8 @@ CreateCachedPlan(Node *raw_parse_tree,
 	MemoryContext source_context;
 	MemoryContext oldcxt;
 
+	Assert(query_string != NULL);				/* required as of 8.4 */
+
 	/*
 	 * Make a dedicated memory context for the CachedPlanSource and its
 	 * subsidiary data.  We expect it can be pretty small.
@@ -152,7 +153,7 @@ CreateCachedPlan(Node *raw_parse_tree,
 	oldcxt = MemoryContextSwitchTo(source_context);
 	plansource = (CachedPlanSource *) palloc(sizeof(CachedPlanSource));
 	plansource->raw_parse_tree = copyObject(raw_parse_tree);
-	plansource->query_string = query_string ? pstrdup(query_string) : NULL;
+	plansource->query_string = pstrdup(query_string);
 	plansource->commandTag = commandTag;		/* no copying needed */
 	if (num_params > 0)
 	{
@@ -228,6 +229,8 @@ FastCreateCachedPlan(Node *raw_parse_tree,
 	OverrideSearchPath *search_path;
 	MemoryContext oldcxt;
 
+	Assert(query_string != NULL);				/* required as of 8.4 */
+
 	/*
 	 * Fetch current search_path into given context, but do any recalculation
 	 * work required in caller's context.
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 4470961a28237e56aa844574634652ae33acfe10..b98b578ed24cdcb4f5332e157775572127c622c2 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.110 2008/05/12 00:00:52 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.111 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -271,7 +271,11 @@ CreateNewPortal(void)
  * PortalDefineQuery
  *		A simple subroutine to establish a portal's query.
  *
- * Notes: commandTag shall be NULL if and only if the original query string
+ * Notes: as of PG 8.4, caller MUST supply a sourceText string; it is not
+ * allowed anymore to pass NULL.  (If you really don't have source text,
+ * you can pass a constant string, perhaps "(query not available)".)
+ *
+ * commandTag shall be NULL if and only if the original query string
  * (before rewriting) was an empty string.	Also, the passed commandTag must
  * be a pointer to a constant string, since it is not copied.
  *
@@ -284,7 +288,7 @@ CreateNewPortal(void)
  * copying them into the portal's heap context.
  *
  * The caller is also responsible for ensuring that the passed prepStmtName
- * and sourceText (if not NULL) have adequate lifetime.
+ * (if not NULL) and sourceText have adequate lifetime.
  *
  * NB: this function mustn't do much beyond storing the passed values; in
  * particular don't do anything that risks elog(ERROR).  If that were to
@@ -302,7 +306,8 @@ PortalDefineQuery(Portal portal,
 	AssertArg(PortalIsValid(portal));
 	AssertState(portal->status == PORTAL_NEW);
 
-	Assert(commandTag != NULL || stmts == NIL);
+	AssertArg(sourceText != NULL);
+	AssertArg(commandTag != NULL || stmts == NIL);
 
 	portal->prepStmtName = prepStmtName;
 	portal->sourceText = sourceText;
@@ -927,10 +932,7 @@ pg_cursor(PG_FUNCTION_ARGS)
 		MemSet(nulls, 0, sizeof(nulls));
 
 		values[0] = CStringGetTextDatum(portal->name);
-		if (!portal->sourceText)
-			nulls[1] = true;
-		else
-			values[1] = CStringGetTextDatum(portal->sourceText);
+		values[1] = CStringGetTextDatum(portal->sourceText);
 		values[2] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_HOLD);
 		values[3] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_BINARY);
 		values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index f0e2c90131756d17e37de0986d83a2b5ad6711ec..878ba7907a363d43d29f775c024ac002bae6651b 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/plancache.h,v 1.11 2008/01/01 19:45:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/plancache.h,v 1.12 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,8 +20,7 @@
 /*
  * CachedPlanSource represents the portion of a cached plan that persists
  * across invalidation/replan cycles.  It stores a raw parse tree (required),
- * the original source text (optional, but highly recommended to improve
- * error reports), and adjunct data.
+ * the original source text (also required, as of 8.4), and adjunct data.
  *
  * Normally, both the struct itself and the subsidiary data live in the
  * context denoted by the context field, while the linked-to CachedPlan, if
@@ -47,7 +46,7 @@
 typedef struct CachedPlanSource
 {
 	Node	   *raw_parse_tree; /* output of raw_parser() */
-	char	   *query_string;	/* text of query, or NULL */
+	char	   *query_string;	/* text of query (as of 8.4, never NULL) */
 	const char *commandTag;		/* command tag (a constant!), or NULL */
 	Oid		   *param_types;	/* array of parameter type OIDs, or NULL */
 	int			num_params;		/* length of param_types array */
diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h
index a37c6ef1688850a9b5b2b9bd54b29ed92ad86756..c420d4d71edb474e2c057c965a57852a7edfad0d 100644
--- a/src/include/utils/portal.h
+++ b/src/include/utils/portal.h
@@ -39,7 +39,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.78 2008/01/01 19:45:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.79 2008/07/18 20:26:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -123,7 +123,7 @@ typedef struct PortalData
 	 */
 
 	/* The query or queries the portal will execute */
-	const char *sourceText;		/* text of query, if known (may be NULL) */
+	const char *sourceText;		/* text of query (as of 8.4, never NULL) */
 	const char *commandTag;		/* command tag for original query */
 	List	   *stmts;			/* PlannedStmts and/or utility statements */
 	CachedPlan *cplan;			/* CachedPlan, if stmts are from one */