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

Commit d5096af

Browse files
committed
Make the world safe for passing whole rows of views to functions. This
already worked fine for whole rows of tables, but not so well for views...
1 parent e4c06b2 commit d5096af

File tree

7 files changed

+161
-44
lines changed

7 files changed

+161
-44
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.103 2001/04/01 22:37:19 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.104 2001/04/18 20:42:55 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -271,8 +271,12 @@ pull_up_subqueries(Query *parse, Node *jtnode)
271271
/*
272272
* Is this a subquery RTE, and if so, is the subquery simple
273273
* enough to pull up? (If not, do nothing at this node.)
274+
*
275+
* Note: even if the subquery itself is simple enough, we can't
276+
* pull it up if there is a reference to its whole tuple result.
274277
*/
275-
if (subquery && is_simple_subquery(subquery))
278+
if (subquery && is_simple_subquery(subquery) &&
279+
!contain_whole_tuple_var((Node *) parse, varno, 0))
276280
{
277281
int rtoffset;
278282
Node *subjointree;

src/backend/optimizer/util/var.c

Lines changed: 109 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.30 2001/03/22 03:59:40 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.31 2001/04/18 20:42:55 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
15-
#include <sys/types.h>
16-
1715
#include "postgres.h"
1816

1917
#include "nodes/plannodes.h"
@@ -27,6 +25,12 @@ typedef struct
2725
int sublevels_up;
2826
} pull_varnos_context;
2927

28+
typedef struct
29+
{
30+
int varno;
31+
int sublevels_up;
32+
} contain_whole_tuple_var_context;
33+
3034
typedef struct
3135
{
3236
List *varlist;
@@ -35,6 +39,8 @@ typedef struct
3539

3640
static bool pull_varnos_walker(Node *node,
3741
pull_varnos_context *context);
42+
static bool contain_whole_tuple_var_walker(Node *node,
43+
contain_whole_tuple_var_context *context);
3844
static bool contain_var_clause_walker(Node *node, void *context);
3945
static bool pull_var_clause_walker(Node *node,
4046
pull_var_clause_context *context);
@@ -46,11 +52,10 @@ static bool pull_var_clause_walker(Node *node,
4652
* Create a list of all the distinct varnos present in a parsetree.
4753
* Only varnos that reference level-zero rtable entries are considered.
4854
*
49-
* NOTE: unlike other routines in this file, pull_varnos() is used on
50-
* not-yet-planned expressions. It may therefore find bare SubLinks,
51-
* and if so it needs to recurse into them to look for uplevel references
52-
* to the desired rtable level! But when we find a completed SubPlan,
53-
* we only need to look at the parameters passed to the subplan.
55+
* NOTE: this is used on not-yet-planned expressions. It may therefore find
56+
* bare SubLinks, and if so it needs to recurse into them to look for uplevel
57+
* references to the desired rtable level! But when we find a completed
58+
* SubPlan, we only need to look at the parameters passed to the subplan.
5459
*/
5560
List *
5661
pull_varnos(Node *node)
@@ -122,17 +127,105 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
122127
(void *) context);
123128
}
124129

