mirror of https://github.com/postgres/postgres.git
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.REL7_0_PATCHES
parent
4624b84cf2
commit
01911c98db
|
|
@ -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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
a->oper = AND;
|
if (clause == NULL)
|
||||||
a->opname = NULL;
|
clause = jqual;
|
||||||
a->lexpr = (Node *) expr;
|
else
|
||||||
a->rexpr = clause;
|
{
|
||||||
expr = a;
|
A_Expr *a = makeNode(A_Expr);
|
||||||
|
|
||||||
|
a->oper = AND;
|
||||||
|
a->opname = NULL;
|
||||||
|
a->lexpr = clause;
|
||||||
|
a->rexpr = jqual;
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
|
|
||||||
/* 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 *
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
#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)
|
||||||
else
|
else
|
||||||
*qual = (Node *) j->quals;
|
*qual = (Node *) j->quals;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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 @@
|
||||||
#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
|
||||||
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", *
|
||||||
--
|
--
|
||||||
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", *
|
||||||
--
|
--
|
||||||
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
|
||||||
--
|
--
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue