diff options
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 89 |
1 files changed, 45 insertions, 44 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 834e170..f01cc25 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); @@ -2599,6 +2598,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 @@ -2611,29 +2615,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 @@ -2642,33 +2633,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 */ @@ -2713,9 +2698,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; @@ -2723,6 +2718,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); } @@ -4975,8 +4973,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, @@ -4991,17 +4992,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 |