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