7
7
*
8
8
*
9
9
* 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 $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
26
26
#include "parser/parse_relation.h"
27
27
#include "parser/parse_target.h"
28
28
#include "parser/parse_coerce.h"
29
+ #include "nodes/print.h"
29
30
31
+ #include "parse.h"
30
32
31
33
32
34
#define ORDER_CLAUSE 0
@@ -37,7 +39,15 @@ static char *clauseText[] = {"ORDER", "GROUP"};
37
39
static TargetEntry *
38
40
findTargetlistEntry (ParseState * pstate , Node * node , List * tlist , int clause );
39
41
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 );
41
51
42
52
43
53
/*
@@ -46,18 +56,18 @@ static void parseFromClause(ParseState *pstate, List *frmList);
46
56
* from_clause.
47
57
*/
48
58
void
49
- makeRangeTable (ParseState * pstate , char * relname , List * frmList )
59
+ makeRangeTable (ParseState * pstate , char * relname , List * frmList , Node * * qual )
50
60
{
51
61
RangeTblEntry * rte ;
52
62
int sublevels_up ;
53
63
54
- parseFromClause (pstate , frmList );
64
+ parseFromClause (pstate , frmList , qual );
55
65
56
66
if (relname == NULL )
57
67
return ;
58
68
59
- if (refnameRangeTablePosn (pstate , relname , & sublevels_up ) == 0 ||
60
- sublevels_up != 0 )
69
+ if (( refnameRangeTablePosn (pstate , relname , & sublevels_up ) == 0 )
70
+ || ( sublevels_up != 0 ) )
61
71
rte = addRangeTableEntry (pstate , relname , relname , FALSE, FALSE);
62
72
else
63
73
rte = refnameRangeTableEntry (pstate , relname );
@@ -77,17 +87,35 @@ makeRangeTable(ParseState *pstate, char *relname, List *frmList)
77
87
* transformWhereClause -
78
88
* transforms the qualification and make sure it is of type Boolean
79
89
*
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
80
93
*/
81
94
Node *
82
- transformWhereClause (ParseState * pstate , Node * a_expr )
95
+ transformWhereClause (ParseState * pstate , Node * a_expr , Node * o_expr )
83
96
{
97
+ A_Expr * expr ;
84
98
Node * qual ;
85
99
86
- if (a_expr == NULL )
100
+ if (( a_expr == NULL ) && ( o_expr == NULL ) )
87
101
return NULL ; /* no qualifiers */
88
102
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
+
89
117
pstate -> p_in_where_clause = true;
90
- qual = transformExpr (pstate , a_expr , EXPR_COLUMN_FIRST );
118
+ qual = transformExpr (pstate , ( Node * ) expr , EXPR_COLUMN_FIRST );
91
119
pstate -> p_in_where_clause = false;
92
120
93
121
if (exprType (qual ) != BOOLOID )
@@ -98,6 +126,122 @@ transformWhereClause(ParseState *pstate, Node *a_expr)
98
126
return qual ;
99
127
}
100
128
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
+
101
245
/*
102
246
* parseFromClause -
103
247
* turns the table references specified in the from-clause into a
@@ -106,23 +250,23 @@ transformWhereClause(ParseState *pstate, Node *a_expr)
106
250
* allow references to relations not specified in the from-clause. We
107
251
* also allow now as an extension.)
108
252
*
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
109
258
*/
110
259
static void
111
- parseFromClause (ParseState * pstate , List * frmList )
260
+ parseFromClause (ParseState * pstate , List * frmList , Node * * qual )
112
261
{
113
262
List * fl ;
114
263
264
+ if (qual != NULL )
265
+ * qual = NULL ;
266
+
115
267
foreach (fl , frmList )
116
268
{
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 );
126
270
/*
127
271
* marks this entry to indicate it comes from the FROM clause. In
128
272
* SQL, the target list can only refer to range variables
@@ -134,7 +278,65 @@ parseFromClause(ParseState *pstate, List *frmList)
134
278
* eg. select * from foo f where f.x = 1; will generate wrong answer
135
279
* if we expand * to foo.x.
136
280
*/
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 ));
138
340
}
139
341
}
140
342
0 commit comments