130+
131+
/*
132+
* contain_whole_tuple_var
133+
*
134+
* Detect whether a parsetree contains any references to the whole
135+
* tuple of a given rtable entry (ie, a Var with varattno = 0).
136+
*
137+
* NOTE: this is used on not-yet-planned expressions. It may therefore find
138+
* bare SubLinks, and if so it needs to recurse into them to look for uplevel
139+
* references to the desired rtable entry! But when we find a completed
140+
* SubPlan, we only need to look at the parameters passed to the subplan.
141+
*/
142+
bool
143+
contain_whole_tuple_var(Node *node, int varno, int levelsup)
144+
{
145+
contain_whole_tuple_var_context context;
146+
147+
context.varno = varno;
148+
context.sublevels_up = levelsup;
149+
150+
/*
151+
* Must be prepared to start with a Query or a bare expression tree;
152+
* if it's a Query, go straight to query_tree_walker to make sure that
153+
* sublevels_up doesn't get incremented prematurely.
154+
*/
155+
if (node && IsA(node, Query))
156+
return query_tree_walker((Query *) node,
157+
contain_whole_tuple_var_walker,
158+
(void *) &context, true);
159+
else
160+
return contain_whole_tuple_var_walker(node, &context);
161+
}
162+
163+
static bool
164+
contain_whole_tuple_var_walker(Node *node,
165+
contain_whole_tuple_var_context *context)
166+
{
167+
if (node == NULL)
168+
return false;
169+
if (IsA(node, Var))
170+
{
171+
Var *var = (Var *) node;
172+
173+
if (var->varno == context->varno &&
174+
var->varlevelsup == context->sublevels_up &&
175+
var->varattno == InvalidAttrNumber)
176+
return true;
177+
return false;
178+
}
179+
if (is_subplan(node))
180+
{
181+
182+
/*
183+
* Already-planned subquery. Examine the args list (parameters to
184+
* be passed to subquery), as well as the "oper" list which is
185+
* executed by the outer query. But short-circuit recursion into
186+
* the subquery itself, which would be a waste of effort.
187+
*/
188+
Expr *expr = (Expr *) node;
189+
190+
if (contain_whole_tuple_var_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper,
191+
context))
192+
return true;
193+
if (contain_whole_tuple_var_walker((Node *) expr->args,
194+
context))
195+
return true;
196+
return false;
197+
}
198+
if (IsA(node, Query))
199+
{
200+
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
201+
bool result;
202+
203+
context->sublevels_up++;
204+
result = query_tree_walker((Query *) node,
205+
contain_whole_tuple_var_walker,
206+
(void *) context, true);
207+
context->sublevels_up--;
208+
return result;
209+
}
210+
return expression_tree_walker(node, contain_whole_tuple_var_walker,
211+
(void *) context);
212+
}
213+
214+
125215
/*
126216
* contain_var_clause
127217
* Recursively scan a clause to discover whether it contains any Var nodes
128218
* (of the current query level).
129219
*
130220
* Returns true if any varnode found.
221+
*
222+
* Does not examine subqueries, therefore must only be used after reduction
223+
* of sublinks to subplans!
131224
*/
132225
bool
133-
contain_var_clause(Node *clause)
226+
contain_var_clause(Node *node)
134227
{
135-
return contain_var_clause_walker(clause, NULL);
228+
return contain_var_clause_walker(node, NULL);
136229
}
137230

138231
static bool
@@ -150,6 +243,7 @@ contain_var_clause_walker(Node *node, void *context)
150243
return expression_tree_walker(node, contain_var_clause_walker, context);
151244
}
152245

246+
153247
/*
154248
* pull_var_clause
155249
* Recursively pulls all var nodes from an expression clause.
@@ -160,16 +254,19 @@ contain_var_clause_walker(Node *node, void *context)
160254
*
161255
* Returns list of varnodes found. Note the varnodes themselves are not
162256
* copied, only referenced.
257+
*
258+
* Does not examine subqueries, therefore must only be used after reduction
259+
* of sublinks to subplans!
163260
*/
164261
List *
165-
pull_var_clause(Node *clause, bool includeUpperVars)
262+
pull_var_clause(Node *node, bool includeUpperVars)
166263
{
167264
pull_var_clause_context context;
168265

169266
context.varlist = NIL;
170267
context.includeUpperVars = includeUpperVars;
171268

172-
pull_var_clause_walker(clause, &context);
269+
pull_var_clause_walker(node, &context);
173270
return context.varlist;
174271
}
175272

