diff options
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 639 |
1 files changed, 329 insertions, 310 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 2f61b4a9fc5..765b3c65c30 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.250 2007/02/22 23:44:25 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.251 2007/02/23 21:59:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -90,17 +90,14 @@ typedef struct * * The rangetable is the list of actual RTEs from the query tree. * - * For deparsing plan trees, we allow two special RTE entries that are not - * part of the rtable list (partly because they don't have consecutively - * allocated varnos). + * For deparsing plan trees, we provide for outer and inner subplan nodes. + * The tlists of these nodes are used to resolve OUTER and INNER varnos. */ typedef struct { List *rtable; /* List of RangeTblEntry nodes */ - int outer_varno; /* varno for outer_rte */ - RangeTblEntry *outer_rte; /* special RangeTblEntry, or NULL */ - int inner_varno; /* varno for inner_rte */ - RangeTblEntry *inner_rte; /* special RangeTblEntry, or NULL */ + Plan *outer_plan; /* OUTER subplan, or NULL if none */ + Plan *inner_plan; /* INNER subplan, or NULL if none */ } deparse_namespace; @@ -158,8 +155,8 @@ static void get_setop_query(Node *setOp, Query *query, static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist, bool force_colno, deparse_context *context); -static void get_names_for_var(Var *var, int levelsup, deparse_context *context, - char **schemaname, char **refname, char **attname); +static char *get_variable(Var *var, int levelsup, bool showstar, + deparse_context *context); static RangeTblEntry *find_rte_by_refname(const char *refname, deparse_context *context); static const char *get_simple_binary_op_name(OpExpr *expr); @@ -1434,8 +1431,7 @@ deparse_context_for(const char *aliasname, Oid relid) /* Build one-element rtable */ dpns->rtable = list_make1(rte); - dpns->outer_varno = dpns->inner_varno = 0; - dpns->outer_rte = dpns->inner_rte = NULL; + dpns->outer_plan = dpns->inner_plan = NULL; /* Return a one-deep namespace stack */ return list_make1(dpns); @@ -1444,17 +1440,21 @@ deparse_context_for(const char *aliasname, Oid relid) /* * deparse_context_for_plan - Build deparse context for a plan node * - * The plan node may contain references to one or two subplans or outer - * join plan nodes. For these, pass the varno used plus a context node - * made with deparse_context_for_subplan. (Pass 0/NULL for unused inputs.) + * When deparsing an expression in a Plan tree, we might have to resolve + * OUTER or INNER references. Pass the plan nodes whose targetlists define + * such references, or NULL when none are expected. (outer_plan and + * inner_plan really ought to be declared as "Plan *", but we use "Node *" + * to avoid having to include plannodes.h in builtins.h.) + * + * As a special case, when deparsing a SubqueryScan plan, pass the subplan + * as inner_plan (there won't be any regular innerPlan() in this case). * * The plan's rangetable list must also be passed. We actually prefer to use * the rangetable to resolve simple Vars, but the subplan inputs are needed * for Vars that reference expressions computed in subplan target lists. */ List * -deparse_context_for_plan(int outer_varno, Node *outercontext, - int inner_varno, Node *innercontext, +deparse_context_for_plan(Node *outer_plan, Node *inner_plan, List *rtable) { deparse_namespace *dpns; @@ -1462,47 +1462,13 @@ deparse_context_for_plan(int outer_varno, Node *outercontext, dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace)); dpns->rtable = rtable; - dpns->outer_varno = outer_varno; - dpns->outer_rte = (RangeTblEntry *) outercontext; - dpns->inner_varno = inner_varno; - dpns->inner_rte = (RangeTblEntry *) innercontext; + dpns->outer_plan = (Plan *) outer_plan; + dpns->inner_plan = (Plan *) inner_plan; /* Return a one-deep namespace stack */ return list_make1(dpns); } -/* - * deparse_context_for_subplan - Build deparse context for a plan node - * - * Helper routine to build one of the inputs for deparse_context_for_plan. - * Pass the name to be used to reference the subplan, plus the Plan node. - * (subplan really ought to be declared as "Plan *", but we use "Node *" - * to avoid having to include plannodes.h in builtins.h.) - * - * The returned node is actually a RangeTblEntry, but we declare it as just - * Node to discourage callers from assuming anything. - */ -Node * -deparse_context_for_subplan(const char *name, Node *subplan) -{ - RangeTblEntry *rte = makeNode(RangeTblEntry); - - /* - * We create an RTE_SPECIAL RangeTblEntry, and store the subplan in its - * funcexpr field. RTE_SPECIAL nodes shouldn't appear in deparse contexts - * otherwise. - */ - rte->rtekind = RTE_SPECIAL; - rte->relid = InvalidOid; - rte->funcexpr = subplan; - rte->alias = NULL; - rte->eref = makeAlias(name, NIL); - rte->inh = false; - rte->inFromCl = true; - - return (Node *) rte; -} - /* ---------- * make_ruledef - reconstruct the CREATE RULE command * for a given pg_rewrite tuple @@ -1645,8 +1611,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, context.prettyFlags = prettyFlags; context.indentLevel = PRETTYINDENT_STD; dpns.rtable = query->rtable; - dpns.outer_varno = dpns.inner_varno = 0; - dpns.outer_rte = dpns.inner_rte = NULL; + dpns.outer_plan = dpns.inner_plan = NULL; get_rule_expr(qual, &context, false); } @@ -1789,8 +1754,7 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace, context.indentLevel = startIndent; dpns.rtable = query->rtable; - dpns.outer_varno = dpns.inner_varno = 0; - dpns.outer_rte = dpns.inner_rte = NULL; + dpns.outer_plan = dpns.inner_plan = NULL; switch (query->commandType) { @@ -2129,38 +2093,7 @@ get_target_list(List *targetList, deparse_context *context, */ if (tle->expr && IsA(tle->expr, Var)) { - Var *var = (Var *) (tle->expr); - char *schemaname; - char *refname; - - get_names_for_var(var, 0, context, - &schemaname, &refname, &attname); - if (refname && (context->varprefix || attname == NULL)) - { - if (schemaname) - appendStringInfo(buf, "%s.", - quote_identifier(schemaname)); - - if (strcmp(refname, "*NEW*") == 0) - appendStringInfoString(buf, "new"); - else if (strcmp(refname, "*OLD*") == 0) - appendStringInfoString(buf, "old"); - else - appendStringInfoString(buf, quote_identifier(refname)); - - if (attname) - appendStringInfoChar(buf, '.'); - } - if (attname) - appendStringInfoString(buf, quote_identifier(attname)); - else - { - /* - * In the whole-row Var case, refname is what the default AS - * name would be. - */ - attname = refname; - } + attname = get_variable((Var *) tle->expr, 0, false, context); } else { @@ -2596,25 +2529,60 @@ get_utility_query_def(Query *query, deparse_context *context) /* - * Get the RTE referenced by a (possibly nonlocal) Var. + * push_plan: set up deparse_namespace to recurse into the tlist of a subplan * - * The appropriate attribute number is stored into *attno - * (do not assume that var->varattno is what to use). + * When expanding an OUTER or INNER reference, we must push new outer/inner + * subplans in case the referenced expression itself uses OUTER/INNER. We + * modify the top stack entry in-place to avoid affecting levelsup issues + * (although in a Plan tree there really shouldn't be any). + * + * Caller must save and restore outer_plan and inner_plan around this. + */ +static void +push_plan(deparse_namespace *dpns, Plan *subplan) +{ + /* + * We special-case Append to pretend that the first child plan is the + * OUTER referent; otherwise normal. + */ + if (IsA(subplan, Append)) + dpns->outer_plan = (Plan *) linitial(((Append *) subplan)->appendplans); + else + dpns->outer_plan = outerPlan(subplan); + /* + * For a SubqueryScan, pretend the subplan is INNER referent. (We don't + * use OUTER because that could someday conflict with the normal meaning.) + */ + if (IsA(subplan, SubqueryScan)) + dpns->inner_plan = ((SubqueryScan *) subplan)->subplan; + else + dpns->inner_plan = innerPlan(subplan); +} + + +/* + * Display a Var appropriately. * * In some cases (currently only when recursing into an unnamed join) * the Var's varlevelsup has to be interpreted with respect to a context * above the current one; levelsup indicates the offset. + * + * If showstar is TRUE, whole-row Vars are displayed as "foo.*"; + * if FALSE, merely as "foo". + * + * Returns the attname of the Var, or NULL if not determinable. */ -static RangeTblEntry * -get_rte_for_var(Var *var, int levelsup, deparse_context *context, - AttrNumber *attno) +static char * +get_variable(Var *var, int levelsup, bool showstar, deparse_context *context) { + StringInfo buf = context->buf; RangeTblEntry *rte; + AttrNumber attnum; int netlevelsup; deparse_namespace *dpns; - - /* default assumption */ - *attno = var->varattno; + char *schemaname; + char *refname; + char *attname; /* Find appropriate nesting depth */ netlevelsup = var->varlevelsup + levelsup; @@ -2628,59 +2596,81 @@ get_rte_for_var(Var *var, int levelsup, deparse_context *context, * Try to find the relevant RTE in this rtable. In a plan tree, it's * likely that varno is OUTER or INNER, in which case we try to use * varnoold instead. If the Var references an expression computed by a - * subplan, varnoold will be 0, and we fall back to looking at the special - * subplan RTEs. + * subplan, varnoold will be 0, and we must dig down into the subplans. */ if (var->varno >= 1 && var->varno <= list_length(dpns->rtable)) + { rte = rt_fetch(var->varno, dpns->rtable); + attnum = var->varattno; + } else if (var->varnoold >= 1 && var->varnoold <= list_length(dpns->rtable)) { rte = rt_fetch(var->varnoold, dpns->rtable); - *attno = var->varoattno; + attnum = var->varoattno; } - else if (var->varno == dpns->outer_varno) - rte = dpns->outer_rte; - else if (var->varno == dpns->inner_varno) - rte = dpns->inner_rte; - else - rte = NULL; - if (rte == NULL) - elog(ERROR, "bogus varno: %d", var->varno); - return rte; -} + else if (var->varno == OUTER && dpns->outer_plan) + { + TargetEntry *tle; + Plan *save_outer; + Plan *save_inner; + tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno); + if (!tle) + elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno); -/* - * Get the schemaname, refname and attname for a (possibly nonlocal) Var. - * - * In some cases (currently only when recursing into an unnamed join) - * the Var's varlevelsup has to be interpreted with respect to a context - * above the current one; levelsup indicates the offset. - * - * schemaname is usually returned as NULL. It will be non-null only if - * use of the unqualified refname would find the wrong RTE. - * - * refname will be returned as NULL if the Var references an unnamed join. - * In this case the Var *must* be displayed without any qualification. - * - * attname will be returned as NULL if the Var represents a whole tuple - * of the relation. (Typically we'd want to display the Var as "foo.*", - * but it's convenient to return NULL to make it easier for callers to - * distinguish this case.) - */ -static void -get_names_for_var(Var *var, int levelsup, deparse_context *context, - char **schemaname, char **refname, char **attname) -{ - RangeTblEntry *rte; - AttrNumber attnum; + Assert(netlevelsup == 0); + save_outer = dpns->outer_plan; + save_inner = dpns->inner_plan; + push_plan(dpns, dpns->outer_plan); + + /* + * Force parentheses because our caller probably assumed a Var is a + * simple expression. + */ + appendStringInfoChar(buf, '('); + get_rule_expr((Node *) tle->expr, context, true); + appendStringInfoChar(buf, ')'); + + dpns->outer_plan = save_outer; + dpns->inner_plan = save_inner; + return NULL; + } + else if (var->varno == INNER && dpns->inner_plan) + { + TargetEntry *tle; + Plan *save_outer; + Plan *save_inner; + + tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno); + if (!tle) + elog(ERROR, "bogus varattno for INNER var: %d", var->varattno); - /* Find appropriate RTE */ - rte = get_rte_for_var(var, levelsup, context, &attnum); + Assert(netlevelsup == 0); + save_outer = dpns->outer_plan; + save_inner = dpns->inner_plan; + push_plan(dpns, dpns->inner_plan); - /* Emit results */ - *schemaname = NULL; /* default assumptions */ - *refname = rte->eref->aliasname; + /* + * Force parentheses because our caller probably assumed a Var is a + * simple expression. + */ + appendStringInfoChar(buf, '('); + get_rule_expr((Node *) tle->expr, context, true); + appendStringInfoChar(buf, ')'); + + dpns->outer_plan = save_outer; + dpns->inner_plan = save_inner; + return NULL; + } + else + { + elog(ERROR, "bogus varno: %d", var->varno); + return NULL; /* keep compiler quiet */ + } + + /* Identify names to use */ + schemaname = NULL; /* default assumptions */ + refname = rte->eref->aliasname; /* Exceptions occur only if the RTE is alias-less */ if (rte->alias == NULL) @@ -2693,18 +2683,17 @@ get_names_for_var(Var *var, int levelsup, deparse_context *context, * to specify the schemaname to avoid these errors. */ if (find_rte_by_refname(rte->eref->aliasname, context) != rte) - *schemaname = - get_namespace_name(get_rel_namespace(rte->relid)); + schemaname = get_namespace_name(get_rel_namespace(rte->relid)); } else if (rte->rtekind == RTE_JOIN) { /* * If it's an unnamed join, look at the expansion of the alias * variable. If it's a simple reference to one of the input vars - * then recursively find the name of that var, instead. (This + * then recursively print the name of that var, instead. (This * allows correct decompiling of cases where there are identically * named columns on both sides of the join.) When it's not a - * simple reference, we have to just return the unqualified + * simple reference, we have to just print the unqualified * variable name (this can only happen with columns that were * merged by USING or NATURAL clauses). */ @@ -2715,63 +2704,55 @@ get_names_for_var(Var *var, int levelsup, deparse_context *context, aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1); if (IsA(aliasvar, Var)) { - get_names_for_var(aliasvar, - var->varlevelsup + levelsup, context, - schemaname, refname, attname); - return; + return get_variable(aliasvar, var->varlevelsup + levelsup, + showstar, context); } } /* Unnamed join has neither schemaname nor refname */ - *refname = NULL; - } - else if (rte->rtekind == RTE_SPECIAL) - { - /* - * This case occurs during EXPLAIN when we are looking at a - * deparse context node set up by deparse_context_for_subplan(). - * If the subplan tlist provides a name, use it, but usually we'll - * end up with "?columnN?". - */ - List *tlist = ((Plan *) rte->funcexpr)->targetlist; - TargetEntry *tle = get_tle_by_resno(tlist, attnum); - - if (tle && tle->resname) - { - *attname = tle->resname; - } - else - { - char buf[32]; - - snprintf(buf, sizeof(buf), "?column%d?", attnum); - *attname = pstrdup(buf); - } - return; + refname = NULL; } } if (attnum == InvalidAttrNumber) - *attname = NULL; + attname = NULL; else - *attname = get_rte_attribute_name(rte, attnum); + attname = get_rte_attribute_name(rte, attnum); + + if (refname && (context->varprefix || attname == NULL)) + { + if (schemaname) + appendStringInfo(buf, "%s.", + quote_identifier(schemaname)); + + if (strcmp(refname, "*NEW*") == 0) + appendStringInfoString(buf, "new"); + else if (strcmp(refname, "*OLD*") == 0) + appendStringInfoString(buf, "old"); + else + appendStringInfoString(buf, quote_identifier(refname)); + + if (attname || showstar) + appendStringInfoChar(buf, '.'); + } + if (attname) + appendStringInfoString(buf, quote_identifier(attname)); + else if (showstar) + appendStringInfoChar(buf, '*'); + + return attname; } /* - * Get the name of a field of a Var of type RECORD. + * Get the name of a field of an expression of composite type. * + * This is fairly straightforward except for the case of a Var of type RECORD. * Since no actual table or view column is allowed to have type RECORD, such * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We * drill down to find the ultimate defining expression and attempt to infer * the field name from it. We ereport if we can't determine the name. * * levelsup is an extra offset to interpret the Var's varlevelsup correctly. - * - * Note: this has essentially the same logic as the parser's - * expandRecordVariable() function, but we are dealing with a different - * representation of the input context, and we only need one field name not - * a TupleDesc. Also, we have a special case for RTE_SPECIAL so that we can - * deal with displaying RECORD-returning functions in subplan targetlists. */ static const char * get_name_for_var_field(Var *var, int fieldno, @@ -2779,15 +2760,100 @@ get_name_for_var_field(Var *var, int fieldno, { RangeTblEntry *rte; AttrNumber attnum; + int netlevelsup; + deparse_namespace *dpns; TupleDesc tupleDesc; Node *expr; - /* Check my caller didn't mess up */ - Assert(IsA(var, Var)); - Assert(var->vartype == RECORDOID); + /* + * If it's a Var of type RECORD, we have to find what the Var refers to; + * if not, we can use get_expr_result_type. If that fails, we try + * lookup_rowtype_tupdesc, which will probably fail too, but will ereport + * an acceptable message. + */ + if (!IsA(var, Var) || + var->vartype != RECORDOID) + { + if (get_expr_result_type((Node *) var, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) + tupleDesc = lookup_rowtype_tupdesc_copy(exprType((Node *) var), + exprTypmod((Node *) var)); + Assert(tupleDesc); + /* Got the tupdesc, so we can extract the field name */ + Assert(fieldno >= 1 && fieldno <= tupleDesc->natts); + return NameStr(tupleDesc->attrs[fieldno - 1]->attname); + } + + /* Find appropriate nesting depth */ + netlevelsup = var->varlevelsup + levelsup; + if (netlevelsup >= list_length(context->namespaces)) + elog(ERROR, "bogus varlevelsup: %d offset %d", + var->varlevelsup, levelsup); + dpns = (deparse_namespace *) list_nth(context->namespaces, + netlevelsup); - /* Find appropriate RTE */ - rte = get_rte_for_var(var, levelsup, context, &attnum); + /* + * Try to find the relevant RTE in this rtable. In a plan tree, it's + * likely that varno is OUTER or INNER, in which case we must dig down + * into the subplans. (We can't shortcut with varnoold here, because + * it might reference a SUBQUERY RTE; we have to dig down to the + * SubqueryScan plan level to cope with that. See below.) + */ + if (var->varno >= 1 && var->varno <= list_length(dpns->rtable)) + { + rte = rt_fetch(var->varno, dpns->rtable); + attnum = var->varattno; + } + else if (var->varno == OUTER && dpns->outer_plan) + { + TargetEntry *tle; + Plan *save_outer; + Plan *save_inner; + const char *result; + + tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno); + if (!tle) + elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno); + + Assert(netlevelsup == 0); + save_outer = dpns->outer_plan; + save_inner = dpns->inner_plan; + push_plan(dpns, dpns->outer_plan); + + result = get_name_for_var_field((Var *) tle->expr, fieldno, + levelsup, context); + + dpns->outer_plan = save_outer; + dpns->inner_plan = save_inner; + return result; + } + else if (var->varno == INNER && dpns->inner_plan) + { + TargetEntry *tle; + Plan *save_outer; + Plan *save_inner; + const char *result; + + tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno); + if (!tle) + elog(ERROR, "bogus varattno for INNER var: %d", var->varattno); + + Assert(netlevelsup == 0); + save_outer = dpns->outer_plan; + save_inner = dpns->inner_plan; + push_plan(dpns, dpns->inner_plan); + + result = get_name_for_var_field((Var *) tle->expr, fieldno, + levelsup, context); + + dpns->outer_plan = save_outer; + dpns->inner_plan = save_inner; + return result; + } + else + { + elog(ERROR, "bogus varno: %d", var->varno); + return NULL; /* keep compiler quiet */ + } if (attnum == InvalidAttrNumber) { @@ -2795,11 +2861,19 @@ get_name_for_var_field(Var *var, int fieldno, return get_rte_attribute_name(rte, fieldno); } + /* + * This part has essentially the same logic as the parser's + * expandRecordVariable() function, but we are dealing with a different + * representation of the input context, and we only need one field name not + * a TupleDesc. Also, we need a special case for deparsing Plan trees, + * because the subquery field has been removed from SUBQUERY RTEs. + */ expr = (Node *) var; /* default if we can't drill down */ switch (rte->rtekind) { case RTE_RELATION: + case RTE_SPECIAL: case RTE_VALUES: /* @@ -2810,38 +2884,77 @@ get_name_for_var_field(Var *var, int fieldno, break; case RTE_SUBQUERY: { - /* Subselect-in-FROM: examine sub-select's output expr */ - TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList, - attnum); - - if (ste == NULL || ste->resjunk) - elog(ERROR, "subquery %s does not have attribute %d", - rte->eref->aliasname, attnum); - expr = (Node *) ste->expr; - if (IsA(expr, Var)) + if (rte->subquery) { - /* - * Recurse into the sub-select to see what its Var refers - * to. We have to build an additional level of namespace - * to keep in step with varlevelsup in the subselect. - */ - deparse_namespace mydpns; - const char *result; + /* Subselect-in-FROM: examine sub-select's output expr */ + TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList, + attnum); + + if (ste == NULL || ste->resjunk) + elog(ERROR, "subquery %s does not have attribute %d", + rte->eref->aliasname, attnum); + expr = (Node *) ste->expr; + if (IsA(expr, Var)) + { + /* + * Recurse into the sub-select to see what its Var + * refers to. We have to build an additional level of + * namespace to keep in step with varlevelsup in the + * subselect. + */ + deparse_namespace mydpns; + const char *result; - mydpns.rtable = rte->subquery->rtable; - mydpns.outer_varno = mydpns.inner_varno = 0; - mydpns.outer_rte = mydpns.inner_rte = NULL; + mydpns.rtable = rte->subquery->rtable; + mydpns.outer_plan = mydpns.inner_plan = NULL; - context->namespaces = lcons(&mydpns, context->namespaces); + context->namespaces = lcons(&mydpns, + context->namespaces); - result = get_name_for_var_field((Var *) expr, fieldno, - 0, context); + result = get_name_for_var_field((Var *) expr, fieldno, + 0, context); - context->namespaces = list_delete_first(context->namespaces); + context->namespaces = + list_delete_first(context->namespaces); + return result; + } + /* else fall through to inspect the expression */ + } + else + { + /* + * We're deparsing a Plan tree so we don't have complete + * RTE entries. But the only place we'd see a Var + * directly referencing a SUBQUERY RTE is in a SubqueryScan + * plan node, and we can look into the child plan's tlist + * instead. + */ + TargetEntry *tle; + Plan *save_outer; + Plan *save_inner; + const char *result; + + if (!dpns->inner_plan) + elog(ERROR, "failed to find plan for subquery %s", + rte->eref->aliasname); + tle = get_tle_by_resno(dpns->inner_plan->targetlist, + attnum); + if (!tle) + elog(ERROR, "bogus varattno for subquery var: %d", + attnum); + Assert(netlevelsup == 0); + save_outer = dpns->outer_plan; + save_inner = dpns->inner_plan; + push_plan(dpns, dpns->inner_plan); + + result = get_name_for_var_field((Var *) tle->expr, fieldno, + levelsup, context); + + dpns->outer_plan = save_outer; + dpns->inner_plan = save_inner; return result; } - /* else fall through to inspect the expression */ } break; case RTE_JOIN: @@ -2861,40 +2974,6 @@ get_name_for_var_field(Var *var, int fieldno, * its result columns as RECORD, which is not allowed. */ break; - case RTE_SPECIAL: - { - /* - * We are looking at a deparse context node set up by - * deparse_context_for_subplan(). The Var must refer to an - * expression computed by this subplan (or possibly one of its - * inputs), rather than any simple attribute of an RTE entry. - * Look into the subplan's target list to get the referenced - * expression, digging down as far as needed to find something - * that's not a Var, and then pass it to - * get_expr_result_type(). - */ - Plan *subplan = (Plan *) rte->funcexpr; - - for (;;) - { - TargetEntry *ste; - - ste = get_tle_by_resno(subplan->targetlist, - ((Var *) expr)->varattno); - if (!ste || !ste->expr) - break; - expr = (Node *) ste->expr; - if (!IsA(expr, Var)) - break; - if (((Var *) expr)->varno == INNER) - subplan = innerPlan(subplan); - else - subplan = outerPlan(subplan); - if (!subplan) - break; - } - } - break; } /* @@ -2906,7 +2985,7 @@ get_name_for_var_field(Var *var, int fieldno, if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr), exprTypmod(expr)); - + Assert(tupleDesc); /* Got the tupdesc, so we can extract the field name */ Assert(fieldno >= 1 && fieldno <= tupleDesc->natts); return NameStr(tupleDesc->attrs[fieldno - 1]->attname); @@ -2947,20 +3026,6 @@ find_rte_by_refname(const char *refname, deparse_context *context) result = rte; } } - if (dpns->outer_rte && - strcmp(dpns->outer_rte->eref->aliasname, refname) == 0) - { - if (result) - return NULL; /* it's ambiguous */ - result = dpns->outer_rte; - } - if (dpns->inner_rte && - strcmp(dpns->inner_rte->eref->aliasname, refname) == 0) - { - if (result) - return NULL; /* it's ambiguous */ - result = dpns->inner_rte; - } if (result) break; } @@ -3291,39 +3356,11 @@ get_rule_expr(Node *node, deparse_context *context, * expression tree. The only exception is that when the input is a List, * we emit the component items comma-separated with no surrounding * decoration; this is convenient for most callers. - * - * There might be some work left here to support additional node types. */ switch (nodeTag(node)) { case T_Var: - { - Var *var = (Var *) node; - char *schemaname; - char *refname; - char *attname; - - get_names_for_var(var, 0, context, - &schemaname, &refname, &attname); - if (refname && (context->varprefix || attname == NULL)) - { - if (schemaname) - appendStringInfo(buf, "%s.", - quote_identifier(schemaname)); - - if (strcmp(refname, "*NEW*") == 0) - appendStringInfoString(buf, "new."); - else if (strcmp(refname, "*OLD*") == 0) - appendStringInfoString(buf, "old."); - else - appendStringInfo(buf, "%s.", - quote_identifier(refname)); - } - if (attname) - appendStringInfoString(buf, quote_identifier(attname)); - else - appendStringInfoString(buf, "*"); - } + (void) get_variable((Var *) node, 0, true, context); break; case T_Const: @@ -3509,28 +3546,10 @@ get_rule_expr(Node *node, deparse_context *context, appendStringInfoChar(buf, ')'); /* - * If it's a Var of type RECORD, we have to find what the Var - * refers to; otherwise we can use get_expr_result_type. If - * that fails, we try lookup_rowtype_tupdesc, which will - * probably fail too, but will ereport an acceptable message. + * Get and print the field name. */ - if (IsA(arg, Var) && - ((Var *) arg)->vartype == RECORDOID) - fieldname = get_name_for_var_field((Var *) arg, fno, - 0, context); - else - { - TupleDesc tupdesc; - - if (get_expr_result_type(arg, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - tupdesc = lookup_rowtype_tupdesc_copy(exprType(arg), - exprTypmod(arg)); - Assert(tupdesc); - /* Got the tupdesc, so we can extract the field name */ - Assert(fno >= 1 && fno <= tupdesc->natts); - fieldname = NameStr(tupdesc->attrs[fno - 1]->attname); - } - + fieldname = get_name_for_var_field((Var *) arg, fno, + 0, context); appendStringInfo(buf, ".%s", quote_identifier(fieldname)); } break; |