aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_clause.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_clause.c')
-rw-r--r--src/backend/parser/parse_clause.c162
1 files changed, 91 insertions, 71 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 61904439e7d..2f1eda4a9bf 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.83 2001/10/25 05:49:37 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.84 2002/03/12 00:51:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -503,7 +503,13 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
*res_colnames,
*l_colvars,
*r_colvars,
- *res_colvars;
+ *coltypes,
+ *coltypmods,
+ *leftcolnos,
+ *rightcolnos;
+ Index leftrti,
+ rightrti;
+ RangeTblEntry *rte;
/*
* Recursively process the left and right subtrees
@@ -525,39 +531,32 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
/*
* Extract column name and var lists from both subtrees
+ *
+ * Note: expandRTE returns new lists, safe for me to modify
*/
- if (IsA(j->larg, JoinExpr))
- {
- /* Make a copy of the subtree's lists so we can modify! */
- l_colnames = copyObject(((JoinExpr *) j->larg)->colnames);
- l_colvars = copyObject(((JoinExpr *) j->larg)->colvars);
- }
+ if (IsA(j->larg, RangeTblRef))
+ leftrti = ((RangeTblRef *) j->larg)->rtindex;
+ else if (IsA(j->larg, JoinExpr))
+ leftrti = ((JoinExpr *) j->larg)->rtindex;
else
{
- RangeTblEntry *rte;
-
- Assert(IsA(j->larg, RangeTblRef));
- rte = rt_fetch(((RangeTblRef *) j->larg)->rtindex,
- pstate->p_rtable);
- expandRTE(pstate, rte, &l_colnames, &l_colvars);
- /* expandRTE returns new lists, so no need for copyObject */
- }
- if (IsA(j->rarg, JoinExpr))
- {
- /* Make a copy of the subtree's lists so we can modify! */
- r_colnames = copyObject(((JoinExpr *) j->rarg)->colnames);
- r_colvars = copyObject(((JoinExpr *) j->rarg)->colvars);
+ elog(ERROR, "transformFromClauseItem: unexpected subtree type");
+ leftrti = 0; /* keep compiler quiet */
}
+ rte = rt_fetch(leftrti, pstate->p_rtable);
+ expandRTE(pstate, rte, &l_colnames, &l_colvars);
+
+ if (IsA(j->rarg, RangeTblRef))
+ rightrti = ((RangeTblRef *) j->rarg)->rtindex;
+ else if (IsA(j->rarg, JoinExpr))
+ rightrti = ((JoinExpr *) j->rarg)->rtindex;
else
{
- RangeTblEntry *rte;
-
- Assert(IsA(j->rarg, RangeTblRef));
- rte = rt_fetch(((RangeTblRef *) j->rarg)->rtindex,
- pstate->p_rtable);
- expandRTE(pstate, rte, &r_colnames, &r_colvars);
- /* expandRTE returns new lists, so no need for copyObject */
+ elog(ERROR, "transformFromClauseItem: unexpected subtree type");
+ rightrti = 0; /* keep compiler quiet */
}
+ rte = rt_fetch(rightrti, pstate->p_rtable);
+ expandRTE(pstate, rte, &r_colnames, &r_colvars);
/*
* Natural join does not explicitly specify columns; must generate
@@ -604,7 +603,10 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
* Now transform the join qualifications, if any.
*/
res_colnames = NIL;
- res_colvars = NIL;
+ coltypes = NIL;
+ coltypmods = NIL;
+ leftcolnos = NIL;
+ rightcolnos = NIL;
if (j->using)
{
@@ -624,9 +626,10 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
{
char *u_colname = strVal(lfirst(ucol));
List *col;
- Node *l_colvar,
- *r_colvar,
- *colvar;
+ Var *l_colvar,
+ *r_colvar;
+ Oid outcoltype;
+ int32 outcoltypmod;
int ndx;
int l_index = -1;
int r_index = -1;
@@ -672,34 +675,28 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
res_colnames = lappend(res_colnames,
nth(l_index, l_colnames));
- switch (j->jointype)
+ /*
+ * Choose output type if input types are dissimilar.
+ */
+ outcoltype = l_colvar->vartype;
+ outcoltypmod = l_colvar->vartypmod;
+ if (outcoltype != r_colvar->vartype)
{
- case JOIN_INNER:
- case JOIN_LEFT:
- colvar = l_colvar;
- break;
- case JOIN_RIGHT:
- colvar = r_colvar;
- break;
- default:
- {
- /* Need COALESCE(l_colvar, r_colvar) */
- CaseExpr *c = makeNode(CaseExpr);
- CaseWhen *w = makeNode(CaseWhen);
- NullTest *n = makeNode(NullTest);
-
- n->arg = l_colvar;
- n->nulltesttype = IS_NOT_NULL;
- w->expr = (Node *) n;
- w->result = l_colvar;
- c->args = makeList1(w);
- c->defresult = r_colvar;
- colvar = transformExpr(pstate, (Node *) c,
- EXPR_COLUMN_FIRST);
- break;
- }
+ outcoltype =
+ select_common_type(makeListi2(l_colvar->vartype,
+ r_colvar->vartype),
+ "JOIN/USING");
+ outcoltypmod = -1; /* ie, unknown */
}
- res_colvars = lappend(res_colvars, colvar);
+ else if (outcoltypmod != r_colvar->vartypmod)
+ {
+ /* same type, but not same typmod */
+ outcoltypmod = -1; /* ie, unknown */
+ }
+ coltypes = lappendi(coltypes, outcoltype);
+ coltypmods = lappendi(coltypmods, outcoltypmod);
+ leftcolnos = lappendi(leftcolnos, l_index+1);
+ rightcolnos = lappendi(rightcolnos, r_index+1);
}
j->quals = transformJoinUsingClause(pstate,
@@ -724,30 +721,53 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
r_colnames, r_colvars,
&r_colnames, &r_colvars);
res_colnames = nconc(res_colnames, l_colnames);
- res_colvars = nconc(res_colvars, l_colvars);
+ while (l_colvars)
+ {
+ Var *l_var = (Var *) lfirst(l_colvars);
+
+ coltypes = lappendi(coltypes, l_var->vartype);
+ coltypmods = lappendi(coltypmods, l_var->vartypmod);
+ leftcolnos = lappendi(leftcolnos, l_var->varattno);
+ rightcolnos = lappendi(rightcolnos, 0);
+ l_colvars = lnext(l_colvars);
+ }
res_colnames = nconc(res_colnames, r_colnames);
- res_colvars = nconc(res_colvars, r_colvars);
+ while (r_colvars)
+ {
+ Var *r_var = (Var *) lfirst(r_colvars);
+
+ coltypes = lappendi(coltypes, r_var->vartype);
+ coltypmods = lappendi(coltypmods, r_var->vartypmod);
+ leftcolnos = lappendi(leftcolnos, 0);
+ rightcolnos = lappendi(rightcolnos, r_var->varattno);
+ r_colvars = lnext(r_colvars);
+ }
/*
- * Process alias (AS clause), if any.
+ * Check alias (AS clause), if any.
*/
if (j->alias)
{
- /*
- * If a column alias list is specified, substitute the alias
- * names into my output-column list
- */
if (j->alias->attrs != NIL)
{
- if (length(j->alias->attrs) != length(res_colnames))
- elog(ERROR, "Column alias list for \"%s\" has wrong number of entries (need %d)",
- j->alias->relname, length(res_colnames));
- res_colnames = j->alias->attrs;
+ if (length(j->alias->attrs) > length(res_colnames))
+ elog(ERROR, "Column alias list for \"%s\" has too many entries",
+ j->alias->relname);
}
}
- j->colnames = res_colnames;
- j->colvars = res_colvars;
+ /*
+ * Now build an RTE for the result of the join
+ */
+ rte = addRangeTableEntryForJoin(pstate, res_colnames,
+ j->jointype,
+ coltypes, coltypmods,
+ leftcolnos, rightcolnos,
+ j->alias, true);
+
+ /* assume new rte is at end */
+ j->rtindex = length(pstate->p_rtable);
+ Assert(rte == rt_fetch(j->rtindex, pstate->p_rtable));
return (Node *) j;
}