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