Commit d5096af2 authored by Tom Lane's avatar Tom Lane

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...
parent e4c06b21
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.103 2001/04/01 22:37:19 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.104 2001/04/18 20:42:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -271,8 +271,12 @@ pull_up_subqueries(Query *parse, Node *jtnode)
/*
* Is this a subquery RTE, and if so, is the subquery simple
* enough to pull up? (If not, do nothing at this node.)
*
* Note: even if the subquery itself is simple enough, we can't
* pull it up if there is a reference to its whole tuple result.
*/
if (subquery && is_simple_subquery(subquery))
if (subquery && is_simple_subquery(subquery) &&
!contain_whole_tuple_var((Node *) parse, varno, 0))
{
int rtoffset;
Node *subjointree;
......
......@@ -8,12 +8,10 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.30 2001/03/22 03:59:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.31 2001/04/18 20:42:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/types.h>
#include "postgres.h"
#include "nodes/plannodes.h"
......@@ -27,6 +25,12 @@ typedef struct
int sublevels_up;
} pull_varnos_context;
typedef struct
{
int varno;
int sublevels_up;
} contain_whole_tuple_var_context;
typedef struct
{
List *varlist;
......@@ -35,6 +39,8 @@ typedef struct
static bool pull_varnos_walker(Node *node,
pull_varnos_context *context);
static bool contain_whole_tuple_var_walker(Node *node,
contain_whole_tuple_var_context *context);
static bool contain_var_clause_walker(Node *node, void *context);
static bool pull_var_clause_walker(Node *node,
pull_var_clause_context *context);
......@@ -46,11 +52,10 @@ static bool pull_var_clause_walker(Node *node,
* Create a list of all the distinct varnos present in a parsetree.
* Only varnos that reference level-zero rtable entries are considered.
*
* NOTE: unlike other routines in this file, pull_varnos() is used on
* not-yet-planned expressions. It may therefore find bare SubLinks,
* and if so it needs to recurse into them to look for uplevel references
* to the desired rtable level! But when we find a completed SubPlan,
* we only need to look at the parameters passed to the subplan.
* NOTE: this is used on not-yet-planned expressions. It may therefore find
* bare SubLinks, and if so it needs to recurse into them to look for uplevel
* references to the desired rtable level! But when we find a completed
* SubPlan, we only need to look at the parameters passed to the subplan.
*/
List *
pull_varnos(Node *node)
......@@ -122,17 +127,105 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
(void *) context);
}
/*
* contain_whole_tuple_var
*
* Detect whether a parsetree contains any references to the whole
* tuple of a given rtable entry (ie, a Var with varattno = 0).
*
* NOTE: this is used on not-yet-planned expressions. It may therefore find
* bare SubLinks, and if so it needs to recurse into them to look for uplevel
* references to the desired rtable entry! But when we find a completed
* SubPlan, we only need to look at the parameters passed to the subplan.
*/
bool
contain_whole_tuple_var(Node *node, int varno, int levelsup)
{
contain_whole_tuple_var_context context;
context.varno = varno;
context.sublevels_up = levelsup;
/*
* Must be prepared to start with a Query or a bare expression tree;
* if it's a Query, go straight to query_tree_walker to make sure that
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
return query_tree_walker((Query *) node,
contain_whole_tuple_var_walker,
(void *) &context, true);
else
return contain_whole_tuple_var_walker(node, &context);
}
static bool
contain_whole_tuple_var_walker(Node *node,
contain_whole_tuple_var_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varno == context->varno &&
var->varlevelsup == context->sublevels_up &&
var->varattno == InvalidAttrNumber)
return true;
return false;
}
if (is_subplan(node))
{
/*
* Already-planned subquery. Examine the args list (parameters to
* be passed to subquery), as well as the "oper" list which is
* executed by the outer query. But short-circuit recursion into
* the subquery itself, which would be a waste of effort.
*/
Expr *expr = (Expr *) node;
if (contain_whole_tuple_var_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper,
context))
return true;
if (contain_whole_tuple_var_walker((Node *) expr->args,
context))
return true;
return false;
}
if (IsA(node, Query))
{
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node,
contain_whole_tuple_var_walker,
(void *) context, true);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, contain_whole_tuple_var_walker,
(void *) context);
}
/*
* contain_var_clause
* Recursively scan a clause to discover whether it contains any Var nodes
* (of the current query level).
*
* Returns true if any varnode found.
*
* Does not examine subqueries, therefore must only be used after reduction
* of sublinks to subplans!
*/
bool
contain_var_clause(Node *clause)
contain_var_clause(Node *node)
{
return contain_var_clause_walker(clause, NULL);
return contain_var_clause_walker(node, NULL);
}
static bool
......@@ -150,6 +243,7 @@ contain_var_clause_walker(Node *node, void *context)
return expression_tree_walker(node, contain_var_clause_walker, context);
}
/*
* pull_var_clause
* Recursively pulls all var nodes from an expression clause.
......@@ -160,16 +254,19 @@ contain_var_clause_walker(Node *node, void *context)
*
* Returns list of varnodes found. Note the varnodes themselves are not
* copied, only referenced.
*
* Does not examine subqueries, therefore must only be used after reduction
* of sublinks to subplans!
*/
List *
pull_var_clause(Node *clause, bool includeUpperVars)
pull_var_clause(Node *node, bool includeUpperVars)
{
pull_var_clause_context context;
context.varlist = NIL;
context.includeUpperVars = includeUpperVars;
pull_var_clause_walker(clause, &context);
pull_var_clause_walker(node, &context);
return context.varlist;
}
......
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.56 2001/03/22 03:59:44 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.57 2001/04/18 20:42:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -765,8 +765,13 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
if (this_varno == context->target_varno &&
this_varlevelsup == context->sublevels_up)
{
Node *n = FindMatchingNew(context->targetlist,
var->varattno);
Node *n;
/* band-aid: don't do the wrong thing with a whole-tuple Var */
if (var->varattno == InvalidAttrNumber)
elog(ERROR, "ResolveNew: can't handle whole-tuple reference");
n = FindMatchingNew(context->targetlist, var->varattno);
if (n == NULL)
{
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: var.h,v 1.12 2001/01/24 19:43:26 momjian Exp $
* $Id: var.h,v 1.13 2001/04/18 20:42:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,8 +16,9 @@
#include "nodes/primnodes.h"
extern List *pull_varnos(Node *me);
extern bool contain_var_clause(Node *clause);
extern List *pull_var_clause(Node *clause, bool includeUpperVars);
extern List *pull_varnos(Node *node);
extern bool contain_whole_tuple_var(Node *node, int varno, int levelsup);
extern bool contain_var_clause(Node *node);
extern List *pull_var_clause(Node *node, bool includeUpperVars);
#endif /* VAR_H */
......@@ -4,7 +4,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.16 2001/02/19 19:49:53 tgl Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.17 2001/04/18 20:42:56 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -885,7 +885,7 @@ fori_lower :
}
}
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
......@@ -1272,7 +1272,7 @@ read_sqlstmt (int until, char *s, char *sqlstart)
}
}
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
......@@ -1310,7 +1310,7 @@ make_select_stmt()
{
PLpgSQL_stmt_execsql *execsql;
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
......@@ -1449,14 +1449,13 @@ make_select_stmt()
{
PLpgSQL_stmt_execsql *execsql;
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
expr->nparams = nparams;
while(nparams-- > 0) {
while (nparams-- > 0)
expr->params[nparams] = params[nparams];
}
plpgsql_dstring_free(&ds);
execsql = malloc(sizeof(PLpgSQL_stmt_execsql));
......@@ -1549,7 +1548,7 @@ make_select_stmt()
}
}
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (nparams - 1));
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
......
......@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.29 2001/04/06 02:06:48 tgl Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.30 2001/04/18 20:42:56 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -552,7 +552,7 @@ plpgsql_parse_word(char *word)
*/
if (plpgsql_curr_compile->fn_functype == T_TRIGGER)
{
if (!strcmp(cp, "tg_argv"))
if (strcmp(cp, "tg_argv") == 0)
{
int save_spacescanned = plpgsql_SpaceScanned;
PLpgSQL_trigarg *trigarg;
......@@ -751,7 +751,7 @@ plpgsql_parse_dblword(char *string)
row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
for (i = 0; i < row->nfields; i++)
{
if (!strcmp(row->fieldnames[i], word2))
if (strcmp(row->fieldnames[i], word2) == 0)
{
plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]);
pfree(word1);
......@@ -855,7 +855,7 @@ plpgsql_parse_tripword(char *string)
row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
for (i = 0; i < row->nfields; i++)
{
if (!strcmp(row->fieldnames[i], word3))
if (strcmp(row->fieldnames[i], word3) == 0)
{
plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]);
pfree(word1);
......@@ -1139,14 +1139,17 @@ plpgsql_parse_wordrowtype(char *string)
elog(ERROR, "%s: no such class", word1);
}
classStruct = (Form_pg_class) GETSTRUCT(classtup);
if (classStruct->relkind != 'r' && classStruct->relkind != 's')
/* accept relation, sequence, or view pg_class entries */
if (classStruct->relkind != 'r' &&
classStruct->relkind != 's' &&
classStruct->relkind != 'v')
{
plpgsql_comperrinfo();
elog(ERROR, "%s isn't a table", word1);
}
/*
* Fetch the tables pg_type tuple too
* Fetch the table's pg_type tuple too
*/
typetup = SearchSysCache(TYPENAME,
PointerGetDatum(word1),
......@@ -1205,15 +1208,17 @@ plpgsql_parse_wordrowtype(char *string)
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
/*
* Create the internal variable We know if the table definitions
* contain a default value or if the field is declared in the
* table as NOT NULL. But it's possible to create a table field as
* NOT NULL without a default value and that would lead to
* problems later when initializing the variables due to entering
* a block at execution time. Thus we ignore this information for
* now.
* Create the internal variable
*
* We know if the table definitions contain a default value or if the
* field is declared in the table as NOT NULL. But it's possible to
* create a table field as NOT NULL without a default value and that
* would lead to problems later when initializing the variables due to
* entering a block at execution time. Thus we ignore this information
* for now.
*/
var = malloc(sizeof(PLpgSQL_var));
memset(var, 0, sizeof(PLpgSQL_var));
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = malloc(strlen(word1) + strlen(cp) + 2);
strcpy(var->refname, word1);
......@@ -1241,7 +1246,7 @@ plpgsql_parse_wordrowtype(char *string)
/*
* Add the variable to the row.
*/
row->fieldnames[i] = cp;
row->fieldnames[i] = strdup(cp);
row->varnos[i] = var->varno;
}
......
......@@ -4,7 +4,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.9 2001/02/19 19:49:53 tgl Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.10 2001/04/18 20:42:56 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -145,6 +145,12 @@ dump { return O_DUMP; }
{WS}{WC}*%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
\$[0-9]+ { return plpgsql_parse_word(yytext); }
\$[0-9]+\.{WS}{WC}* { return plpgsql_parse_dblword(yytext); }
\$[0-9]+\.{WS}{WC}*\.{WS}{WC}* { return plpgsql_parse_tripword(yytext); }
\$[0-9]+%TYPE { return plpgsql_parse_wordtype(yytext); }
\$[0-9]+\.{WS}{WC}*%TYPE { return plpgsql_parse_dblwordtype(yytext); }
\$[0-9]+%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
[0-9]+ { return T_NUMBER; }
/* ----------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment