Here's an updated patch that reports command status back to
ProcessUtility via 'bool' return value.

I was a bit unsure about using bool return values because it's not
immediately obvious what "true" or "false" refer to, but defining a
new enum seemed like overkill, so I went with bool anyway. Any better
ideas?

The 2nd patch also moves MOVE/FETCH command tag formatting up to
ProcessUtility, hopefully this change is for the better.

Regards,
Marti
From 25a19ca972e6f02ba350b6e4112935ff1ed44b24 Mon Sep 17 00:00:00 2001
From: Marti Raudsepp <ma...@juffo.org>
Date: Sun, 28 Nov 2010 16:49:41 +0200
Subject: [PATCH 1/2] Return command tag 'REPLACE X' for CREATE OR REPLACE statements.

This affects CREATE OR REPLACE LANGUAGE/VIEW/RULE/FUNCTION

Related functions that previously returned "void" have been changed to
"bool" to report status up. Others have a new argument bool *didReplace.
---
 src/backend/catalog/pg_aggregate.c  |    3 +-
 src/backend/catalog/pg_proc.c       |    6 ++++-
 src/backend/commands/functioncmds.c |   13 ++++++++--
 src/backend/commands/proclang.c     |   34 ++++++++++++++++++---------
 src/backend/commands/view.c         |   22 +++++++++--------
 src/backend/rewrite/rewriteDefine.c |   33 ++++++++++++++++++---------
 src/backend/tcop/utility.c          |   43 +++++++++++++++++++++++++++++++---
 src/include/catalog/pg_proc_fn.h    |    3 +-
 src/include/commands/defrem.h       |    2 +-
 src/include/commands/proclang.h     |    2 +-
 src/include/commands/view.h         |    2 +-
 src/include/rewrite/rewriteDefine.h |    4 +-
 12 files changed, 119 insertions(+), 48 deletions(-)

diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 86e8c6b..95e4469 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -229,7 +229,8 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,		/* prorows */
+							  NULL);	/* didReplace */
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2ab87d2..8b15efc 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -85,7 +85,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				bool *didReplace)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -650,6 +651,9 @@ ProcedureCreate(const char *procedureName,
 			AtEOXact_GUC(true, save_nestlevel);
 	}
 
+	if(didReplace)
+		*didReplace = is_update;
+
 	return retval;
 }
 
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 2a2b7c7..4678d9c 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -768,8 +768,11 @@ interpret_AS_clause(Oid languageOid, const char *languageName,
 /*
  * CreateFunction
  *	 Execute a CREATE FUNCTION utility statement.
+ *
+ * Returns TRUE if function was replaced via "CREATE OR REPLACE", FALSE
+ * if created.
  */
-void
+bool
 CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 {
 	char	   *probin_str;
@@ -791,7 +794,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 	Oid			requiredResultType;
 	bool		isWindowFunc,
 				isStrict,
-				security;
+				security,
+				didReplace;
 	char		volatility;
 	ArrayType  *proconfig;
 	float4		procost;
@@ -958,7 +962,10 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 					parameterDefaults,
 					PointerGetDatum(proconfig),
 					procost,
-					prorows);
+					prorows,
+					&didReplace);
+
+	return didReplace;
 }
 
 
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 3860105..7a1520c 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -49,7 +49,7 @@ typedef struct
 	char	   *tmpllibrary;	/* path of shared library */
 } PLTemplate;
 
-static void create_proc_lang(const char *languageName, bool replace,
+static bool create_proc_lang(const char *languageName, bool replace,
 				 Oid languageOwner, Oid handlerOid, Oid inlineOid,
 				 Oid valOid, bool trusted);
 static PLTemplate *find_language_template(const char *languageName);
@@ -59,9 +59,12 @@ static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel,
 
 /* ---------------------------------------------------------------------
  * CREATE PROCEDURAL LANGUAGE
+ *
+ * Returns TRUE if language was replaced via "CREATE OR REPLACE", FALSE
+ * if created.
  * ---------------------------------------------------------------------
  */
-void
+bool
 CreateProceduralLanguage(CreatePLangStmt *stmt)
 {
 	char	   *languageName;
@@ -146,7 +149,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 NULL);
 		}
 
 		/*
@@ -181,7 +185,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											NULL);
 			}
 		}
 		else
@@ -219,16 +224,17 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 NULL);
 			}
 		}
 		else
 			valOid = InvalidOid;
 
 		/* ok, create it */