src/backend/rewrite/rewriteManip.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.56 2001/03/22 03:59:44 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.57 2001/04/18 20:42:55 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -765,8 +765,13 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
765765
if (this_varno == context->target_varno &&
766766
this_varlevelsup == context->sublevels_up)
767767
{
768-
Node *n = FindMatchingNew(context->targetlist,
769-
var->varattno);
768+
Node *n;
769+
770+
/* band-aid: don't do the wrong thing with a whole-tuple Var */
771+
if (var->varattno == InvalidAttrNumber)
772+
elog(ERROR, "ResolveNew: can't handle whole-tuple reference");
773+
774+
n = FindMatchingNew(context->targetlist, var->varattno);
770775

771776
if (n == NULL)
772777
{

src/include/optimizer/var.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: var.h,v 1.12 2001/01/24 19:43:26 momjian Exp $
10+
* $Id: var.h,v 1.13 2001/04/18 20:42:55 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -16,8 +16,9 @@
1616

1717
#include "nodes/primnodes.h"
1818

19-
extern List *pull_varnos(Node *me);
20-
extern bool contain_var_clause(Node *clause);
21-
extern List *pull_var_clause(Node *clause, bool includeUpperVars);
19+
extern List *pull_varnos(Node *node);
20+
extern bool contain_whole_tuple_var(Node *node, int varno, int levelsup);
21+
extern bool contain_var_clause(Node *node);
22+
extern List *pull_var_clause(Node *node, bool includeUpperVars);
2223

2324
#endif /* VAR_H */

src/pl/plpgsql/src/gram.y

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* procedural language
55
*
66
* IDENTIFICATION
7-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.16 2001/02/19 19:49:53 tgl Exp $
7+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.17 2001/04/18 20:42:56 tgl Exp $
88
*
99
* This software is copyrighted by Jan Wieck - Hamburg.
1010
*
@@ -885,7 +885,7 @@ fori_lower :
885885
}
886886
}
887887

888-
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
888+
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
889889
expr->dtype = PLPGSQL_DTYPE_EXPR;
890890
expr->query = strdup(plpgsql_dstring_get(&ds));
891891
expr->plan = NULL;
@@ -1272,7 +1272,7 @@ read_sqlstmt (int until, char *s, char *sqlstart)
12721272
}
12731273
}
12741274

1275-
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
1275+
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
12761276
expr->dtype = PLPGSQL_DTYPE_EXPR;
12771277
expr->query = strdup(plpgsql_dstring_get(&ds));
12781278
expr->plan = NULL;
@@ -1310,7 +1310,7 @@ make_select_stmt()
13101310
{
13111311
PLpgSQL_stmt_execsql *execsql;
13121312

1313-
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
1313+
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
13141314
expr->dtype = PLPGSQL_DTYPE_EXPR;
13151315
expr->query = strdup(plpgsql_dstring_get(&ds));
13161316
expr->plan = NULL;
@@ -1449,14 +1449,13 @@ make_select_stmt()
14491449
{
14501450
PLpgSQL_stmt_execsql *execsql;
14511451

1452-
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
1452+
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
14531453
expr->dtype = PLPGSQL_DTYPE_EXPR;
14541454
expr->query = strdup(plpgsql_dstring_get(&ds));
14551455
expr->plan = NULL;
14561456
expr->nparams = nparams;
1457-
while(nparams-- > 0) {
1457+
while (nparams-- > 0)
14581458
expr->params[nparams] = params[nparams];
1459-
}
14601459
plpgsql_dstring_free(&ds);
14611460

14621461
execsql = malloc(sizeof(PLpgSQL_stmt_execsql));
@@ -1549,7 +1548,7 @@ make_select_stmt()
15491548
}
15501549
}
15511550

1552-
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (nparams - 1));
1551+
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
15531552
expr->dtype = PLPGSQL_DTYPE_EXPR;
15541553
expr->query = strdup(plpgsql_dstring_get(&ds));
15551554
expr->plan = NULL;

0 commit comments

Comments
 (0)