9
9
*
10
10
*
11
11
* 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 $
13
13
*
14
14
*-------------------------------------------------------------------------
15
15
*/
@@ -4468,6 +4468,22 @@ get_rule_expr(Node *node, deparse_context *context,
4468
4468
ArrayRef * aref = (ArrayRef * ) node ;
4469
4469
bool need_parens ;
4470
4470
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
+
4471
4487
/*
4472
4488
* Parenthesize the argument unless it's a simple Var or a
4473
4489
* FieldSelect. (In particular, if it's another ArrayRef, we
@@ -4480,14 +4496,35 @@ get_rule_expr(Node *node, deparse_context *context,
4480
4496
get_rule_expr ((Node * ) aref -> refexpr , context , showimplicit );
4481
4497
if (need_parens )
4482
4498
appendStringInfoChar (buf , ')' );
4483
- printSubscripts (aref , context );
4484
4499
4485
4500
/*
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.
4488
4508
*/
4489
4509
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
+ }
4491
4528
}
4492
4529
break ;
4493
4530
@@ -4679,12 +4716,36 @@ get_rule_expr(Node *node, deparse_context *context,
4679
4716
break ;
4680
4717
4681
4718
case T_FieldStore :
4719
+ {
4720
+ FieldStore * fstore = (FieldStore * ) node ;
4721
+ bool need_parens ;
4682
4722
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
+ }
4688
4749
break ;
4689
4750
4690
4751
case T_RelabelType :
@@ -6307,12 +6368,11 @@ processIndirection(Node *node, deparse_context *context, bool printit)
6307
6368
format_type_be (fstore -> resulttype ));
6308
6369
6309
6370
/*
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.
6315
6374
*/
6375
+ Assert (list_length (fstore -> fieldnums ) == 1 );
6316
6376
fieldname = get_relid_attribute_name (typrelid ,
6317
6377
linitial_int (fstore -> fieldnums ));
6318
6378
if (printit )
0 commit comments