Commit 95860015 authored by Tom Lane's avatar Tom Lane

Fix several problems in rule deparsing: didn't handle array

references or CASE expressions, didn't parenthesize complex expressions
properly.  Also, always output variable references as fully qualified
names to eliminate ambiguity bug recently reported.  (This could be
smarter, but reliability comes first.)
parent 37d20eb8
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* out of it's tuple * out of it's tuple
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.23 1999/08/25 23:21:35 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.24 1999/08/28 03:59:05 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -58,6 +58,11 @@ typedef struct QryHier ...@@ -58,6 +58,11 @@ typedef struct QryHier
Query *query; Query *query;
} QryHier; } QryHier;
typedef struct {
Index rt_index;
int levelsup;
} check_if_rte_used_context;
/* ---------- /* ----------
* Global data * Global data
...@@ -95,6 +100,7 @@ static char *get_select_query_def(Query *query, QryHier *qh); ...@@ -95,6 +100,7 @@ static char *get_select_query_def(Query *query, QryHier *qh);
static char *get_insert_query_def(Query *query, QryHier *qh); static char *get_insert_query_def(Query *query, QryHier *qh);
static char *get_update_query_def(Query *query, QryHier *qh); static char *get_update_query_def(Query *query, QryHier *qh);
static char *get_delete_query_def(Query *query, QryHier *qh); static char *get_delete_query_def(Query *query, QryHier *qh);
static RangeTblEntry *get_rte_for_var(Var *var, QryHier *qh);
static char *get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix); static char *get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix);
static char *get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix); static char *get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix);
static char *get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix); static char *get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix);
...@@ -102,7 +108,9 @@ static char *get_const_expr(Const *constval); ...@@ -102,7 +108,9 @@ static char *get_const_expr(Const *constval);
static char *get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix); static char *get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix);
static char *get_relation_name(Oid relid); static char *get_relation_name(Oid relid);
static char *get_attribute_name(Oid relid, int2 attnum); static char *get_attribute_name(Oid relid, int2 attnum);
static bool check_if_rte_used(int rt_index, Node *node, int sup); static bool check_if_rte_used(Node *node, Index rt_index, int levelsup);
static bool check_if_rte_used_walker(Node *node,
check_if_rte_used_context *context);
/* ---------- /* ----------
...@@ -853,7 +861,7 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -853,7 +861,7 @@ get_select_query_def(Query *query, QryHier *qh)
List *l; List *l;
/* ---------- /* ----------
* First we need need to know which and how many of the * First we need to know which and how many of the
* range table entries in the query are used in the target list * range table entries in the query are used in the target list
* or queries qualification * or queries qualification
* ---------- * ----------
...@@ -862,21 +870,15 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -862,21 +870,15 @@ get_select_query_def(Query *query, QryHier *qh)
rt_used = palloc(sizeof(bool) * rt_length); rt_used = palloc(sizeof(bool) * rt_length);
for (i = 0; i < rt_length; i++) for (i = 0; i < rt_length; i++)
{ {
if (check_if_rte_used(i + 1, (Node *) (query->targetList), 0)) if (check_if_rte_used((Node *) (query->targetList), i + 1, 0) ||
check_if_rte_used(query->qual, i + 1, 0) ||
check_if_rte_used(query->havingQual, i + 1, 0))
{ {
rt_used[i] = TRUE; rt_used[i] = TRUE;
rt_numused++; rt_numused++;
} }
else else
{ rt_used[i] = FALSE;
if (check_if_rte_used(i + 1, (Node *) (query->qual), 0))
{
rt_used[i] = TRUE;
rt_numused++;
}
else
rt_used[i] = FALSE;
}
} }
/* ---------- /* ----------
...@@ -920,14 +922,14 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -920,14 +922,14 @@ get_select_query_def(Query *query, QryHier *qh)
strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1))); strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1)));
/* Check if we must say AS ... */ /* Check if we must say AS ... */
if (nodeTag(tle->expr) != T_Var) if (! IsA(tle->expr, Var))
tell_as = strcmp(tle->resdom->resname, "?column?"); tell_as = strcmp(tle->resdom->resname, "?column?");
else else
{ {
Var *var = (Var *) (tle->expr); Var *var = (Var *) (tle->expr);
char *attname; char *attname;
rte = (RangeTblEntry *) nth(var->varno - 1, query->rtable); rte = get_rte_for_var(var, qh);
attname = get_attribute_name(rte->relid, var->varattno); attname = get_attribute_name(rte->relid, var->varattno);
if (strcmp(attname, tle->resdom->resname)) if (strcmp(attname, tle->resdom->resname))
tell_as = TRUE; tell_as = TRUE;
...@@ -990,9 +992,14 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -990,9 +992,14 @@ get_select_query_def(Query *query, QryHier *qh)
sep = ""; sep = "";
foreach(l, query->groupClause) foreach(l, query->groupClause)
{ {
GroupClause *grp = (GroupClause *) lfirst(l);
Node *groupexpr;
groupexpr = get_sortgroupclause_expr(grp,
query->targetList);
strcat(buf, sep); strcat(buf, sep);
strcat(buf, get_rule_expr(qh, 0, groupexpr, (rt_numused > 1)));
sep = ", "; sep = ", ";
strcat(buf, get_rule_expr(qh, 0, lfirst(l), (rt_numused > 1)));
} }
} }
...@@ -1032,21 +1039,15 @@ get_insert_query_def(Query *query, QryHier *qh) ...@@ -1032,21 +1039,15 @@ get_insert_query_def(Query *query, QryHier *qh)
rt_used = palloc(sizeof(bool) * rt_length); rt_used = palloc(sizeof(bool) * rt_length);
for (i = 0; i < rt_length; i++) for (i = 0; i < rt_length; i++)
{ {
if (check_if_rte_used(i + 1, (Node *) (query->targetList), 0)) if (check_if_rte_used((Node *) (query->targetList), i + 1, 0) ||
check_if_rte_used(query->qual, i + 1, 0) ||
check_if_rte_used(query->havingQual, i + 1, 0))
{ {
rt_used[i] = TRUE; rt_used[i] = TRUE;
rt_numused++; rt_numused++;
} }
else else
{ rt_used[i] = FALSE;
if (check_if_rte_used(i + 1, (Node *) (query->qual), 0))
{
rt_used[i] = TRUE;
rt_numused++;
}
else
rt_used[i] = FALSE;
}
} }
i = 0; i = 0;
...@@ -1200,6 +1201,20 @@ get_delete_query_def(Query *query, QryHier *qh) ...@@ -1200,6 +1201,20 @@ get_delete_query_def(Query *query, QryHier *qh)
return pstrdup(buf); return pstrdup(buf);
} }
/*
* Find the RTE referenced by a (possibly nonlocal) Var.
*/
static RangeTblEntry *
get_rte_for_var(Var *var, QryHier *qh)
{
int sup = var->varlevelsup;
while (sup-- > 0)
qh = qh->parent;
return (RangeTblEntry *) nth(var->varno - 1, qh->query->rtable);
}
/* ---------- /* ----------
* get_rule_expr - Parse back an expression * get_rule_expr - Parse back an expression
...@@ -1216,44 +1231,39 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1216,44 +1231,39 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
buf[0] = '\0'; buf[0] = '\0';
/* ---------- /* ----------
* Up to now I don't know if all the node types below * Each level of get_rule_expr must return an indivisible term
* can really occur in rules actions and qualifications. * (parenthesized if necessary) to ensure result is reparsed into
* There might be some work left. * the same expression tree.
*
* There might be some work left here to support additional node types...
* ---------- * ----------
*/ */
switch (nodeTag(node)) switch (nodeTag(node))
{ {
case T_TargetEntry: case T_Const:
{ return get_const_expr((Const *) node);
TargetEntry *tle = (TargetEntry *) node;
return get_rule_expr(qh, rt_index,
(Node *) (tle->expr), varprefix);
}
break; break;
case T_Aggref: case T_Var:
{ {
Aggref *aggref = (Aggref *) node; Var *var = (Var *) node;
RangeTblEntry *rte = get_rte_for_var(var, qh);
if (!strcmp(rte->refname, "*NEW*"))
strcat(buf, "new.");
else if (!strcmp(rte->refname, "*CURRENT*"))
strcat(buf, "old.");
else
{
strcat(buf, "\"");
strcat(buf, rte->refname);
strcat(buf, "\".");
}
strcat(buf, "\"");
strcat(buf, get_attribute_name(rte->relid, var->varattno));
strcat(buf, "\""); strcat(buf, "\"");
strcat(buf, aggref->aggname);
strcat(buf, "\"(");
strcat(buf, get_rule_expr(qh, rt_index,
(Node *) (aggref->target), varprefix));
strcat(buf, ")");
return pstrdup(buf);
}
break;
case T_GroupClause:
{
GroupClause *grp = (GroupClause *) node;
Node *groupexpr;
groupexpr = get_sortgroupclause_expr(grp, return pstrdup(buf);
qh->query->targetList);
return get_rule_expr(qh, rt_index, groupexpr, varprefix);
} }
break; break;
...@@ -1268,6 +1278,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1268,6 +1278,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
switch (expr->opType) switch (expr->opType)
{ {
case OP_EXPR: case OP_EXPR:
strcat(buf, "(");
strcat(buf, get_rule_expr(qh, rt_index, strcat(buf, get_rule_expr(qh, rt_index,
(Node *) get_leftop(expr), (Node *) get_leftop(expr),
varprefix)); varprefix));
...@@ -1277,6 +1288,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1277,6 +1288,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
strcat(buf, get_rule_expr(qh, rt_index, strcat(buf, get_rule_expr(qh, rt_index,
(Node *) get_rightop(expr), (Node *) get_rightop(expr),
varprefix)); varprefix));
strcat(buf, ")");
return pstrdup(buf); return pstrdup(buf);
break; break;
...@@ -1285,7 +1297,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1285,7 +1297,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
strcat(buf, get_rule_expr(qh, rt_index, strcat(buf, get_rule_expr(qh, rt_index,
(Node *) get_leftop(expr), (Node *) get_leftop(expr),
varprefix)); varprefix));
strcat(buf, ") OR ("); strcat(buf, " OR ");
strcat(buf, get_rule_expr(qh, rt_index, strcat(buf, get_rule_expr(qh, rt_index,
(Node *) get_rightop(expr), (Node *) get_rightop(expr),
varprefix)); varprefix));
...@@ -1298,7 +1310,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1298,7 +1310,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
strcat(buf, get_rule_expr(qh, rt_index, strcat(buf, get_rule_expr(qh, rt_index,
(Node *) get_leftop(expr), (Node *) get_leftop(expr),
varprefix)); varprefix));
strcat(buf, ") AND ("); strcat(buf, " AND ");
strcat(buf, get_rule_expr(qh, rt_index, strcat(buf, get_rule_expr(qh, rt_index,
(Node *) get_rightop(expr), (Node *) get_rightop(expr),
varprefix)); varprefix));
...@@ -1307,7 +1319,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1307,7 +1319,7 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
break; break;
case NOT_EXPR: case NOT_EXPR:
strcat(buf, "NOT ("); strcat(buf, "(NOT ");
strcat(buf, get_rule_expr(qh, rt_index, strcat(buf, get_rule_expr(qh, rt_index,
(Node *) get_leftop(expr), (Node *) get_leftop(expr),
varprefix)); varprefix));
...@@ -1323,50 +1335,77 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1323,50 +1335,77 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
default: default:
printf("\n%s\n", nodeToString(node)); printf("\n%s\n", nodeToString(node));
elog(ERROR, "Expr not yet supported"); elog(ERROR, "Expr type not supported");
} }
} }
break; break;
case T_Var: case T_Aggref:
{ {
Var *var = (Var *) node; Aggref *aggref = (Aggref *) node;
RangeTblEntry *rte;
int sup = var->varlevelsup;
while (sup-- > 0) strcat(buf, "\"");
qh = qh->parent; strcat(buf, aggref->aggname);
strcat(buf, "\"(");
strcat(buf, get_rule_expr(qh, rt_index,
(Node *) (aggref->target), varprefix));
strcat(buf, ")");
return pstrdup(buf);
}
break;
rte = (RangeTblEntry *) nth(var->varno - 1, qh->query->rtable); case T_ArrayRef:
{
ArrayRef *aref = (ArrayRef *) node;
List *lowlist;
List *uplist;
if (!strcmp(rte->refname, "*NEW*")) strcat(buf, get_rule_expr(qh, rt_index,
strcat(buf, "new."); aref->refexpr, varprefix));
else lowlist = aref->reflowerindexpr;
foreach(uplist, aref->refupperindexpr)
{ {
if (!strcmp(rte->refname, "*CURRENT*")) strcat(buf, "[");
strcat(buf, "old."); if (lowlist)
else
{ {
if (strcmp(rte->relname, rte->refname) != 0) strcat(buf, get_rule_expr(qh, rt_index,
{ (Node *) lfirst(lowlist),
strcat(buf, "\""); varprefix));
strcat(buf, rte->refname); strcat(buf, ":");
strcat(buf, "\"."); lowlist = lnext(lowlist);
}
} }
strcat(buf, get_rule_expr(qh, rt_index,
(Node *) lfirst(uplist),
varprefix));
strcat(buf, "]");
} }
strcat(buf, "\""); /* XXX need to do anything with refassgnexpr? */
strcat(buf, get_attribute_name(rte->relid, var->varattno));
strcat(buf, "\"");
return pstrdup(buf); return pstrdup(buf);
} }
break; break;
case T_List: case T_CaseExpr:
{ {
printf("\n%s\n", nodeToString(node)); CaseExpr *caseexpr = (CaseExpr *) node;
elog(ERROR, "List not yet supported"); List *temp;
strcat(buf, "CASE");
foreach(temp, caseexpr->args)
{
CaseWhen *when = (CaseWhen *) lfirst(temp);
strcat(buf, " WHEN ");
strcat(buf, get_rule_expr(qh, rt_index,
when->expr, varprefix));
strcat(buf, " THEN ");
strcat(buf, get_rule_expr(qh, rt_index,
when->result, varprefix));
}
strcat(buf, " ELSE ");
strcat(buf, get_rule_expr(qh, rt_index,
caseexpr->defresult, varprefix));
strcat(buf, " END");
return pstrdup(buf);
} }
break; break;
...@@ -1374,13 +1413,9 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1374,13 +1413,9 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
return get_sublink_expr(qh, rt_index, node, varprefix); return get_sublink_expr(qh, rt_index, node, varprefix);
break; break;
case T_Const:
return get_const_expr((Const *) node);
break;
default: default:
printf("\n%s\n", nodeToString(node)); printf("\n%s\n", nodeToString(node));
elog(ERROR, "get_ruledef of %s: unknown node type %d get_rule_expr()", elog(ERROR, "get_ruledef of %s: unknown node type %d in get_rule_expr()",
rulename, nodeTag(node)); rulename, nodeTag(node));
break; break;
} }
...@@ -1423,7 +1458,7 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix) ...@@ -1423,7 +1458,7 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix)
strcpy(buf, "("); strcpy(buf, "(");
strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args), strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args),
varprefix)); varprefix));
strcat(buf, ") ISNULL"); strcat(buf, " ISNULL)");
return pstrdup(buf); return pstrdup(buf);
} }
if (!strcmp(proname, "nonnullvalue")) if (!strcmp(proname, "nonnullvalue"))
...@@ -1431,7 +1466,7 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix) ...@@ -1431,7 +1466,7 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix)
strcpy(buf, "("); strcpy(buf, "(");
strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args), strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args),
varprefix)); varprefix));
strcat(buf, ") NOTNULL"); strcat(buf, " NOTNULL)");
return pstrdup(buf); return pstrdup(buf);
} }
} }
...@@ -1475,10 +1510,11 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix) ...@@ -1475,10 +1510,11 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix)
static char * static char *
get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix) get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix)
{ {
HeapTuple proctup; Expr *expr = (Expr *) (tle->expr);
Form_pg_proc procStruct;
Expr *expr;
Func *func; Func *func;
HeapTuple tup;
Form_pg_proc procStruct;
Form_pg_type typeStruct;
Const *second_arg; Const *second_arg;
/* ---------- /* ----------
...@@ -1486,12 +1522,9 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix) ...@@ -1486,12 +1522,9 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix)
* expression in the targetlist entry is a function call * expression in the targetlist entry is a function call
* ---------- * ----------
*/ */
if (tle->resdom->restypmod < 0) if (tle->resdom->restypmod < 0 ||
return get_rule_expr(qh, rt_index, tle->expr, varprefix); ! IsA(expr, Expr) ||
if (nodeTag(tle->expr) != T_Expr) expr->opType != FUNC_EXPR)
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
expr = (Expr *) (tle->expr);
if (expr->opType != FUNC_EXPR)
return get_rule_expr(qh, rt_index, tle->expr, varprefix); return get_rule_expr(qh, rt_index, tle->expr, varprefix);
func = (Func *) (expr->oper); func = (Func *) (expr->oper);
...@@ -1500,12 +1533,11 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix) ...@@ -1500,12 +1533,11 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix)
* Get the functions pg_proc tuple * Get the functions pg_proc tuple
* ---------- * ----------
*/ */
proctup = SearchSysCacheTuple(PROOID, tup = SearchSysCacheTuple(PROOID,
ObjectIdGetDatum(func->funcid), 0, 0, 0); ObjectIdGetDatum(func->funcid), 0, 0, 0);
if (!HeapTupleIsValid(proctup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup for proc %u failed", func->funcid); elog(ERROR, "cache lookup for proc %u failed", func->funcid);
procStruct = (Form_pg_proc) GETSTRUCT(tup);
procStruct = (Form_pg_proc) GETSTRUCT(proctup);
/* ---------- /* ----------
* It must be a function with two arguments where the first * It must be a function with two arguments where the first
...@@ -1513,22 +1545,34 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix) ...@@ -1513,22 +1545,34 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix)
* an int4. * an int4.
* ---------- * ----------
*/ */
if (procStruct->pronargs != 2) if (procStruct->pronargs != 2 ||
return get_rule_expr(qh, rt_index, tle->expr, varprefix); procStruct->prorettype != procStruct->proargtypes[0] ||
if (procStruct->prorettype != procStruct->proargtypes[0]) procStruct->proargtypes[1] != INT4OID)
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
if (procStruct->proargtypes[1] != INT4OID)
return get_rule_expr(qh, rt_index, tle->expr, varprefix); return get_rule_expr(qh, rt_index, tle->expr, varprefix);
/*
* Furthermore, the name of the function must be the same
* as the argument/result type name.
*/
tup = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(procStruct->prorettype),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup for type %u failed",
procStruct->prorettype);
typeStruct = (Form_pg_type) GETSTRUCT(tup);
if (strncmp(procStruct->proname.data, typeStruct->typname.data,
NAMEDATALEN) != 0)
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
/* ---------- /* ----------
* Finally (to be totally safe) the second argument must be a * Finally (to be totally safe) the second argument must be a
* const and match the value in the results atttypmod. * const and match the value in the results atttypmod.
* ---------- * ----------
*/ */
second_arg = (Const *) nth(1, expr->args); second_arg = (Const *) nth(1, expr->args);
if (nodeTag((Node *) second_arg) != T_Const) if (! IsA(second_arg, Const) ||
return get_rule_expr(qh, rt_index, tle->expr, varprefix); ((int4) second_arg->constvalue) != tle->resdom->restypmod)
if ((int4) (second_arg->constvalue) != tle->resdom->restypmod)
return get_rule_expr(qh, rt_index, tle->expr, varprefix); return get_rule_expr(qh, rt_index, tle->expr, varprefix);
/* ---------- /* ----------
...@@ -1556,12 +1600,12 @@ get_const_expr(Const *constval) ...@@ -1556,12 +1600,12 @@ get_const_expr(Const *constval)
char namebuf[64]; char namebuf[64];
if (constval->constisnull) if (constval->constisnull)
return "NULL"; return pstrdup("NULL");
typetup = SearchSysCacheTuple(TYPOID, typetup = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(constval->consttype), 0, 0, 0); ObjectIdGetDatum(constval->consttype), 0, 0, 0);
if (!HeapTupleIsValid(typetup)) if (!HeapTupleIsValid(typetup))
elog(ERROR, "cache lookup of type %d failed", constval->consttype); elog(ERROR, "cache lookup of type %u failed", constval->consttype);
typeStruct = (Form_pg_type) GETSTRUCT(typetup); typeStruct = (Form_pg_type) GETSTRUCT(typetup);
...@@ -1593,6 +1637,8 @@ get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1593,6 +1637,8 @@ get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
buf[0] = '\0'; buf[0] = '\0';
strcat(buf, "(");
if (sublink->lefthand != NULL) if (sublink->lefthand != NULL)
{ {
if (length(sublink->lefthand) > 1) if (length(sublink->lefthand) > 1)
...@@ -1645,7 +1691,7 @@ get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1645,7 +1691,7 @@ get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
strcat(buf, "("); strcat(buf, "(");
strcat(buf, get_query_def(query, qh)); strcat(buf, get_query_def(query, qh));
strcat(buf, ")"); strcat(buf, "))");
return pstrdup(buf); return pstrdup(buf);
} }
...@@ -1694,96 +1740,49 @@ get_attribute_name(Oid relid, int2 attnum) ...@@ -1694,96 +1740,49 @@ get_attribute_name(Oid relid, int2 attnum)
/* ---------- /* ----------
* check_if_rte_used - Check a targetlist or qual * check_if_rte_used
* if a given rangetable entry * Check a targetlist or qual to see if a given rangetable entry
* is used in it * is used in it
* ---------- * ----------
*/ */
static bool static bool
check_if_rte_used(int rt_index, Node *node, int sup) check_if_rte_used(Node *node, Index rt_index, int levelsup)
{ {
if (node == NULL) check_if_rte_used_context context;
return FALSE;
switch (nodeTag(node))
{
case T_TargetEntry:
{
TargetEntry *tle = (TargetEntry *) node;
return check_if_rte_used(rt_index,
(Node *) (tle->expr), sup);
}
break;
case T_Aggref:
{
Aggref *aggref = (Aggref *) node;
return check_if_rte_used(rt_index,
(Node *) (aggref->target), sup);
}
break;
case T_GroupClause: context.rt_index = rt_index;
return FALSE; context.levelsup = levelsup;
break; return check_if_rte_used_walker(node, &context);
}
case T_Expr:
{
Expr *expr = (Expr *) node;
return check_if_rte_used(rt_index,
(Node *) (expr->args), sup);
}
break;
case T_Var:
{
Var *var = (Var *) node;
return var->varno == rt_index && var->varlevelsup == sup;
}
break;
case T_List:
{
List *l;
foreach(l, (List *) node)
{
if (check_if_rte_used(rt_index, lfirst(l), sup))
return TRUE;
}
return FALSE;
}
break;
case T_SubLink:
{
SubLink *sublink = (SubLink *) node;
Query *query = (Query *) sublink->subselect;
if (check_if_rte_used(rt_index, (Node *) (query->qual), sup + 1))
return TRUE;
/* why aren't we looking at query->targetlist, havingQual? */
if (check_if_rte_used(rt_index, (Node *) (sublink->lefthand), sup))
return TRUE;
return FALSE;
}
break;
case T_Const: static bool
return FALSE; check_if_rte_used_walker(Node *node,
break; check_if_rte_used_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
default: return var->varno == context->rt_index &&
elog(ERROR, "get_ruledef of %s: unknown node type %d in check_if_rte_used()", var->varlevelsup == context->levelsup;
rulename, nodeTag(node));
break;
} }
if (IsA(node, SubLink))
return FALSE; {
SubLink *sublink = (SubLink *) node;
Query *query = (Query *) sublink->subselect;
/* Recurse into subquery; expression_tree_walker will not */
if (check_if_rte_used((Node *) (query->targetList),
context->rt_index, context->levelsup + 1) ||
check_if_rte_used(query->qual,
context->rt_index, context->levelsup + 1) ||
check_if_rte_used(query->havingQual,
context->rt_index, context->levelsup + 1))
return true;
/* fall through to let expression_tree_walker examine lefthand args */
}
return expression_tree_walker(node, check_if_rte_used_walker,
(void *) context);
} }
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