Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9039813

Browse files
committed
Fix get_name_for_var_field() to deal with RECORD Params.
With 9.1's use of Params to pass down values from NestLoop join nodes to their inner plans, it is possible for a Param to have type RECORD, in which case the set of fields comprising the value isn't determinable by inspection of the Param alone. However, just as with a Var of type RECORD, we can find out what we need to know if we can locate the expression that the Param represents. We already knew how to do this in get_parameter(), but I'd overlooked the need to be able to cope in get_name_for_var_field(), which led to EXPLAIN failing with "record type has not been registered". To fix, refactor the search code in get_parameter() so it can be used by both functions. Per report from Marti Raudsepp.
1 parent d5d94e1 commit 9039813

File tree

1 file changed

+115
-56
lines changed

1 file changed

+115
-56
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 115 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,9 @@ static char *get_variable(Var *var, int levelsup, bool showstar,
207207
deparse_context *context);
208208
static RangeTblEntry *find_rte_by_refname(const char *refname,
209209
deparse_context *context);
210+
static Node *find_param_referent(Param *param, deparse_context *context,
211+
deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
210212
static void get_parameter(Param *param, deparse_context *context);
211-
static void print_parameter_expr(Node *expr, ListCell *ancestor_cell,
212-
deparse_namespace *dpns, deparse_context *context);
213213
static const char *get_simple_binary_op_name(OpExpr *expr);
214214
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
215215
static void appendContextKeyword(deparse_context *context, const char *str,
@@ -3889,15 +3889,21 @@ get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
38893889

38903890

38913891
/*
3892-
* Get the name of a field of an expression of composite type.
3893-
*
3894-
* This is fairly straightforward except for the case of a Var of type RECORD.
3895-
* Since no actual table or view column is allowed to have type RECORD, such
3896-
* a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We
3897-
* drill down to find the ultimate defining expression and attempt to infer
3898-
* the field name from it. We ereport if we can't determine the name.
3892+
* Get the name of a field of an expression of composite type. The
3893+
* expression is usually a Var, but we handle other cases too.
38993894
*
39003895
* levelsup is an extra offset to interpret the Var's varlevelsup correctly.
3896+
*
3897+
* This is fairly straightforward when the expression has a named composite
3898+
* type; we need only look up the type in the catalogs. However, the type
3899+
* could also be RECORD. Since no actual table or view column is allowed to
3900+
* have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
3901+
* or to a subquery output. We drill down to find the ultimate defining
3902+
* expression and attempt to infer the field name from it. We ereport if we
3903+
* can't determine the name.
3904+
*
3905+
* Similarly, a PARAM of type RECORD has to refer to some expression of
3906+
* a determinable composite type.
39013907
*/
39023908
static const char *
39033909
get_name_for_var_field(Var *var, int fieldno,
@@ -3922,6 +3928,29 @@ get_name_for_var_field(Var *var, int fieldno,
39223928
return strVal(list_nth(r->colnames, fieldno - 1));
39233929
}
39243930

3931+
/*
3932+
* If it's a Param of type RECORD, try to find what the Param refers to.
3933+
*/
3934+
if (IsA(var, Param))
3935+
{
3936+
Param *param = (Param *) var;
3937+
ListCell *ancestor_cell;
3938+
3939+
expr = find_param_referent(param, context, &dpns, &ancestor_cell);
3940+
if (expr)
3941+
{
3942+
/* Found a match, so recurse to decipher the field name */
3943+
deparse_namespace save_dpns;
3944+
const char *result;
3945+
3946+
push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
3947+
result = get_name_for_var_field((Var *) expr, fieldno,
3948+
0, context);
3949+
pop_ancestor_plan(dpns, &save_dpns);
3950+
return result;
3951+
}
3952+
}
3953+
39253954
/*
39263955
* If it's a Var of type RECORD, we have to find what the Var refers to;
39273956
* if not, we can use get_expr_result_type. If that fails, we try
@@ -4276,17 +4305,25 @@ find_rte_by_refname(const char *refname, deparse_context *context)
42764305
}
42774306

42784307
/*
4279-
* Display a Param appropriately.
4308+
* Try to find the referenced expression for a PARAM_EXEC Param that might
4309+
* reference a parameter supplied by an upper NestLoop or SubPlan plan node.
4310+
*
4311+
* If successful, return the expression and set *dpns_p and *ancestor_cell_p
4312+
* appropriately for calling push_ancestor_plan(). If no referent can be
4313+
* found, return NULL.
42804314
*/
4281-
static void
4282-
get_parameter(Param *param, deparse_context *context)
4315+
static Node *
4316+
find_param_referent(Param *param, deparse_context *context,
4317+
deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
42834318
{
4319+
/* Initialize output parameters to prevent compiler warnings */
4320+
*dpns_p = NULL;
4321+
*ancestor_cell_p = NULL;
4322+
42844323
/*
4285-
* If it's a PARAM_EXEC parameter, try to locate the expression from which
4286-
* the parameter was computed. This will necessarily be in some ancestor
4287-
* of the current expression's PlanState. Note that failing to find a
4288-
* referent isn't an error, since the Param might well be a subplan output
4289-
* rather than an input.
4324+
* If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
4325+
* SubPlan argument. This will necessarily be in some ancestor of the
4326+
* current expression's PlanState.
42904327
*/
42914328
if (param->paramkind == PARAM_EXEC)
42924329
{
@@ -4321,10 +4358,10 @@ get_parameter(Param *param, deparse_context *context)
43214358

43224359
if (nlp->paramno == param->paramid)
43234360
{
4324-
/* Found a match, so print it */
4325-
print_parameter_expr((Node *) nlp->paramval, lc,
4326-
dpns, context);
4327-
return;
4361+
/* Found a match, so return it */
4362+
*dpns_p = dpns;
4363+
*ancestor_cell_p = lc;
4364+
return (Node *) nlp->paramval;
43284365
}
43294366
}
43304367
}
@@ -4350,9 +4387,10 @@ get_parameter(Param *param, deparse_context *context)
43504387

43514388
if (paramid == param->paramid)
43524389
{
4353-
/* Found a match, so print it */
4354-
print_parameter_expr(arg, lc, dpns, context);
4355-
return;
4390+
/* Found a match, so return it */
4391+
*dpns_p = dpns;
4392+
*ancestor_cell_p = lc;
4393+
return arg;
43564394
}
43574395
}
43584396

@@ -4387,50 +4425,71 @@ get_parameter(Param *param, deparse_context *context)
43874425
}
43884426
}
43894427

4390-
/*
4391-
* Not PARAM_EXEC, or couldn't find referent: just print $N.
4392-
*/
4393-
appendStringInfo(context->buf, "$%d", param->paramid);
4428+
/* No referent found */
4429+
return NULL;
43944430
}
43954431

