aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-08-08 01:44:31 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-08-08 01:44:31 +0000
commitb084cc3504ec62cd0b36ae47c11b4b6f06e0bb97 (patch)
tree0e21ffe15a562533b7b4bee17295ebd76f18db65 /src/backend/utils/adt/ruleutils.c
parente42f8e32e9f6580d081ac13136469c0cd8338ffa (diff)
downloadpostgresql-b084cc3504ec62cd0b36ae47c11b4b6f06e0bb97.tar.gz
postgresql-b084cc3504ec62cd0b36ae47c11b4b6f06e0bb97.zip
Cause schema-qualified FROM items and schema-qualified variable references
to behave according to SQL92 (or according to my current understanding of same, anyway). Per pghackers discussion way back in March 2002: thread 'Do FROM items of different schemas conflict?'
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c120
1 files changed, 104 insertions, 16 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 5999ad96285..98bbba534aa 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.112 2002/07/18 23:11:28 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.113 2002/08/08 01:44:31 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -131,7 +131,9 @@ static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist,
bool force_colno,
deparse_context *context);
static void get_names_for_var(Var *var, deparse_context *context,
- char **refname, char **attname);
+ char **schemaname, char **refname, char **attname);
+static RangeTblEntry *find_rte_by_refname(const char *refname,
+ deparse_context *context);
static void get_rule_expr(Node *node, deparse_context *context);
static void get_oper_expr(Expr *expr, deparse_context *context);
static void get_func_expr(Expr *expr, deparse_context *context);
@@ -1204,10 +1206,11 @@ get_basic_select_query(Query *query, deparse_context *context)
else
{
Var *var = (Var *) (tle->expr);
+ char *schemaname;
char *refname;
char *attname;
- get_names_for_var(var, context, &refname, &attname);
+ get_names_for_var(var, context, &schemaname, &refname, &attname);
tell_as = (attname == NULL ||
strcmp(attname, tle->resdom->resname) != 0);
}
@@ -1513,17 +1516,22 @@ get_utility_query_def(Query *query, deparse_context *context)
/*
- * Get the relation refname and attname for a (possibly nonlocal) Var.
+ * Get the schemaname, refname and attname for a (possibly nonlocal) Var.
+ *
+ * schemaname is usually returned as NULL. It will be non-null only if
+ * use of the unqualified refname would find the wrong RTE.
*
* refname will be returned as NULL if the Var references an unnamed join.
* In this case the Var *must* be displayed without any qualification.
*
* attname will be returned as NULL if the Var represents a whole tuple
- * of the relation.
+ * of the relation. (Typically we'd want to display the Var as "foo.*",
+ * but it's convenient to return NULL to make it easier for callers to
+ * distinguish this case.)
*/
static void
get_names_for_var(Var *var, deparse_context *context,
- char **refname, char **attname)
+ char **schemaname, char **refname, char **attname)
{
List *nslist = context->namespaces;
int sup = var->varlevelsup;
@@ -1552,10 +1560,29 @@ get_names_for_var(Var *var, deparse_context *context,
var->varno);
/* Emit results */
- if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
- *refname = NULL;
- else
- *refname = rte->eref->aliasname;
+ *schemaname = NULL; /* default assumptions */
+ *refname = rte->eref->aliasname;
+
+ /* Exceptions occur only if the RTE is alias-less */
+ if (rte->alias == NULL)
+ {
+ if (rte->rtekind == RTE_RELATION)
+ {
+ /*
+ * It's possible that use of the bare refname would find another
+ * more-closely-nested RTE, or be ambiguous, in which case
+ * we need to specify the schemaname to avoid these errors.
+ */
+ if (find_rte_by_refname(rte->eref->aliasname, context) != rte)
+ *schemaname =
+ get_namespace_name(get_rel_namespace(rte->relid));
+ }
+ else if (rte->rtekind == RTE_JOIN)
+ {
+ /* Unnamed join has neither schemaname nor refname */
+ *refname = NULL;
+ }
+ }
if (var->varattno == InvalidAttrNumber)
*attname = NULL;
@@ -1563,6 +1590,61 @@ get_names_for_var(Var *var, deparse_context *context,
*attname = get_rte_attribute_name(rte, var->varattno);
}
+/*
+ * find_rte_by_refname - look up an RTE by refname in a deparse context
+ *
+ * Returns NULL if there is no matching RTE or the refname is ambiguous.
+ *
+ * NOTE: this code is not really correct since it does not take account of
+ * the fact that not all the RTEs in a rangetable may be visible from the
+ * point where a Var reference appears. For the purposes we need, however,
+ * the only consequence of a false match is that we might stick a schema
+ * qualifier on a Var that doesn't really need it. So it seems close
+ * enough.
+ */
+static RangeTblEntry *
+find_rte_by_refname(const char *refname, deparse_context *context)
+{
+ RangeTblEntry *result = NULL;
+ List *nslist;
+
+ foreach(nslist, context->namespaces)
+ {
+ deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
+ List *rtlist;
+
+ foreach(rtlist, dpns->rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtlist);
+
+ if (strcmp(rte->eref->aliasname, refname) == 0)
+ {
+ if (result)
+ return NULL; /* it's ambiguous */
+ result = rte;
+ }
+ }
+ if (dpns->outer_rte &&
+ strcmp(dpns->outer_rte->eref->aliasname, refname) == 0)
+ {
+ if (result)
+ return NULL; /* it's ambiguous */
+ result = dpns->outer_rte;
+ }
+ if (dpns->inner_rte &&
+ strcmp(dpns->inner_rte->eref->aliasname, refname) == 0)
+ {
+ if (result)
+ return NULL; /* it's ambiguous */
+ result = dpns->inner_rte;
+ }
+ if (result)
+ break;
+ }
+ return result;
+}
+
+
/* ----------
* get_rule_expr - Parse back an expression
* ----------
@@ -1592,24 +1674,30 @@ get_rule_expr(Node *node, deparse_context *context)
case T_Var:
{
Var *var = (Var *) node;
+ char *schemaname;
char *refname;
char *attname;
- get_names_for_var(var, context, &refname, &attname);
+ get_names_for_var(var, context,
+ &schemaname, &refname, &attname);
if (refname && (context->varprefix || attname == NULL))
{
+ if (schemaname)
+ appendStringInfo(buf, "%s.",
+ quote_identifier(schemaname));
+
if (strcmp(refname, "*NEW*") == 0)
- appendStringInfo(buf, "new");
+ appendStringInfo(buf, "new.");
else if (strcmp(refname, "*OLD*") == 0)
- appendStringInfo(buf, "old");
+ appendStringInfo(buf, "old.");
else
- appendStringInfo(buf, "%s",
+ appendStringInfo(buf, "%s.",
quote_identifier(refname));
- if (attname)
- appendStringInfoChar(buf, '.');
}
if (attname)
appendStringInfo(buf, "%s", quote_identifier(attname));
+ else
+ appendStringInfo(buf, "*");
}
break;