Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitaef7a0c

Browse files
committed
Parse JOIN/ON conditions with the proper visibility of input columns,
ie, consider only the columns coming from the JOIN clause's sub-clauses.Also detect attempts to reference columns belonging to other tables(which would still be possible using an explicitly-qualified name).I'm not sure this implements the spec's semantics 100% accurately, butat least it gives plausible behavior.
1 parent418bd67 commitaef7a0c

File tree

1 file changed

+115
-30
lines changed

1 file changed

+115
-30
lines changed

‎src/backend/parser/parse_clause.c

Lines changed: 115 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.66 2000/09/1221:07:02 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.67 2000/09/17 22:21:27 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
1515

1616
#include"postgres.h"
1717

1818
#include"access/heapam.h"
19-
#include"optimizer/tlist.h"
2019
#include"nodes/makefuncs.h"
20+
#include"optimizer/tlist.h"
21+
#include"optimizer/var.h"
2122
#include"parser/analyze.h"
2223
#include"parser/parse.h"
2324
#include"parser/parsetree.h"
@@ -38,12 +39,15 @@ static char *clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON"};
3839
staticvoidextractUniqueColumns(List*common_colnames,
3940
List*src_colnames,List*src_colvars,
4041
List**res_colnames,List**res_colvars);
41-
staticNode*transformUsingClause(ParseState*pstate,
42-
List*leftVars,List*rightVars);
42+
staticNode*transformJoinUsingClause(ParseState*pstate,
43+
List*leftVars,List*rightVars);
44+
staticNode*transformJoinOnClause(ParseState*pstate,JoinExpr*j,
45+
List*containedRels);
4346
staticRangeTblRef*transformTableEntry(ParseState*pstate,RangeVar*r);
4447
staticRangeTblRef*transformRangeSubselect(ParseState*pstate,
4548
RangeSubselect*r);
46-
staticNode*transformFromClauseItem(ParseState*pstate,Node*n);
49+
staticNode*transformFromClauseItem(ParseState*pstate,Node*n,
50+
List**containedRels);
4751
staticTargetEntry*findTargetlistEntry(ParseState*pstate,Node*node,
4852
List*tlist,intclause);
4953
staticList*addTargetToSortList(TargetEntry*tle,List*sortlist,
@@ -76,8 +80,9 @@ makeRangeTable(ParseState *pstate, List *frmList)
7680
foreach(fl,frmList)
7781
{
7882
Node*n=lfirst(fl);
83+
List*containedRels;
7984

80-
n=transformFromClauseItem(pstate,n);
85+
n=transformFromClauseItem(pstate,n,&containedRels);
8186
pstate->p_jointree=lappend(pstate->p_jointree,n);
8287
}
8388
}
@@ -164,13 +169,13 @@ extractUniqueColumns(List *common_colnames,
164169
*res_colvars=new_colvars;
165170
}
166171

167-
/*transformUsingClause()
168-
* Build a complete ON clause from a partially-transformed USING list.
169-
*We are given lists of Var nodes representing left and right match columns.
170-
* Result is a transformed qualification expression.
172+
/*transformJoinUsingClause()
173+
* Build a complete ON clause from a partially-transformed USING list.
174+
*We are given lists of nodes representing left and right match columns.
175+
* Result is a transformed qualification expression.
171176
*/
172177
staticNode*
173-
transformUsingClause(ParseState*pstate,List*leftVars,List*rightVars)
178+
transformJoinUsingClause(ParseState*pstate,List*leftVars,List*rightVars)
174179
{
175180
Node*result=NULL;
176181
List*lvars,
@@ -210,18 +215,82 @@ transformUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
210215
rvars=lnext(rvars);
211216
}
212217

218+
/*
219+
* Since the references are already Vars, and are certainly from the
220+
* input relations, we don't have to go through the same pushups that
221+
* transformJoinOnClause() does. Just invoke transformExpr() to fix
222+
* up the operators, and we're done.
223+
*/
213224
result=transformExpr(pstate,result,EXPR_COLUMN_FIRST);
214225

215226
if (exprType(result)!=BOOLOID)
216227
{
217228
/* This could only happen if someone defines a funny version of '=' */
218-
elog(ERROR,"USING clause must return type bool, not type %s",
229+
elog(ERROR,"JOIN/USING clause must return type bool, not type %s",
219230
typeidTypeName(exprType(result)));
220231
}
221232

222233
returnresult;
223-
}/* transformUsingClause() */
234+
}/* transformJoinUsingClause() */
235+
236+
/* transformJoinOnClause()
237+
* Transform the qual conditions for JOIN/ON.
238+
* Result is a transformed qualification expression.
239+
*/
240+
staticNode*
241+
transformJoinOnClause(ParseState*pstate,JoinExpr*j,
242+
List*containedRels)
243+
{
244+
Node*result;
245+
List*sv_jointree;
246+
List*clause_varnos,
247+
*l;
248+
249+
/*
250+
* This is a tad tricky, for two reasons. First, at the point where
251+
* we're called, the two subtrees of the JOIN node aren't yet part of
252+
* the pstate's jointree, which means that transformExpr() won't resolve
253+
* unqualified references to their columns correctly. We fix this in a
254+
* slightly klugy way: temporarily make the pstate's jointree consist of
255+
* just those two subtrees (which creates exactly the namespace the ON
256+
* clause should see). This is OK only because the ON clause can't
257+
* legally alter the jointree by causing relation refs to be added.
258+
*/
259+
sv_jointree=pstate->p_jointree;
260+
pstate->p_jointree=lcons(j->larg,lcons(j->rarg,NIL));
261+
262+
/* This part is just like transformWhereClause() */
263+
result=transformExpr(pstate,j->quals,EXPR_COLUMN_FIRST);
264+
if (exprType(result)!=BOOLOID)
265+
{
266+
elog(ERROR,"JOIN/ON clause must return type bool, not type %s",
267+
typeidTypeName(exprType(result)));
268+
}
269+
270+
pstate->p_jointree=sv_jointree;
271+
272+
/*
273+
* Second, we need to check that the ON condition doesn't refer to any
274+
* rels outside the input subtrees of the JOIN. It could do that despite
275+
* our hack on the jointree if it uses fully-qualified names. So, grovel
276+
* through the transformed clause and make sure there are no bogus
277+
* references.
278+
*/
279+
clause_varnos=pull_varnos(result);
280+
foreach(l,clause_varnos)
281+
{
282+
intvarno=lfirsti(l);
224283

284+
if (!intMember(varno,containedRels))
285+
{
286+
elog(ERROR,"JOIN/ON clause refers to \"%s\", which is not part of JOIN",
287+
rt_fetch(varno,pstate->p_rtable)->eref->relname);
288+
}
289+
}
290+
freeList(clause_varnos);
291+
292+
returnresult;
293+
}
225294