4396-
/* Print a parameter reference expression found by get_parameter */
4432+
/*
4433+
* Display a Param appropriately.
4434+
*/
43974435
static void
4398-
print_parameter_expr(Node *expr, ListCell *ancestor_cell,
4399-
deparse_namespace *dpns, deparse_context *context)
4436+
get_parameter(Param *param, deparse_context *context)
44004437
{
4401-
deparse_namespace save_dpns;
4402-
bool save_varprefix;
4403-
bool need_paren;
4404-
4405-
/* Switch attention to the ancestor plan node */
4406-
push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
4438+
Node *expr;
4439+
deparse_namespace *dpns;
4440+
ListCell *ancestor_cell;
44074441

44084442
/*
4409-
* Force prefixing of Vars, since they won't belong to the relation being
4410-
* scanned in the original plan node.
4443+
* If it's a PARAM_EXEC parameter, try to locate the expression from which
4444+
* the parameter was computed. Note that failing to find a referent isn't
4445+
* an error, since the Param might well be a subplan output rather than an
4446+
* input.
44114447
*/
4412-
save_varprefix = context->varprefix;
4413-
context->varprefix = true;
4448+
expr = find_param_referent(param, context, &dpns, &ancestor_cell);
4449+
if (expr)
4450+
{
4451+
/* Found a match, so print it */
4452+
deparse_namespace save_dpns;
4453+
bool save_varprefix;
4454+
bool need_paren;
44144455

4415-
/*
4416-
* A Param's expansion is typically a Var, Aggref, or upper-level Param,
4417-
* which wouldn't need extra parentheses. Otherwise, insert parens to
4418-
* ensure the expression looks atomic.
4419-
*/
4420-
need_paren = !(IsA(expr, Var) ||
4421-
IsA(expr, Aggref) ||
4422-
IsA(expr, Param));
4423-
if (need_paren)
4424-
appendStringInfoChar(context->buf, '(');
4456+
/* Switch attention to the ancestor plan node */
4457+
push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
44254458

4426-
get_rule_expr(expr, context, false);
4459+
/*
4460+
* Force prefixing of Vars, since they won't belong to the relation
4461+
* being scanned in the original plan node.
4462+
*/
4463+
save_varprefix = context->varprefix;
4464+
context->varprefix = true;
44274465

4428-
if (need_paren)
4429-
appendStringInfoChar(context->buf, ')');
4466+
/*
4467+
* A Param's expansion is typically a Var, Aggref, or upper-level
4468+
* Param, which wouldn't need extra parentheses. Otherwise, insert
4469+
* parens to ensure the expression looks atomic.
4470+
*/
4471+
need_paren = !(IsA(expr, Var) ||
4472+
IsA(expr, Aggref) ||
4473+
IsA(expr, Param));
4474+
if (need_paren)
4475+
appendStringInfoChar(context->buf, '(');
4476+
4477+
get_rule_expr(expr, context, false);
4478+
4479+
if (need_paren)
4480+
appendStringInfoChar(context->buf, ')');
4481+
4482+
context->varprefix = save_varprefix;
44304483

4431-
context->varprefix = save_varprefix;
4484+
pop_ancestor_plan(dpns, &save_dpns);
44324485

4433-
pop_ancestor_plan(dpns, &save_dpns);
4486+
return;
4487+
}
4488+
4489+
/*
4490+
* Not PARAM_EXEC, or couldn't find referent: just print $N.
4491+
*/
4492+
appendStringInfo(context->buf, "$%d", param->paramid);
44344493
}
44354494

44364495
/*

0 commit comments

Comments
 (0)