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

Commit a7d9203

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 f195937 commit a7d9203

File tree

1 file changed

+115
-56
lines changed

1 file changed

+115
-56
lines changed

src/backend/utils/adt/ruleutils.c

+115-56
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,
@@ -3892,15 +3892,21 @@ get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
38923892

38933893

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

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

42814310
/*
4282-
* Display a Param appropriately.
4311+
* Try to find the referenced expression for a PARAM_EXEC Param that might
4312+
* reference a parameter supplied by an upper NestLoop or SubPlan plan node.
4313+
*
4314+
* If successful, return the expression and set *dpns_p and *ancestor_cell_p
4315+
* appropriately for calling push_ancestor_plan(). If no referent can be
4316+
* found, return NULL.
42834317
*/
4284-
static void
4285-
get_parameter(Param *param, deparse_context *context)
4318+
static Node *
4319+
find_param_referent(Param *param, deparse_context *context,
4320+
deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
42864321
{
4322+
/* Initialize output parameters to prevent compiler warnings */
4323+
*dpns_p = NULL;
4324+
*ancestor_cell_p = NULL;
4325+
42874326
/*
4288-
* If it's a PARAM_EXEC parameter, try to locate the expression from which
4289-
* the parameter was computed. This will necessarily be in some ancestor
4290-
* of the current expression's PlanState. Note that failing to find a
4291-
* referent isn't an error, since the Param might well be a subplan output
4292-
* rather than an input.
4327+
* If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
4328+
* SubPlan argument. This will necessarily be in some ancestor of the
4329+
* current expression's PlanState.
42934330
*/
42944331
if (param->paramkind == PARAM_EXEC)
42954332
{
@@ -4324,10 +4361,10 @@ get_parameter(Param *param, deparse_context *context)
43244361

43254362
if (nlp->paramno == param->paramid)
43264363
{
4327-
/* Found a match, so print it */
4328-
print_parameter_expr((Node *) nlp->paramval, lc,
4329-
dpns, context);
4330-
return;
4364+
/* Found a match, so return it */
4365+
*dpns_p = dpns;
4366+
*ancestor_cell_p = lc;
4367+
return (Node *) nlp->paramval;
43314368
}
43324369
}
43334370
}
@@ -4353,9 +4390,10 @@ get_parameter(Param *param, deparse_context *context)
43534390

43544391
if (paramid == param->paramid)
43554392
{
4356-
/* Found a match, so print it */
4357-
print_parameter_expr(arg, lc, dpns, context);
4358-
return;
4393+
/* Found a match, so return it */
4394+
*dpns_p = dpns;
4395+
*ancestor_cell_p = lc;
4396+
return arg;
43594397
}
43604398
}
43614399

@@ -4390,50 +4428,71 @@ get_parameter(Param *param, deparse_context *context)
43904428
}
43914429
}
43924430

4393-
/*
4394-
* Not PARAM_EXEC, or couldn't find referent: just print $N.
4395-
*/
4396-
appendStringInfo(context->buf, "$%d", param->paramid);
4431+
/* No referent found */
4432+
return NULL;
43974433
}
43984434

4399-
/* Print a parameter reference expression found by get_parameter */
4435+
/*
4436+
* Display a Param appropriately.
4437+
*/
44004438
static void
4401-
print_parameter_expr(Node *expr, ListCell *ancestor_cell,
4402-
deparse_namespace *dpns, deparse_context *context)
4439+
get_parameter(Param *param, deparse_context *context)
44034440
{
4404-
deparse_namespace save_dpns;
4405-
bool save_varprefix;
4406-
bool need_paren;
4407-
4408-
/* Switch attention to the ancestor plan node */
4409-
push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
4441+
Node *expr;
4442+
deparse_namespace *dpns;
4443+
ListCell *ancestor_cell;
44104444

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

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

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

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

4434-
context->varprefix = save_varprefix;
4487+
pop_ancestor_plan(dpns, &save_dpns);
44354488

4436-
pop_ancestor_plan(dpns, &save_dpns);
4489+
return;
4490+
}
4491+
4492+
/*
4493+
* Not PARAM_EXEC, or couldn't find referent: just print $N.
4494+
*/
4495+
appendStringInfo(context->buf, "$%d", param->paramid);
44374496
}
44384497

44394498
/*

0 commit comments

Comments
 (0)