-		create_proc_lang(languageName, stmt->replace, GetUserId(),
-						 handlerOid, inlineOid,
-						 valOid, pltemplate->tmpltrusted);
+		return create_proc_lang(languageName, stmt->replace, GetUserId(),
+								handlerOid, inlineOid,
+								valOid, pltemplate->tmpltrusted);
 	}
 	else
 	{
@@ -301,16 +307,18 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 			valOid = InvalidOid;
 
 		/* ok, create it */
-		create_proc_lang(languageName, stmt->replace, GetUserId(),
-						 handlerOid, inlineOid,
-						 valOid, stmt->pltrusted);
+		return create_proc_lang(languageName, stmt->replace, GetUserId(),
+								handlerOid, inlineOid,
+								valOid, stmt->pltrusted);
 	}
 }
 
 /*
  * Guts of language creation.
+ *
+ * Returns TRUE if function was replaced, FALSE otherwise.
  */
-static void
+static bool
 create_proc_lang(const char *languageName, bool replace,
 				 Oid languageOwner, Oid handlerOid, Oid inlineOid,
 				 Oid valOid, bool trusted)
@@ -431,6 +439,8 @@ create_proc_lang(const char *languageName, bool replace,
 						   LanguageRelationId, myself.objectId, 0);
 
 	heap_close(rel, RowExclusiveLock);
+
+	return is_update;
 }
 
 /*
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index a684172..41d4321 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -303,20 +303,20 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc)
 	 */
 }
 
