1 /*-------------------------------------------------------------------------
4 * handle clauses in parser
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.41 1999/07/17 20:17:23 momjian Exp $
12 *-------------------------------------------------------------------------
16 #include "access/heapam.h"
17 #include "nodes/relation.h"
19 #include "parser/parse_clause.h"
20 #include "parser/parse_coerce.h"
21 #include "parser/parse_expr.h"
22 #include "parser/parse_oper.h"
23 #include "parser/parse_relation.h"
24 #include "parser/parse_target.h"
27 #define ORDER_CLAUSE 0
28 #define GROUP_CLAUSE 1
30 static char *clauseText[] = {"ORDER", "GROUP"};
33 findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause);
35 static void parseFromClause(ParseState *pstate, List *frmList, Node **qual);
37 #ifdef ENABLE_OUTER_JOINS
38 Node *transformUsingClause(ParseState *pstate, List *onList, char *lname, char *rname);
42 static char *transformTableEntry(ParseState *pstate, RangeVar *r);
47 * make a range table with the specified relation (optional) and the
51 makeRangeTable(ParseState *pstate, char *relname, List *frmList, Node **qual)
56 parseFromClause(pstate, frmList, qual);
61 if ((refnameRangeTablePosn(pstate, relname, &sublevels_up) == 0)
62 || (sublevels_up != 0))
63 rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE);
65 rte = refnameRangeTableEntry(pstate, relname);
67 /* This could only happen for multi-action rules */
68 if (pstate->p_target_relation != NULL)
69 heap_close(pstate->p_target_relation);
71 pstate->p_target_rangetblentry = rte;
72 pstate->p_target_relation = heap_open(rte->relid);
73 /* will close relation later */
77 * transformWhereClause -
78 * transforms the qualification and make sure it is of type Boolean
80 * Now accept an additional argument, which is a qualification derived
81 * from the JOIN/ON or JOIN/USING syntax.
85 transformWhereClause(ParseState *pstate, Node *a_expr, Node *o_expr)
90 if ((a_expr == NULL) && (o_expr == NULL))
91 return NULL; /* no qualifiers */
93 if ((a_expr != NULL) && (o_expr != NULL))
95 A_Expr *a = makeNode(A_Expr);
103 else if (o_expr != NULL)
104 expr = (A_Expr *) o_expr;
106 expr = (A_Expr *) a_expr;
108 pstate->p_in_where_clause = true;
109 qual = transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST);
110 pstate->p_in_where_clause = false;
112 if (exprType(qual) != BOOLOID)
114 elog(ERROR, "WHERE clause must return type bool, not type %s",
115 typeidTypeName(exprType(qual)));
122 makeAttr(char *relname, char *attname)
124 Attr *a = makeNode(Attr);
126 a->relname = relname;
128 a->attrs = lcons(makeString(attname), NIL);
129 a->indirection = NULL;
135 #ifdef ENABLE_OUTER_JOINS
136 /* transformUsingClause()
137 * Take an ON or USING clause from a join expression and expand if necessary.
140 transformUsingClause(ParseState *pstate, List *onList, char *lname, char *rname)
151 * Ident node means it is just a column name from a real USING
154 if (IsA(qual, Ident))
156 Ident *i = (Ident *) qual;
157 Attr *lattr = makeAttr(lname, i->name);
158 Attr *rattr = makeAttr(rname, i->name);
159 A_Expr *e = makeNode(A_Expr);
163 e->lexpr = (Node *) lattr;
164 e->rexpr = (Node *) rattr;
168 A_Expr *a = makeNode(A_Expr);
172 a->lexpr = (Node *) expr;
173 a->rexpr = (Node *) e;
180 /* otherwise, we have an expression from an ON clause... */
185 A_Expr *a = makeNode(A_Expr);
189 a->lexpr = (Node *) expr;
190 a->rexpr = (Node *) qual;
194 expr = (A_Expr *) qual;
197 return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST));
203 transformTableEntry(ParseState *pstate, RangeVar *r)
205 RelExpr *baserel = r->relExpr;
206 char *relname = baserel->relname;
207 char *refname = r->name;
214 * marks this entry to indicate it comes from the FROM clause. In SQL,
215 * the target list can only refer to range variables specified in the
216 * from clause but we follow the more powerful POSTQUEL semantics and
217 * automatically generate the range variable if not specified. However
218 * there are times we need to know whether the entries are legitimate.
220 * eg. select * from foo f where f.x = 1; will generate wrong answer if
221 * we expand * to foo.x.
224 rte = addRangeTableEntry(pstate, relname, refname, baserel->inh, TRUE);
231 * turns the table references specified in the from-clause into a
232 * range table. The range table may grow as we transform the expressions
233 * in the target list. (Note that this happens because in POSTQUEL, we
234 * allow references to relations not specified in the from-clause. We
235 * also allow now as an extension.)
237 * The FROM clause can now contain JoinExpr nodes, which contain parsing info
238 * for inner and outer joins. The USING clause must be expanded into a qualification
239 * for an inner join at least, since that is compatible with the old syntax.
240 * Not sure yet how to handle outer joins, but it will become clear eventually?
241 * - thomas 1998-12-16
244 parseFromClause(ParseState *pstate, List *frmList, Node **qual)
253 Node *n = lfirst(fl);
256 * marks this entry to indicate it comes from the FROM clause. In
257 * SQL, the target list can only refer to range variables
258 * specified in the from clause but we follow the more powerful
259 * POSTQUEL semantics and automatically generate the range
260 * variable if not specified. However there are times we need to
261 * know whether the entries are legitimate.
263 * eg. select * from foo f where f.x = 1; will generate wrong answer
264 * if we expand * to foo.x.
266 if (IsA(n, RangeVar))
267 transformTableEntry(pstate, (RangeVar *) n);
268 else if (IsA(n, JoinExpr))
270 JoinExpr *j = (JoinExpr *) n;
272 #ifdef ENABLE_OUTER_JOINS
273 char *lname = transformTableEntry(pstate, (RangeVar *) j->larg);
278 if (IsA((Node *) j->rarg, RangeVar))
279 rname = transformTableEntry(pstate, (RangeVar *) j->rarg);
281 elog(ERROR, "Nested JOINs are not yet supported");
283 #ifdef ENABLE_OUTER_JOINS
284 if (j->jointype == INNER_P)
288 * This is an inner join, so rip apart the join node and
289 * transform into a traditional FROM list. NATURAL JOIN
290 * and USING clauses both change the shape of the result.
291 * Need to generate a list of result columns to use for
292 * target list expansion and validation. Not doing this
295 if (IsA(j->quals, List))
296 j->quals = lcons(transformUsingClause(pstate, (List *) j->quals, lname, rname), NIL);
298 Assert(qual != NULL);
301 *qual = lfirst(j->quals);
303 elog(ERROR, "Multiple JOIN/ON clauses not handled (internal error)");
306 * if we are transforming this node back into a FROM list,
307 * then we will need to replace the node with two nodes.
308 * Will need access to the previous list item to change
309 * the link pointer to reference these new nodes. Try
310 * accumulating and returning a new list. - thomas
311 * 1999-01-08 Not doing this yet though!
315 else if ((j->jointype == LEFT)
316 || (j->jointype == RIGHT)
317 || (j->jointype == FULL))
318 elog(ERROR, "OUTER JOIN is not implemented");
320 elog(ERROR, "Unrecognized JOIN clause; tag is %d (internal error)",
323 elog(ERROR, "JOIN expressions are not yet implemented");
327 elog(ERROR, "parseFromClause: unexpected FROM clause node (internal error)"
328 "\n\t%s", nodeToString(n));
333 * findTargetlistEntry -
334 * returns the Resdom in the target list matching the specified varname
335 * and range. If none exist one is created.
337 * Rewritten for ver 6.4 to handle expressions in the GROUP/ORDER BY clauses.
338 * - daveh@insightdist.com 1998-07-31
342 findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
348 TargetEntry *target_result = NULL;
350 char *relname = NULL;
355 /* Pull out some values before looping thru target list */
356 switch (nodeTag(node))
359 relname = ((Attr *) node)->relname;
360 val = (Value *) lfirst(((Attr *) node)->attrs);
362 rtable_pos = refnameRangeTablePosn(pstate, relname, NULL);
363 relCnt = length(pstate->p_rtable);
367 name = ((Ident *) node)->name;
368 relCnt = length(pstate->p_rtable);
372 val = &((A_Const *) node)->val;
374 if (nodeTag(val) != T_Integer)
375 elog(ERROR, "Illegal Constant in %s BY", clauseText[clause]);
376 target_pos = intVal(val);
381 expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
385 elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node));
389 * Loop through target entries and try to match to node
393 TargetEntry *target = (TargetEntry *) lfirst(l);
394 Resdom *resnode = target->resdom;
395 Var *var = (Var *) target->expr;
396 char *resname = resnode->resname;
397 int test_rtable_pos = var->varno;
401 switch (nodeTag(node))
404 if (strcmp(resname, name) == 0 && rtable_pos == test_rtable_pos)
408 * Check for only 1 table & ORDER BY -ambiguity does
411 if (clause == ORDER_CLAUSE && relCnt == 1)
414 if (target_result != NULL)
415 elog(ERROR, "%s BY '%s' is ambiguous", clauseText[clause], name);
417 target_result = target;
418 /* Stay in loop to check for ambiguity */
423 if (strcmp(resname, name) == 0)
427 * Check for only 1 table & ORDER BY -ambiguity does
430 if (clause == ORDER_CLAUSE && relCnt == 1)
433 if (target_result != NULL)
434 elog(ERROR, "%s BY '%s' is ambiguous", clauseText[clause], name);
436 target_result = target;
437 /* Stay in loop to check for ambiguity */
442 if (target_pos == targetlist_pos)
444 /* Can't be ambigious and we got what we came for */
451 if (equal(expr, target->expr))
455 * Check for only 1 table & ORDER BY -ambiguity does
458 if (clause == ORDER_CLAUSE)
461 if (target_result != NULL)
462 elog(ERROR, "GROUP BY has ambiguous expression");
464 target_result = target;
469 elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node));
474 * If no matches, construct a new target entry which is appended to
475 * the end of the target list. This target is set to be resjunk =
476 * TRUE so that it will not be projected into the final tuple.
478 if (target_result == NULL)
480 switch (nodeTag(node))
483 target_result = MakeTargetEntryIdent(pstate, node,
484 &((Attr *) node)->relname, NULL,
485 ((Attr *) node)->relname, true);
486 lappend(tlist, target_result);
490 target_result = MakeTargetEntryIdent(pstate, node,
491 &((Ident *) node)->name, NULL,
492 ((Ident *) node)->name, true);
493 lappend(tlist, target_result);
499 * If we got this far, then must have been an out-of-range
502 elog(ERROR, "%s BY position %d is not in target list", clauseText[clause], target_pos);
507 target_result = MakeTargetEntryExpr(pstate, "resjunk", expr, false, true);
508 lappend(tlist, target_result);
512 elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node));
517 return target_result;
524 * transformGroupClause -
525 * transform a Group By clause
529 transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
534 while (grouplist != NIL)
536 GroupClause *grpcl = makeNode(GroupClause);
537 TargetEntry *restarget;
540 restarget = findTargetlistEntry(pstate, lfirst(grouplist), targetlist, GROUP_CLAUSE);
542 resdom = restarget->resdom;
543 grpcl->grpOpoid = oprid(oper("<",
545 resdom->restype, false));
548 int groupref = length(glist) + 1;
550 restarget->resdom->resgroupref = groupref;
551 grpcl->tleGroupref = groupref;
553 gl = glist = lcons(grpcl, NIL);
561 GroupClause *gcl = (GroupClause *) lfirst(i);
563 if (equal(get_groupclause_expr(gcl, targetlist),
567 if (i == NIL) /* not in grouplist already */
569 int groupref = length(glist) + 1;
571 restarget->resdom->resgroupref = groupref;
572 grpcl->tleGroupref = groupref;
574 lnext(gl) = lcons(grpcl, NIL);
578 pfree(grpcl); /* get rid of this */
580 grouplist = lnext(grouplist);
587 * transformSortClause -
588 * transform an Order By clause
592 transformSortClause(ParseState *pstate,
600 while (orderlist != NIL)
602 SortGroupBy *sortby = lfirst(orderlist);
603 SortClause *sortcl = makeNode(SortClause);
604 TargetEntry *restarget;
607 restarget = findTargetlistEntry(pstate, sortby->node, targetlist, ORDER_CLAUSE);
609 sortcl->resdom = resdom = restarget->resdom;
612 * if we have InvalidOid, then this is a NULL field and don't need
615 if (resdom->restype == InvalidOid)
616 resdom->restype = INT4OID;
618 sortcl->opoid = oprid(oper(sortby->useOp,
620 resdom->restype, false));
622 s = sortlist = lcons(sortcl, NIL);
629 SortClause *scl = (SortClause *) lfirst(i);
631 if (scl->resdom == sortcl->resdom)
634 if (i == NIL) /* not in sortlist already */
636 lnext(s) = lcons(sortcl, NIL);
640 pfree(sortcl); /* get rid of this */
642 orderlist = lnext(orderlist);
649 if (uniqueFlag[0] == '*')
653 * concatenate all elements from target list that are not
654 * already in the sortby list
656 foreach(i, targetlist)
658 TargetEntry *tlelt = (TargetEntry *) lfirst(i);
663 SortClause *sortcl = lfirst(s);
666 * We use equal() here because we are called for UNION
667 * from the optimizer, and at that point, the sort
668 * clause resdom pointers don't match the target list
671 if (equal(sortcl->resdom, tlelt->resdom))
677 /* not a member of the sortclauses yet */
678 SortClause *sortcl = makeNode(SortClause);
680 if (tlelt->resdom->restype == InvalidOid)
681 tlelt->resdom->restype = INT4OID;
683 sortcl->resdom = tlelt->resdom;
684 sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
686 sortlist = lappend(sortlist, sortcl);
692 TargetEntry *tlelt = NULL;
693 char *uniqueAttrName = uniqueFlag;
695 /* only create sort clause with the specified unique attribute */
696 foreach(i, targetlist)
698 tlelt = (TargetEntry *) lfirst(i);
699 if (strcmp(tlelt->resdom->resname, uniqueAttrName) == 0)
703 elog(ERROR, "All fields in the UNIQUE ON clause must appear in the target list");
707 SortClause *sortcl = lfirst(s);
709 if (sortcl->resdom == tlelt->resdom)
714 /* not a member of the sortclauses yet */
715 SortClause *sortcl = makeNode(SortClause);
717 sortcl->resdom = tlelt->resdom;
718 sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
720 sortlist = lappend(sortlist, sortcl);
728 /* transformUnionClause()
729 * Transform a UNION clause.
730 * Note that the union clause is actually a fully-formed select structure.
731 * So, it is evaluated as a select, then the resulting target fields
732 * are matched up to ensure correct types in the results.
733 * The select clause parsing is done recursively, so the unions are evaluated
734 * right-to-left. One might want to look at all columns from all clauses before
735 * trying to coerce, but unless we keep track of the call depth we won't know
736 * when to do this because of the recursion.
737 * Let's just try matching in pairs for now (right to left) and see if it works.
738 * - thomas 1998-05-22
742 transformUnionClause(List *unionClause, List *targetlist)
744 List *union_list = NIL;
751 qlist = parse_analyze(unionClause, NULL);
753 foreach(qlist_item, qlist)
755 Query *query = (Query *) lfirst(qlist_item);
756 List *prev_target = targetlist;
761 foreach(prev_target, targetlist)
762 if (!((TargetEntry *) lfirst(prev_target))->resdom->resjunk)
765 foreach(next_target, query->targetList)
766 if (!((TargetEntry *) lfirst(next_target))->resdom->resjunk)
769 if (prev_len != next_len)
770 elog(ERROR, "Each UNION clause must have the same number of columns");
772 foreach(next_target, query->targetList)
777 otype = ((TargetEntry *) lfirst(prev_target))->resdom->restype;
778 itype = ((TargetEntry *) lfirst(next_target))->resdom->restype;
780 /* one or both is a NULL column? then don't convert... */
781 if (otype == InvalidOid)
783 /* propagate a known type forward, if available */
784 if (itype != InvalidOid)
785 ((TargetEntry *) lfirst(prev_target))->resdom->restype = itype;
789 ((TargetEntry *) lfirst(prev_target))->resdom->restype = UNKNOWNOID;
790 ((TargetEntry *) lfirst(next_target))->resdom->restype = UNKNOWNOID;
794 else if (itype == InvalidOid)
797 /* they don't match in type? then convert... */
798 else if (itype != otype)
802 expr = ((TargetEntry *) lfirst(next_target))->expr;
803 expr = CoerceTargetExpr(NULL, expr, itype, otype);
806 elog(ERROR, "Unable to transform %s to %s"
807 "\n\tEach UNION clause must have compatible target types",
808 typeidTypeName(itype),
809 typeidTypeName(otype));
811 ((TargetEntry *) lfirst(next_target))->expr = expr;
812 ((TargetEntry *) lfirst(next_target))->resdom->restype = otype;
815 /* both are UNKNOWN? then evaluate as text... */
816 else if (itype == UNKNOWNOID)
818 ((TargetEntry *) lfirst(next_target))->resdom->restype = TEXTOID;
819 ((TargetEntry *) lfirst(prev_target))->resdom->restype = TEXTOID;
821 prev_target = lnext(prev_target);
823 union_list = lappend(union_list, query);