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

Commit 858d169

Browse files
committed
Provide some rather hokey ways for EXPLAIN to print FieldStore and assignment
ArrayRef expressions that are not in the immediate context of an INSERT or UPDATE targetlist. Such cases never arise in stored rules, so ruleutils.c hadn't tried to handle them. However, they do occur in the targetlists of plans derived from such statements, and now that EXPLAIN VERBOSE tries to print targetlists, we need some way to deal with the case. I chose to represent an assignment ArrayRef as "array[subscripts] := source", which is fairly reasonable and doesn't omit any information. However, FieldStore is problematic because the planner will fold multiple assignments to fields of the same composite column into one FieldStore, resulting in a structure that is hard to understand at all, let alone display comprehensibly. So in that case I punted and just made it print the source expression(s). Backpatch to 8.4 --- the lack of functionality exists in older releases, but doesn't seem to be important for lack of anything that would call it.
1 parent 11d5ba9 commit 858d169

File tree

1 file changed

+75
-15
lines changed

1 file changed

+75
-15
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.323 2010/02/16 22:34:50 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.324 2010/02/18 22:43:31 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -4468,6 +4468,22 @@ get_rule_expr(Node *node, deparse_context *context,
44684468
ArrayRef *aref = (ArrayRef *) node;
44694469
bool need_parens;
44704470

4471+
/*
4472+
* If the argument is a CaseTestExpr, we must be inside a
4473+
* FieldStore, ie, we are assigning to an element of an
4474+
* array within a composite column. Since we already punted
4475+
* on displaying the FieldStore's target information, just
4476+
* punt here too, and display only the assignment source
4477+
* expression.
4478+
*/
4479+
if (IsA(aref->refexpr, CaseTestExpr))
4480+
{
4481+
Assert(aref->refassgnexpr);
4482+
get_rule_expr((Node *) aref->refassgnexpr,
4483+
context, showimplicit);
4484+
break;
4485+
}
4486+
44714487
/*
44724488
* Parenthesize the argument unless it's a simple Var or a
44734489
* FieldSelect. (In particular, if it's another ArrayRef, we
@@ -4480,14 +4496,35 @@ get_rule_expr(Node *node, deparse_context *context,
44804496
get_rule_expr((Node *) aref->refexpr, context, showimplicit);
44814497
if (need_parens)
44824498
appendStringInfoChar(buf, ')');
4483-
printSubscripts(aref, context);
44844499

44854500
/*
4486-
* Array assignment nodes should have been handled in
4487-
* processIndirection().
4501+
* If there's a refassgnexpr, we want to print the node in
4502+
* the format "array[subscripts] := refassgnexpr". This is
4503+
* not legal SQL, so decompilation of INSERT or UPDATE
4504+
* statements should always use processIndirection as part
4505+
* of the statement-level syntax. We should only see this
4506+
* when EXPLAIN tries to print the targetlist of a plan
4507+
* resulting from such a statement.
44884508
*/
44894509
if (aref->refassgnexpr)
4490-
elog(ERROR, "unexpected refassgnexpr");
4510+
{
4511+
Node *refassgnexpr;
4512+
4513+
/*
4514+
* Use processIndirection to print this node's
4515+
* subscripts as well as any additional field selections
4516+
* or subscripting in immediate descendants. It returns
4517+
* the RHS expr that is actually being "assigned".
4518+
*/
4519+
refassgnexpr = processIndirection(node, context, true);
4520+
appendStringInfoString(buf, " := ");
4521+
get_rule_expr(refassgnexpr, context, showimplicit);
4522+
}
4523+
else
4524+
{
4525+
/* Just an ordinary array fetch, so print subscripts */
4526+
printSubscripts(aref, context);
4527+
}
44914528
}
44924529
break;
44934530

@@ -4679,12 +4716,36 @@ get_rule_expr(Node *node, deparse_context *context,
46794716
break;
46804717

46814718
case T_FieldStore:
4719+
{
4720+
FieldStore *fstore = (FieldStore *) node;
4721+
bool need_parens;
46824722

4683-
/*
4684-
* We shouldn't see FieldStore here; it should have been stripped
4685-
* off by processIndirection().
4686-
*/
4687-
elog(ERROR, "unexpected FieldStore");
4723+
/*
4724+
* There is no good way to represent a FieldStore as real SQL,
4725+
* so decompilation of INSERT or UPDATE statements should
4726+
* always use processIndirection as part of the
4727+
* statement-level syntax. We should only get here when
4728+
* EXPLAIN tries to print the targetlist of a plan resulting
4729+
* from such a statement. The plan case is even harder than
4730+
* ordinary rules would be, because the planner tries to
4731+
* collapse multiple assignments to the same field or subfield
4732+
* into one FieldStore; so we can see a list of target fields
4733+
* not just one, and the arguments could be FieldStores
4734+
* themselves. We don't bother to try to print the target
4735+
* field names; we just print the source arguments, with a
4736+
* ROW() around them if there's more than one. This isn't
4737+
* terribly complete, but it's probably good enough for
4738+
* EXPLAIN's purposes; especially since anything more would be
4739+
* either hopelessly confusing or an even poorer
4740+
* representation of what the plan is actually doing.
4741+
*/
4742+
need_parens = (list_length(fstore->newvals) != 1);
4743+
if (need_parens)
4744+
appendStringInfoString(buf, "ROW(");
4745+
get_rule_expr((Node *) fstore->newvals, context, showimplicit);
4746+
if (need_parens)
4747+
appendStringInfoChar(buf, ')');
4748+
}
46884749
break;
46894750

46904751
case T_RelabelType:
@@ -6307,12 +6368,11 @@ processIndirection(Node *node, deparse_context *context, bool printit)
63076368
format_type_be(fstore->resulttype));
63086369

63096370
/*
6310-
* Print the field name. Note we assume here that there's only
6311-
* one field being assigned to. This is okay in stored rules but
6312-
* could be wrong in executable target lists. Presently no
6313-
* problem since explain.c doesn't print plan targetlists, but
6314-
* someday may have to think of something ...
6371+
* Print the field name. There should only be one target field
6372+
* in stored rules. There could be more than that in executable
6373+
* target lists, but this function cannot be used for that case.
63156374
*/
6375+
Assert(list_length(fstore->fieldnums) == 1);
63166376
fieldname = get_relid_attribute_name(typrelid,
63176377
linitial_int(fstore->fieldnums));
63186378
if (printit)

0 commit comments

Comments
 (0)