-static void
+static bool
 DefineViewRules(Oid viewOid, Query *viewParse, bool replace)
 {
 	/*
 	 * Set up the ON SELECT rule.  Since the query has already been through
 	 * parse analysis, we use DefineQueryRewrite() directly.
 	 */
-	DefineQueryRewrite(pstrdup(ViewSelectRuleName),
-					   viewOid,
-					   NULL,
-					   CMD_SELECT,
-					   true,
-					   replace,
-					   list_make1(viewParse));
+	return DefineQueryRewrite(pstrdup(ViewSelectRuleName),
+							  viewOid,
+							  NULL,
+							  CMD_SELECT,
+							  true,
+							  replace,
+							  list_make1(viewParse));
 
 	/*
 	 * Someday: automatic ON INSERT, etc
@@ -392,8 +392,10 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
 /*
  * DefineView
  *		Execute a CREATE VIEW command.
+ *
+ * Returns TRUE if view was replaced via "CREATE OR REPLACE"
  */
-void
+bool
 DefineView(ViewStmt *stmt, const char *queryString)
 {
 	Query	   *viewParse;
@@ -489,5 +491,5 @@ DefineView(ViewStmt *stmt, const char *queryString)
 	/*
 	 * Now create the rules associated with the view.
 	 */
-	DefineViewRules(viewOid, viewParse, stmt->replace);
+	return DefineViewRules(viewOid, viewParse, stmt->replace);
 }
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 99c397b..518154e 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -56,7 +56,8 @@ InsertRule(char *rulname,
 		   bool evinstead,
 		   Node *event_qual,
 		   List *action,
-		   bool replace)
+		   bool replace,
+		   bool *didReplace)
 {
 	char	   *evqual = nodeToString(event_qual);
 	char	   *actiontree = nodeToString((Node *) action);
@@ -184,14 +185,18 @@ InsertRule(char *rulname,
 
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
 
+	*didReplace = is_update;
+
 	return rewriteObjectId;
 }
 
 /*
  * DefineRule
  *		Execute a CREATE RULE command.
+ *
+ * Returns TRUE if rule was replaced via "CREATE OR REPLACE".
  */
-void
+bool
 DefineRule(RuleStmt *stmt, const char *queryString)
 {
 	List	   *actions;
@@ -205,13 +210,13 @@ DefineRule(RuleStmt *stmt, const char *queryString)
 	relId = RangeVarGetRelid(stmt->relation, false);
 
 	/* ... and execute */
-	DefineQueryRewrite(stmt->rulename,
-					   relId,
-					   whereClause,
-					   stmt->event,
-					   stmt->instead,
-					   stmt->replace,
-					   actions);
+	return DefineQueryRewrite(stmt->rulename,
+							  relId,
+							  whereClause,
+							  stmt->event,
+							  stmt->instead,
+							  stmt->replace,
+							  actions);
 }
 
 
@@ -221,8 +226,10 @@ DefineRule(RuleStmt *stmt, const char *queryString)
  *
  * This is essentially the same as DefineRule() except that the rule's
  * action and qual have already been passed through parse analysis.
+ *
+ * Returns TRUE if rule was replaced, FALSE otherwise.
  */
-void
+bool
 DefineQueryRewrite(char *rulename,
 				   Oid event_relid,
 				   Node *event_qual,
@@ -237,6 +244,7 @@ DefineQueryRewrite(char *rulename,
 	ListCell   *l;
 	Query	   *query;
 	bool		RelisBecomingView = false;
+	bool		didReplace = false;
 
 	/*
 	 * If we are installing an ON SELECT rule, we had better grab
@@ -487,7 +495,8 @@ DefineQueryRewrite(char *rulename,
 							is_instead,
 							event_qual,
 							action,
-							replace);
+							replace,
+							&didReplace);
 
 		/*
 		 * Set pg_class 'relhasrules' field TRUE for event relation. If
@@ -512,6 +521,8 @@ DefineQueryRewrite(char *rulename,
 
 	/* Close rel, but keep lock till commit... */
 	heap_close(event_relation, NoLock);
+
+	return didReplace;
 }
 
 /*
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 9500037..b1120d0 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -336,6 +336,8 @@ standard_ProcessUtility(Node *parsetree,
 						DestReceiver *dest,
 						char *completionTag)
 {
+	bool		didReplace;
+
 	check_xact_readonly(parsetree);
 
 	if (completionTag)
@@ -891,11 +893,28 @@ standard_ProcessUtility(Node *parsetree,
 			break;
 
 		case T_ViewStmt:		/* CREATE VIEW */
-			DefineView((ViewStmt *) parsetree, queryString);
+			didReplace = DefineView((ViewStmt *) parsetree, queryString);
+
+			if (completionTag)
+			{
+				if (didReplace)
+					strcpy(completionTag, "REPLACE VIEW");
+				else
+					strcpy(completionTag, "CREATE VIEW");
+			}
 			break;
 
 		case T_CreateFunctionStmt:		/* CREATE FUNCTION */
-			CreateFunction((CreateFunctionStmt *) parsetree, queryString);
+			didReplace = CreateFunction((CreateFunctionStmt *) parsetree,
+										queryString);
+
+			if (completionTag)
+			{
+				if (didReplace)
+					strcpy(completionTag, "REPLACE FUNCTION");
+				else
+					strcpy(completionTag, "CREATE FUNCTION");
+			}
 			break;
 
 		case T_AlterFunctionStmt:		/* ALTER FUNCTION */
@@ -939,7 +958,15 @@ standard_ProcessUtility(Node *parsetree,
 			break;
 
 		case T_RuleStmt:		/* CREATE RULE */
-			DefineRule((RuleStmt *) parsetree, queryString);
+			didReplace = DefineRule((RuleStmt *) parsetree, queryString);
+
+			if (completionTag)
+			{
+				if (didReplace)
+					strcpy(completionTag, "REPLACE RULE");
+				else
+					strcpy(completionTag, "CREATE RULE");
+			}
 			break;
 
 		case T_CreateSeqStmt:
@@ -1110,7 +1137,15 @@ standard_ProcessUtility(Node *parsetree,
 			break;
 
 		case T_CreatePLangStmt:
-			CreateProceduralLanguage((CreatePLangStmt *) parsetree);
+			didReplace = CreateProceduralLanguage((CreatePLangStmt *) parsetree);
+
+			if (completionTag)
+			{
+				if (didReplace)
+					strcpy(completionTag, "REPLACE LANGUAGE");
+				else
+					strcpy(completionTag, "CREATE LANGUAGE");
+			}
 			break;
 
 		case T_DropPLangStmt:
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 09d779f..2e354b7 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -37,7 +37,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				bool *didReplace);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index a806f9e..530cc74 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -52,7 +52,7 @@ extern List *ChooseIndexColumnNames(List *indexElems);
 extern Oid	GetDefaultOpClass(Oid type_id, Oid am_id);
 
 /* commands/functioncmds.c */
-extern void CreateFunction(CreateFunctionStmt *stmt, const char *queryString);
+extern bool CreateFunction(CreateFunctionStmt *stmt, const char *queryString);
 extern void RemoveFunction(RemoveFuncStmt *stmt);
 extern void RemoveFunctionById(Oid funcOid);
 extern void SetFunctionReturnType(Oid funcOid, Oid newRetType);
diff --git a/src/include/commands/proclang.h b/src/include/commands/proclang.h
index aa1fb34..be91f3b 100644
--- a/src/include/commands/proclang.h
+++ b/src/include/commands/proclang.h
@@ -14,7 +14,7 @@
 
 #include "nodes/parsenodes.h"
 
-extern void CreateProceduralLanguage(CreatePLangStmt *stmt);
+extern bool CreateProceduralLanguage(CreatePLangStmt *stmt);
 extern void DropProceduralLanguage(DropPLangStmt *stmt);
 extern void DropProceduralLanguageById(Oid langOid);
 extern void RenameLanguage(const char *oldname, const char *newname);
diff --git a/src/include/commands/view.h b/src/include/commands/view.h
index 9751e32..f58122c 100644
--- a/src/include/commands/view.h
+++ b/src/include/commands/view.h
@@ -16,6 +16,6 @@
 
 #include "nodes/parsenodes.h"
 
-extern void DefineView(ViewStmt *stmt, const char *queryString);
+extern bool DefineView(ViewStmt *stmt, const char *queryString);
 
 #endif   /* VIEW_H */
diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h
index 4bf474b..052c002 100644
--- a/src/include/rewrite/rewriteDefine.h
+++ b/src/include/rewrite/rewriteDefine.h
@@ -22,9 +22,9 @@
 #define RULE_FIRES_ON_REPLICA	'R'
 #define RULE_DISABLED			'D'
 
-extern void DefineRule(RuleStmt *stmt, const char *queryString);
+extern bool DefineRule(RuleStmt *stmt, const char *queryString);
 
-extern void DefineQueryRewrite(char *rulename,
+extern bool DefineQueryRewrite(char *rulename,
 				   Oid event_relid,
 				   Node *event_qual,
 				   CmdType event_type,
-- 
1.7.3.5

From d11dc0f652277874e79a6eee4ece346e6978eea0 Mon Sep 17 00:00:00 2001
From: Marti Raudsepp <ma...@juffo.org>
Date: Sat, 15 Jan 2011 22:55:28 +0200
Subject: [PATCH 2/2] Move MOVE/FETCH command tag formatting to ProcessUtility.

---
 src/backend/commands/portalcmds.c |   20 ++++----------------
 src/backend/tcop/utility.c        |   13 +++++++++++--
 src/include/commands/portalcmds.h |    3 +--
 3 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index dda592c..80b581d 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -137,15 +137,12 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
  *
  *	stmt: parsetree node for 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.
  *
- * completionTag may be NULL if caller doesn't want a status string.
+ * Returns number of rows processed.
  */
-void
+long
 PerformPortalFetch(FetchStmt *stmt,
-				   DestReceiver *dest,
-				   char *completionTag)
+				   DestReceiver *dest)
 {
 	Portal		portal;
 	long		nprocessed;
@@ -174,16 +171,7 @@ PerformPortalFetch(FetchStmt *stmt,
 		dest = None_Receiver;
 
 	/* Do it */
-	nprocessed = PortalRunFetch(portal,
-								stmt->direction,
-								stmt->howMany,
-								dest);
-
-	/* Return command status if wanted */
-	if (completionTag)
-		snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld",
-				 stmt->ismove ? "MOVE" : "FETCH",
-				 nprocessed);
+	return PortalRunFetch(portal, stmt->direction, stmt->howMany, dest);
 }
 
 /*
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index b1120d0..40c9a02 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -482,8 +482,17 @@ standard_ProcessUtility(Node *parsetree,
 			break;
 
 		case T_FetchStmt:
-			PerformPortalFetch((FetchStmt *) parsetree, dest,
-							   completionTag);
+			{
+				FetchStmt *stmt = (FetchStmt *) parsetree;
+				long nprocessed;
+
+				nprocessed = PerformPortalFetch(stmt, dest);
+
+				if (completionTag)
+					snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
+							 stmt->ismove ? "MOVE %ld" : "FETCH %ld",
+							 nprocessed);
+			}
 			break;
 
 			/*
diff --git a/src/include/commands/portalcmds.h b/src/include/commands/portalcmds.h
index c64aabf..6afd737 100644
--- a/src/include/commands/portalcmds.h
+++ b/src/include/commands/portalcmds.h
@@ -22,8 +22,7 @@
 extern void PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
 				  const char *queryString, bool isTopLevel);
 
-extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest,
-				   char *completionTag);
+extern long PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest);
 
 extern void PerformPortalClose(const char *name);
 
-- 
1.7.3.5

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to