77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.28 1999/02/13 23:17:07 momjian Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.29 1999/02/23 07:46:42 thomas Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
2626#include "parser/parse_relation.h"
2727#include "parser/parse_target.h"
2828#include "parser/parse_coerce.h"
29+ #include "nodes/print.h"
2930
31+ #include "parse.h"
3032
3133
3234#define ORDER_CLAUSE 0
@@ -37,7 +39,15 @@ static char *clauseText[] = {"ORDER", "GROUP"};
3739static TargetEntry *
3840findTargetlistEntry (ParseState * pstate ,Node * node ,List * tlist ,int clause );
3941
40- static void parseFromClause (ParseState * pstate ,List * frmList );
42+ static void parseFromClause (ParseState * pstate ,List * frmList ,Node * * qual );
43+
44+ Attr * makeAttr (char * relname ,char * attname );
45+
46+ #ifdef ENABLE_OUTER_JOINS
47+ Node * transformUsingClause (ParseState * pstate ,List * onList ,char * lname ,char * rname );
48+ #endif
49+
50+ char * transformTableEntry (ParseState * pstate ,RangeVar * r );
4151
4252
4353/*
@@ -46,18 +56,18 @@ static void parseFromClause(ParseState *pstate, List *frmList);
4656 * from_clause.
4757 */
4858void
49- makeRangeTable (ParseState * pstate ,char * relname ,List * frmList )
59+ makeRangeTable (ParseState * pstate ,char * relname ,List * frmList , Node * * qual )
5060{
5161RangeTblEntry * rte ;
5262int sublevels_up ;
5363
54- parseFromClause (pstate ,frmList );
64+ parseFromClause (pstate ,frmList , qual );
5565
5666if (relname == NULL )
5767return ;
5868
59- if (refnameRangeTablePosn (pstate ,relname ,& sublevels_up )== 0 ||
60- sublevels_up != 0 )
69+ if (( refnameRangeTablePosn (pstate ,relname ,& sublevels_up )== 0 )
70+ || ( sublevels_up != 0 ) )
6171rte = addRangeTableEntry (pstate ,relname ,relname , FALSE, FALSE);
6272else
6373rte = refnameRangeTableEntry (pstate ,relname );
@@ -77,17 +87,35 @@ makeRangeTable(ParseState *pstate, char *relname, List *frmList)
7787 * transformWhereClause -
7888 * transforms the qualification and make sure it is of type Boolean
7989 *
90+ * Now accept an additional argument, which is a qualification derived
91+ * from the JOIN/ON or JOIN/USING syntax.
92+ * - thomas 1998-12-16
8093 */
8194Node *
82- transformWhereClause (ParseState * pstate ,Node * a_expr )
95+ transformWhereClause (ParseState * pstate ,Node * a_expr , Node * o_expr )
8396{
97+ A_Expr * expr ;
8498Node * qual ;
8599
86- if (a_expr == NULL )
100+ if (( a_expr == NULL ) && ( o_expr == NULL ) )
87101return NULL ;/* no qualifiers */
88102
103+ if ((a_expr != NULL )&& (o_expr != NULL ))
104+ {
105+ A_Expr * a = makeNode (A_Expr );
106+ a -> oper = AND ;
107+ a -> opname = NULL ;
108+ a -> lexpr = o_expr ;
109+ a -> rexpr = a_expr ;
110+ expr = a ;
111+ }
112+ else if (o_expr != NULL )
113+ expr = (A_Expr * )o_expr ;
114+ else
115+ expr = (A_Expr * )a_expr ;
116+
89117pstate -> p_in_where_clause = true;
90- qual = transformExpr (pstate ,a_expr ,EXPR_COLUMN_FIRST );
118+ qual = transformExpr (pstate ,( Node * ) expr ,EXPR_COLUMN_FIRST );
91119pstate -> p_in_where_clause = false;
92120
93121if (exprType (qual )!= BOOLOID )
@@ -98,6 +126,122 @@ transformWhereClause(ParseState *pstate, Node *a_expr)
98126return qual ;
99127}
100128
129+ Attr *
130+ makeAttr (char * relname ,char * attname )
131+ {
132+ Attr * a = makeNode (Attr );
133+ a -> relname = relname ;
134+ a -> paramNo = NULL ;
135+ a -> attrs = lcons (makeString (attname ),NIL );
136+ a -> indirection = NULL ;
137+
138+ return a ;
139+ }
140+
141+ #ifdef ENABLE_OUTER_JOINS
142+ /* transformUsingClause()
143+ * Take an ON or USING clause from a join expression and expand if necessary.
144+ */
145+ Node *
146+ transformUsingClause (ParseState * pstate ,List * onList ,char * lname ,char * rname )
147+ {
148+ A_Expr * expr = NULL ;
149+ List * on ;
150+ Node * qual ;
151+
152+ foreach (on ,onList )
153+ {
154+ qual = lfirst (on );
155+
156+ /* Ident node means it is just a column name from a real USING clause... */
157+ if (IsA (qual ,Ident ))
158+ {
159+ Ident * i = (Ident * )qual ;
160+ Attr * lattr = makeAttr (lname ,i -> name );
161+ Attr * rattr = makeAttr (rname ,i -> name );
162+ A_Expr * e = makeNode (A_Expr );
163+
164+ #ifdef PARSEDEBUG
165+ printf ("transformUsingClause- transform %s" ,nodeToString (i ));
166+ #endif
167+
168+ e -> oper = OP ;
169+ e -> opname = "=" ;
170+ e -> lexpr = (Node * )lattr ;
171+ e -> rexpr = (Node * )rattr ;
172+
173+ if (expr != NULL )
174+ {
175+ A_Expr * a = makeNode (A_Expr );
176+ a -> oper = AND ;
177+ a -> opname = NULL ;
178+ a -> lexpr = (Node * )expr ;
179+ a -> rexpr = (Node * )e ;
180+ expr = a ;
181+ }
182+ else
183+ expr = e ;
184+ }
185+
186+ /* otherwise, we have an expression from an ON clause... */
187+ else
188+ {
189+ if (expr != NULL )
190+ {
191+ A_Expr * a = makeNode (A_Expr );
192+ a -> oper = AND ;
193+ a -> opname = NULL ;
194+ a -> lexpr = (Node * )expr ;
195+ a -> rexpr = (Node * )qual ;
196+ expr = a ;
197+ }
198+ else
199+ {
200+ expr = (A_Expr * )qual ;
201+ }
202+
203+ #ifdef PARSEDEBUG
204+ printf ("transformUsingClause- transform %s" ,nodeToString (qual ));
205+ #endif
206+
207+ }
208+
209+ #ifdef PARSEDEBUG
210+ printf (" to %s\n" ,nodeToString (expr ));
211+ #endif
212+ }
213+ return ((Node * )transformExpr (pstate , (Node * )expr ,EXPR_COLUMN_FIRST ));
214+ }
215+ #endif
216+
217+ char *
218+ transformTableEntry (ParseState * pstate ,RangeVar * r )
219+ {
220+ RelExpr * baserel = r -> relExpr ;
221+ char * relname = baserel -> relname ;
222+ char * refname = r -> name ;
223+ RangeTblEntry * rte ;
224+
225+ if (refname == NULL )
226+ refname = relname ;
227+
228+ /*
229+ * marks this entry to indicate it comes from the FROM clause. In
230+ * SQL, the target list can only refer to range variables
231+ * specified in the from clause but we follow the more powerful
232+ * POSTQUEL semantics and automatically generate the range
233+ * variable if not specified. However there are times we need to
234+ * know whether the entries are legitimate.
235+ *
236+ * eg. select * from foo f where f.x = 1; will generate wrong answer
237+ * if we expand * to foo.x.
238+ */
239+
240+ rte = addRangeTableEntry (pstate ,relname ,refname ,baserel -> inh , TRUE);
241+
242+ return refname ;
243+ }
244+
101245/*
102246 * parseFromClause -
103247 * turns the table references specified in the from-clause into a
@@ -106,23 +250,23 @@ transformWhereClause(ParseState *pstate, Node *a_expr)
106250 * allow references to relations not specified in the from-clause. We
107251 * also allow now as an extension.)
108252 *
253+ * The FROM clause can now contain JoinExpr nodes, which contain parsing info
254+ * for inner and outer joins. The USING clause must be expanded into a qualification
255+ * for an inner join at least, since that is compatible with the old syntax.
256+ * Not sure yet how to handle outer joins, but it will become clear eventually?
257+ * - thomas 1998-12-16
109258 */
110259static void
111- parseFromClause (ParseState * pstate ,List * frmList )
260+ parseFromClause (ParseState * pstate ,List * frmList , Node * * qual )
112261{
113262List * fl ;
114263
264+ if (qual != NULL )
265+ * qual = NULL ;
266+
115267foreach (fl ,frmList )
116268{
117- RangeVar * r = lfirst (fl );
118- RelExpr * baserel = r -> relExpr ;
119- char * relname = baserel -> relname ;
120- char * refname = r -> name ;
121- RangeTblEntry * rte ;
122-
123- if (refname == NULL )
124- refname = relname ;
125-
269+ Node * n = lfirst (fl );
126270/*
127271 * marks this entry to indicate it comes from the FROM clause. In
128272 * SQL, the target list can only refer to range variables
@@ -134,7 +278,65 @@ parseFromClause(ParseState *pstate, List *frmList)
134278 * eg. select * from foo f where f.x = 1; will generate wrong answer
135279 * if we expand * to foo.x.
136280 */
137- rte = addRangeTableEntry (pstate ,relname ,refname ,baserel -> inh , TRUE);
281+ if (IsA (n ,RangeVar ))
282+ {
283+ transformTableEntry (pstate , (RangeVar * )n );
284+ }
285+ else if (IsA (n ,JoinExpr ))
286+ {
287+ JoinExpr * j = (JoinExpr * )n ;
288+ char * lname = transformTableEntry (pstate , (RangeVar * )j -> larg );
289+ char * rname ;
290+
291+ if (IsA ((Node * )j -> rarg ,RangeVar ))
292+ rname = transformTableEntry (pstate , (RangeVar * )j -> rarg );
293+ else
294+ elog (ERROR ,"Nested JOINs are not yet supported" );
295+
296+ #ifdef ENABLE_OUTER_JOINS
297+ if (j -> jointype == INNER_P )
298+ {
299+ /* This is an inner join, so rip apart the join node
300+ * and transform into a traditional FROM list.
301+ * NATURAL JOIN and USING clauses both change the shape
302+ * of the result. Need to generate a list of result columns
303+ * to use for target list expansion and validation.
304+ * Not doing this yet though!
305+ */
306+ if (IsA (j -> quals ,List ))
307+ j -> quals = lcons (transformUsingClause (pstate , (List * )j -> quals ,lname ,rname ),NIL );
308+
309+ Assert (qual != NULL );
310+
311+ if (* qual == NULL )
312+ * qual = lfirst (j -> quals );
313+ else
314+ elog (ERROR ,"Multiple JOIN/ON clauses not handled (internal error)" );
315+
316+ /* if we are transforming this node back into a FROM list,
317+ * then we will need to replace the node with two nodes.
318+ * Will need access to the previous list item to change
319+ * the link pointer to reference these new nodes.
320+ * Try accumulating and returning a new list.
321+ * - thomas 1999-01-08
322+ * Not doing this yet though!
323+ */
324+
325+ }
326+ else if ((j -> jointype == LEFT )
327+ || (j -> jointype == RIGHT )
328+ || (j -> jointype == FULL ))
329+ elog (ERROR ,"OUTER JOIN is not implemented" );
330+ else
331+ elog (ERROR ,"Unrecognized JOIN clause; tag is %d (internal error)" ,
332+ j -> jointype );
333+ #else
334+ elog (ERROR ,"JOIN expressions are not yet implemented" );
335+ #endif
336+ }
337+ else
338+ elog (ERROR ,"parseFromClause: unexpected FROM clause node (internal error)"
339+ "\n\t%s" ,nodeToString (n ));
138340}
139341}
140342