Commit 01911c98 authored by Tom Lane's avatar Tom Lane

Repair list-vs-node confusion that resulted in failure for INNER JOIN ON.

Make it behave correctly when there are more than two tables being
joined, also.  Update regression test expected outputs.
parent 4624b84c
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.59 2000/04/12 17:15:26 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.60 2000/05/12 01:33:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -41,8 +41,8 @@ static List *addTargetToSortList(TargetEntry *tle, List *sortlist, ...@@ -41,8 +41,8 @@ static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
static bool exprIsInSortList(Node *expr, List *sortList, List *targetList); static bool exprIsInSortList(Node *expr, List *sortList, List *targetList);
#ifndef DISABLE_OUTER_JOINS #ifndef DISABLE_OUTER_JOINS
static Node *transformUsingClause(ParseState *pstate, List *using, List *left, List *right); static List *transformUsingClause(ParseState *pstate, List *using,
List *left, List *right);
#endif #endif
...@@ -94,32 +94,33 @@ setTargetTable(ParseState *pstate, char *relname) ...@@ -94,32 +94,33 @@ setTargetTable(ParseState *pstate, char *relname)
} }
Node * static Node *
mergeInnerJoinQuals(ParseState *pstate, Node *clause);
Node *
mergeInnerJoinQuals(ParseState *pstate, Node *clause) mergeInnerJoinQuals(ParseState *pstate, Node *clause)
{ {
A_Expr *expr = (A_Expr *) pstate->p_join_quals; List *jquals;
if (expr == NULL) foreach(jquals, pstate->p_join_quals)
return clause;
if (clause != NULL)
{ {
A_Expr *a = makeNode(A_Expr); Node *jqual = (Node *) lfirst(jquals);
if (clause == NULL)
clause = jqual;
else
{
A_Expr *a = makeNode(A_Expr);
a->oper = AND; a->oper = AND;
a->opname = NULL; a->opname = NULL;
a->lexpr = (Node *) expr; a->lexpr = clause;
a->rexpr = clause; a->rexpr = jqual;
expr = a; clause = (Node *) a;
}
} }
/* Make sure that we don't do this twice... */ /* Make sure that we don't add same quals twice... */
pstate->p_join_quals = NULL; pstate->p_join_quals = NIL;
return (Node *) expr; return clause;
} /* mergeInnerJoinQuals() */ } /* mergeInnerJoinQuals() */
/* /*
...@@ -131,7 +132,7 @@ transformWhereClause(ParseState *pstate, Node *clause) ...@@ -131,7 +132,7 @@ transformWhereClause(ParseState *pstate, Node *clause)
{ {
Node *qual; Node *qual;
if (pstate->p_join_quals != NULL) if (pstate->p_join_quals != NIL)
clause = mergeInnerJoinQuals(pstate, clause); clause = mergeInnerJoinQuals(pstate, clause);
if (clause == NULL) if (clause == NULL)
...@@ -275,21 +276,22 @@ ExpandAttrs(Attr *attr) ...@@ -275,21 +276,22 @@ ExpandAttrs(Attr *attr)
/* transformUsingClause() /* transformUsingClause()
* Take an ON or USING clause from a join expression and expand if necessary. * Take an ON or USING clause from a join expression and expand if necessary.
* Result is an implicitly-ANDed list of untransformed qualification clauses.
*/ */
static Node * static List *
transformUsingClause(ParseState *pstate, List *usingList, List *leftList, List *rightList) transformUsingClause(ParseState *pstate, List *usingList,
List *leftList, List *rightList)
{ {
A_Expr *expr = NULL; List *result = NIL;
List *using; List *using;
foreach(using, usingList) foreach(using, usingList)
{ {
List *col;
A_Expr *e;
Attr *uattr = lfirst(using); Attr *uattr = lfirst(using);
Attr *lattr = NULL, Attr *lattr = NULL,
*rattr = NULL; *rattr = NULL;
List *col;
A_Expr *e;
/* /*
* find the first instances of this column in the shape list and * find the first instances of this column in the shape list and
...@@ -324,22 +326,11 @@ transformUsingClause(ParseState *pstate, List *usingList, List *leftList, List * ...@@ -324,22 +326,11 @@ transformUsingClause(ParseState *pstate, List *usingList, List *leftList, List *
e->lexpr = (Node *) lattr; e->lexpr = (Node *) lattr;
e->rexpr = (Node *) rattr; e->rexpr = (Node *) rattr;
if (expr != NULL) result = lappend(result, e);
{
A_Expr *a = makeNode(A_Expr);
a->oper = AND;
a->opname = NULL;
a->lexpr = (Node *) expr;
a->rexpr = (Node *) e;
expr = a;
}
else
expr = e;
} }
return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST)); return result;
} /* transformUsiongClause() */ } /* transformUsingClause() */
#endif #endif
...@@ -632,7 +623,7 @@ parseFromClause(ParseState *pstate, List *frmList) ...@@ -632,7 +623,7 @@ parseFromClause(ParseState *pstate, List *frmList)
printf("JOIN/USING input quals are %s\n", nodeToString(j->quals)); printf("JOIN/USING input quals are %s\n", nodeToString(j->quals));
j->quals = (List *) transformUsingClause(pstate, shape, l_cols, r_cols); j->quals = transformUsingClause(pstate, shape, l_cols, r_cols);
printf("JOIN/USING transformed quals are %s\n", nodeToString(j->quals)); printf("JOIN/USING transformed quals are %s\n", nodeToString(j->quals));
...@@ -650,7 +641,12 @@ parseFromClause(ParseState *pstate, List *frmList) ...@@ -650,7 +641,12 @@ parseFromClause(ParseState *pstate, List *frmList)
else else
j->quals = (List *) lcons(j->quals, NIL); j->quals = (List *) lcons(j->quals, NIL);
pstate->p_join_quals = (Node *) j->quals; /* listCopy may not be needed here --- will j->quals list
* be used again anywhere? The #ifdef'd code below may need
* it, if it ever gets used...
*/
pstate->p_join_quals = nconc(pstate->p_join_quals,
listCopy(j->quals));
#if 0 #if 0
if (qual == NULL) if (qual == NULL)
...@@ -660,11 +656,13 @@ parseFromClause(ParseState *pstate, List *frmList) ...@@ -660,11 +656,13 @@ parseFromClause(ParseState *pstate, List *frmList)
#endif #endif
#if 0 #if 0
/* XXX this code is WRONG because j->quals is a List
* not a simple expression. Perhaps *qual
* ought also to be a List and we append to it,
* similarly to the way p_join_quals is handled above?
*/
if (*qual == NULL) if (*qual == NULL)
{ {
#endif
#if 0
/* merge qualified join clauses... */ /* merge qualified join clauses... */
if (j->quals != NULL) if (j->quals != NULL)
{ {
...@@ -682,9 +680,6 @@ parseFromClause(ParseState *pstate, List *frmList) ...@@ -682,9 +680,6 @@ parseFromClause(ParseState *pstate, List *frmList)
else else
*qual = (Node *) j->quals; *qual = (Node *) j->quals;
} }
#endif
#if 0
} }
else else
{ {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_node.h,v 1.19 2000/04/12 17:16:45 momjian Exp $ * $Id: parse_node.h,v 1.20 2000/05/12 01:33:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,9 +17,10 @@ ...@@ -17,9 +17,10 @@
#include "utils/rel.h" #include "utils/rel.h"
/* State information used during parse analysis /* State information used during parse analysis
* p_join_quals is a list of qualification expressions * p_join_quals is a list of untransformed qualification expressions
* found in the FROM clause. Needs to be available later * (implicitly ANDed together) found in the FROM clause.
* to merge with other qualifiers from the WHERE clause. * Needs to be available later to merge with other qualifiers from the
* WHERE clause.
*/ */
typedef struct ParseState typedef struct ParseState
{ {
...@@ -36,7 +37,7 @@ typedef struct ParseState ...@@ -36,7 +37,7 @@ typedef struct ParseState
RangeTblEntry *p_target_rangetblentry; RangeTblEntry *p_target_rangetblentry;
List *p_shape; List *p_shape;
List *p_alias; List *p_alias;
Node *p_join_quals; List *p_join_quals;
} ParseState; } ParseState;
extern ParseState *make_parsestate(ParseState *parentParseState); extern ParseState *make_parsestate(ParseState *parentParseState);
......
...@@ -274,10 +274,22 @@ SELECT '' AS "xxx", * ...@@ -274,10 +274,22 @@ SELECT '' AS "xxx", *
-- --
SELECT '' AS "xxx", * SELECT '' AS "xxx", *
FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.i); FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.i);
ERROR: transformExpr: does not know how to transform node 501 (internal error) xxx | i | j | t | i | k
-----+---+---+-------+---+----
| 1 | 3 | one | 1 | -1
| 2 | 2 | two | 2 | 2
| 2 | 2 | two | 2 | 4
| 3 | 1 | three | 3 | -3
(4 rows)
SELECT '' AS "xxx", * SELECT '' AS "xxx", *
FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.k); FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.k);
ERROR: transformExpr: does not know how to transform node 501 (internal error) xxx | i | j | t | i | k
-----+---+---+------+---+---
| 2 | 2 | two | 2 | 2
| 4 | 0 | four | 2 | 4
(2 rows)
SELECT '' AS "xxx", * SELECT '' AS "xxx", *
FROM J1_TBL CROSS JOIN J2_TBL; FROM J1_TBL CROSS JOIN J2_TBL;
xxx | i | j | t | i | k xxx | i | j | t | i | k
...@@ -305,7 +317,16 @@ SELECT '' AS "xxx", * ...@@ -305,7 +317,16 @@ SELECT '' AS "xxx", *
-- --
SELECT '' AS "xxx", * SELECT '' AS "xxx", *
FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i <= J2_TBL.k); FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i <= J2_TBL.k);
ERROR: transformExpr: does not know how to transform node 501 (internal error) xxx | i | j | t | i | k
-----+---+---+-------+---+---
| 1 | 3 | one | 2 | 2
| 2 | 2 | two | 2 | 2
| 1 | 3 | one | 2 | 4
| 2 | 2 | two | 2 | 4
| 3 | 1 | three | 2 | 4
| 4 | 0 | four | 2 | 4
(6 rows)
-- --
-- Outer joins -- Outer joins
-- --
......
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