226295
/*
227296
* transformTableEntry --- transform a RangeVar (simple relation reference)
@@ -309,25 +378,40 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
309378
* range table list being built in the ParseState, and return the
310379
* transformed item ready to include in the jointree list.
311380
* This routine can recurse to handle SQL92 JOIN expressions.
381+
*
382+
* Aside from the primary return value (the transformed jointree item)
383+
* this routine also returns an integer list of the rangetable indexes
384+
* of all the base relations represented in the jointree item. This
385+
* list is needed for checking JOIN/ON conditions in higher levels.
312386
*/
313387
staticNode*
314-
transformFromClauseItem(ParseState*pstate,Node*n)
388+
transformFromClauseItem(ParseState*pstate,Node*n,List**containedRels)
315389
{
316390
if (IsA(n,RangeVar))
317391
{
318392
/* Plain relation reference */
319-
return (Node*)transformTableEntry(pstate, (RangeVar*)n);
393+
RangeTblRef*rtr;
394+
395+
rtr=transformTableEntry(pstate, (RangeVar*)n);
396+
*containedRels=lconsi(rtr->rtindex,NIL);
397+
return (Node*)rtr;
320398
}
321399
elseif (IsA(n,RangeSubselect))
322400
{
323-
/* Plain relation reference */
324-
return (Node*)transformRangeSubselect(pstate, (RangeSubselect*)n);
401+
/* sub-SELECT is like a plain relation */
402+
RangeTblRef*rtr;
403+
404+
rtr=transformRangeSubselect(pstate, (RangeSubselect*)n);
405+
*containedRels=lconsi(rtr->rtindex,NIL);
406+
return (Node*)rtr;
325407
}
326408
elseif (IsA(n,JoinExpr))
327409
{
328410
/* A newfangled join expression */
329411
JoinExpr*j= (JoinExpr*)n;
330-
List*l_colnames,
412+
List*l_containedRels,
413+
*r_containedRels,
414+
*l_colnames,
331415
*r_colnames,
332416
*res_colnames,
333417
*l_colvars,
@@ -337,8 +421,13 @@ transformFromClauseItem(ParseState *pstate, Node *n)
337421
/*
338422
* Recursively process the left and right subtrees
339423
*/
340-
j->larg=transformFromClauseItem(pstate,j->larg);
341-
j->rarg=transformFromClauseItem(pstate,j->rarg);
424+
j->larg=transformFromClauseItem(pstate,j->larg,&l_containedRels);
425+
j->rarg=transformFromClauseItem(pstate,j->rarg,&r_containedRels);
426+
427+
/*
428+
* Generate combined list of relation indexes
429+
*/
430+
*containedRels=nconc(l_containedRels,r_containedRels);
342431

343432
/*
344433
* Extract column name and var lists from both subtrees
@@ -463,7 +552,7 @@ transformFromClauseItem(ParseState *pstate, Node *n)
463552
ndx++;
464553
}
465554
if (l_index<0)
466-
elog(ERROR,"USING column \"%s\" not found in left table",
555+
elog(ERROR,"JOIN/USING column \"%s\" not found in left table",
467556
u_colname);
468557

469558
ndx=0;
@@ -480,7 +569,7 @@ transformFromClauseItem(ParseState *pstate, Node *n)
480569
ndx++;
481570
}
482571
if (r_index<0)
483-
elog(ERROR,"USING column \"%s\" not found in right table",
572+
elog(ERROR,"JOIN/USING column \"%s\" not found in right table",
484573
u_colname);
485574

486575
l_colvar=nth(l_index,l_colvars);
@@ -520,18 +609,14 @@ transformFromClauseItem(ParseState *pstate, Node *n)
520609
res_colvars=lappend(res_colvars,colvar);
521610
}
522611

523-
j->quals=transformUsingClause(pstate,l_usingvars,r_usingvars);
612+
j->quals=transformJoinUsingClause(pstate,
613+
l_usingvars,
614+
r_usingvars);
524615
}
525616
elseif (j->quals)
526617
{
527618
/* User-written ON-condition; transform it */
528-
j->quals=transformExpr(pstate,j->quals,EXPR_COLUMN_FIRST);
529-
if (exprType(j->quals)!=BOOLOID)
530-
{
531-
elog(ERROR,"ON clause must return type bool, not type %s",
532-
typeidTypeName(exprType(j->quals)));
533-
}
534-
/* XXX should check that ON clause refers only to joined tbls */
619+
j->quals=transformJoinOnClause(pstate,j,*containedRels);
535620
}
536621
else
537622
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp