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

Commit a73b756

Browse files
committed
transformExpr() did the Wrong Thing if applied to a SubLink node that
had already been transformed. This led to failure in examples like UPDATE table SET fld = (SELECT ...). Repair this, and revise the comments to explain that transformExpr has to be robust against this condition. Someday we might want to fix the callers so that transformExpr is never invoked on its own output, but that someday is not today.
1 parent 52d0265 commit a73b756

File tree

1 file changed

+37
-19
lines changed

1 file changed

+37
-19
lines changed

src/backend/parser/parse_expr.c

+37-19
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.74 2000/03/17 05:29:05 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.75 2000/03/19 07:13:58 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -61,10 +61,27 @@ parse_expr_init(void)
6161

6262
/*
6363
* transformExpr -
64-
* analyze and transform expressions. Type checking and type casting is
64+
* Analyze and transform expressions. Type checking and type casting is
6565
* done here. The optimizer and the executor cannot handle the original
6666
* (raw) expressions collected by the parse tree. Hence the transformation
6767
* here.
68+
*
69+
* NOTE: there are various cases in which this routine will get applied to
70+
* an already-transformed expression. Some examples:
71+
* 1. At least one construct (BETWEEN/AND) puts the same nodes
72+
* into two branches of the parse tree; hence, some nodes
73+
* are transformed twice.
74+
* 2. Another way it can happen is that coercion of an operator or
75+
* function argument to the required type (via coerce_type())
76+
* can apply transformExpr to an already-transformed subexpression.
77+
* An example here is "SELECT count(*) + 1.0 FROM table".
78+
* While it might be possible to eliminate these cases, the path of
79+
* least resistance so far has been to ensure that transformExpr() does
80+
* no damage if applied to an already-transformed tree. This is pretty
81+
* easy for cases where the transformation replaces one node type with
82+
* another, such as A_Const => Const; we just do nothing when handed
83+
* a Const. More care is needed for node types that are used as both
84+
* input and output of transformExpr; see SubLink for example.
6885
*/
6986
Node *
7087
transformExpr(ParseState *pstate, Node *expr, int precedence)
@@ -254,6 +271,12 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
254271
List *qtrees;
255272
Query *qtree;
256273

274+
/* If we already transformed this node, do nothing */
275+
if (IsA(sublink->subselect, Query))
276+
{
277+
result = expr;
278+
break;
279+
}
257280
pstate->p_hasSubLinks = true;
258281
qtrees = parse_analyze(lcons(sublink->subselect, NIL), pstate);
259282
if (length(qtrees) != 1)
@@ -390,7 +413,9 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
390413
/*
391414
* It's not shorthand anymore, so drop the implicit
392415
* argument. This is necessary to keep the executor from
393-
* seeing an untransformed expression...
416+
* seeing an untransformed expression... not to mention
417+
* keeping a re-application of transformExpr from doing
418+
* the wrong thing.
394419
*/
395420
c->arg = NULL;
396421

@@ -528,22 +553,14 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
528553
break;
529554
}
530555

531-
/* Some nodes do _not_ come from the original parse tree,
532-
* but result from parser transformation in this phase.
533-
* At least one construct (BETWEEN/AND) puts the same nodes
534-
* into two branches of the parse tree; hence, some nodes
535-
* are transformed twice.
536-
* Another way it can happen is that coercion of an operator or
537-
* function argument to the required type (via coerce_type())
538-
* can apply transformExpr to an already-transformed subexpression.
539-
* An example here is "SELECT count(*) + 1.0 FROM table".
540-
* Thus, we can see node types in this routine that do not appear in the
541-
* original parse tree. Assume they are already transformed, and just
542-
* pass them through.
543-
* Do any other node types need to be accepted? For now we are taking
544-
* a conservative approach, and only accepting node types that are
545-
* demonstrably necessary to accept.
546-
*/
556+
/*
557+
* Quietly accept node types that may be presented when we are called
558+
* on an already-transformed tree.
559+
*
560+
* Do any other node types need to be accepted? For now we are taking
561+
* a conservative approach, and only accepting node types that are
562+
* demonstrably necessary to accept.
563+
*/
547564
case T_Expr:
548565
case T_Var:
549566
case T_Const:
@@ -555,6 +572,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
555572
result = (Node *) expr;
556573
break;
557574
}
575+
558576
default:
559577
/* should not reach here */
560578
elog(ERROR, "transformExpr: does not know how to transform node %d"

0 commit comments

Comments
 (0)