summaryrefslogtreecommitdiffstats
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c89
1 files changed, 45 insertions, 44 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index a1c1831..a427771 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -352,8 +352,7 @@ static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
bool attrsOnly, bool missing_ok);
static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
int prettyFlags, bool missing_ok);
-static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
- int prettyFlags);
+static text *pg_get_expr_worker(text *expr, Oid relid, int prettyFlags);
static int print_function_arguments(StringInfo buf, HeapTuple proctup,
bool print_table_args, bool print_defaults);
static void print_function_rettype(StringInfo buf, HeapTuple proctup);
@@ -2630,6 +2629,11 @@ decompile_column_index_array(Datum column_index_array, Oid relId,
* partial indexes, column default expressions, etc. We also support
* Var-free expressions, for which the OID can be InvalidOid.
*
+ * If the OID is nonzero but not actually valid, don't throw an error,
+ * just return NULL. This is a bit questionable, but it's what we've
+ * done historically, and it can help avoid unwanted failures when
+ * examining catalog entries for just-deleted relations.
+ *
* We expect this function to work, or throw a reasonably clean error,
* for any node tree that can appear in a catalog pg_node_tree column.
* Query trees, such as those appearing in pg_rewrite.ev_action, are
@@ -2642,29 +2646,16 @@ pg_get_expr(PG_FUNCTION_ARGS)
{
text *expr = PG_GETARG_TEXT_PP(0);
Oid relid = PG_GETARG_OID(1);
+ text *result;
int prettyFlags;
- char *relname;
prettyFlags = PRETTYFLAG_INDENT;
- if (OidIsValid(relid))
- {
- /* Get the name for the relation */
- relname = get_rel_name(relid);
-
- /*
- * If the OID isn't actually valid, don't throw an error, just return
- * NULL. This is a bit questionable, but it's what we've done
- * historically, and it can help avoid unwanted failures when
- * examining catalog entries for just-deleted relations.
- */
- if (relname == NULL)
- PG_RETURN_NULL();
- }
+ result = pg_get_expr_worker(expr, relid, prettyFlags);
+ if (result)
+ PG_RETURN_TEXT_P(result);
else
- relname = NULL;
-
- PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
+ PG_RETURN_NULL();
}
Datum
@@ -2673,33 +2664,27 @@ pg_get_expr_ext(PG_FUNCTION_ARGS)
text *expr = PG_GETARG_TEXT_PP(0);
Oid relid = PG_GETARG_OID(1);
bool pretty = PG_GETARG_BOOL(2);
+ text *result;
int prettyFlags;
- char *relname;
prettyFlags = GET_PRETTY_FLAGS(pretty);
- if (OidIsValid(relid))
- {
- /* Get the name for the relation */
- relname = get_rel_name(relid);
- /* See notes above */
- if (relname == NULL)
- PG_RETURN_NULL();
- }
+ result = pg_get_expr_worker(expr, relid, prettyFlags);
+ if (result)
+ PG_RETURN_TEXT_P(result);
else
- relname = NULL;
-
- PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
+ PG_RETURN_NULL();
}
static text *
-pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
+pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
{
Node *node;
Node *tst;
Relids relids;
List *context;
char *exprstr;
+ Relation rel = NULL;
char *str;
/* Convert input pg_node_tree (really TEXT) object to C string */
@@ -2744,9 +2729,19 @@ pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
errmsg("expression contains variables")));
}
- /* Prepare deparse context if needed */
+ /*
+ * Prepare deparse context if needed. If we are deparsing with a relid,
+ * we need to transiently open and lock the rel, to make sure it won't go
+ * away underneath us. (set_relation_column_names would lock it anyway,
+ * so this isn't really introducing any new behavior.)
+ */
if (OidIsValid(relid))
- context = deparse_context_for(relname, relid);
+ {
+ rel = try_relation_open(relid, AccessShareLock);
+ if (rel == NULL)
+ return NULL;
+ context = deparse_context_for(RelationGetRelationName(rel), relid);
+ }
else
context = NIL;
@@ -2754,6 +2749,9 @@ pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
str = deparse_expression_pretty(node, context, false, false,
prettyFlags, 0);
+ if (rel != NULL)
+ relation_close(rel, AccessShareLock);
+
return string_to_text(str);
}
@@ -5015,8 +5013,11 @@ set_deparse_plan(deparse_namespace *dpns, Plan *plan)
* For a WorkTableScan, locate the parent RecursiveUnion plan node and use
* that as INNER referent.
*
- * For MERGE, make the inner tlist point to the merge source tlist, which
- * is same as the targetlist that the ModifyTable's source plan provides.
+ * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
+ * INNER referent. This is the join from the target relation to the data
+ * source, and all INNER_VAR Vars in other parts of the query refer to its
+ * targetlist.
+ *
* For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
* excluded expression's tlist. (Similar to the SubqueryScan we don't want
* to reuse OUTER, it's used for RETURNING in some modify table cases,
@@ -5031,17 +5032,17 @@ set_deparse_plan(deparse_namespace *dpns, Plan *plan)
dpns->inner_plan = find_recursive_union(dpns,
(WorkTableScan *) plan);
else if (IsA(plan, ModifyTable))
- dpns->inner_plan = plan;
- else
- dpns->inner_plan = innerPlan(plan);
-
- if (IsA(plan, ModifyTable))
{
if (((ModifyTable *) plan)->operation == CMD_MERGE)
- dpns->inner_tlist = dpns->outer_tlist;
+ dpns->inner_plan = outerPlan(plan);
else
- dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
+ dpns->inner_plan = plan;
}
+ else
+ dpns->inner_plan = innerPlan(plan);
+
+ if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
+ dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
else if (dpns->inner_plan)
dpns->inner_tlist = dpns->inner_plan->targetlist;
else