aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_clause.c
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>1997-11-25 22:07:18 +0000
committerBruce Momjian <bruce@momjian.us>1997-11-25 22:07:18 +0000
commit4a5b781d71b61887fd312112d75979f250bf723f (patch)
tree315803e512d9e978301311a92866a8b6f17a592d /src/backend/parser/parse_clause.c
parent3aff4011c735faa747ce94d20da6fd9f85144955 (diff)
downloadpostgresql-4a5b781d71b61887fd312112d75979f250bf723f.tar.gz
postgresql-4a5b781d71b61887fd312112d75979f250bf723f.zip
Break parser functions into smaller files, group together.
Diffstat (limited to 'src/backend/parser/parse_clause.c')
-rw-r--r--src/backend/parser/parse_clause.c407
1 files changed, 407 insertions, 0 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
new file mode 100644
index 00000000000..8e08e00a2ea
--- /dev/null
+++ b/src/backend/parser/parse_clause.c
@@ -0,0 +1,407 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_clause.c--
+ * handle clauses in parser
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.1 1997/11/25 22:05:35 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "postgres.h"
+#include "access/heapam.h"
+#include "parser/parse_clause.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_node.h"
+#include "parser/parse_oper.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_target.h"
+#include "catalog/pg_type.h"
+
+#ifdef 0
+#include "nodes/nodes.h"
+#include "nodes/params.h"
+#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+#include "nodes/relation.h"
+#include "parse.h" /* for AND, OR, etc. */
+#include "catalog/pg_aggregate.h"
+#include "catalog/pg_proc.h"
+#include "utils/elog.h"
+#include "utils/builtins.h" /* namecmp(), textout() */
+#include "utils/lsyscache.h"
+#include "utils/palloc.h"
+#include "utils/mcxt.h"
+#include "utils/syscache.h"
+#include "utils/acl.h"
+#include "nodes/makefuncs.h" /* for makeResdom(), etc. */
+#include "nodes/nodeFuncs.h"
+#include "commands/sequence.h"
+
+#include "optimizer/clauses.h"
+
+#include "miscadmin.h"
+
+#include "port-protos.h" /* strdup() */
+#endif
+
+/*
+ * parseFromClause -
+ * turns the table references specified in the from-clause into a
+ * range table. The range table may grow as we transform the expressions
+ * in the target list. (Note that this happens because in POSTQUEL, we
+ * allow references to relations not specified in the from-clause. We
+ * also allow that in our POST-SQL)
+ *
+ */
+void
+parseFromClause(ParseState *pstate, List *frmList)
+{
+ List *fl;
+
+ foreach(fl, frmList)
+ {
+ RangeVar *r = lfirst(fl);
+ RelExpr *baserel = r->relExpr;
+ char *relname = baserel->relname;
+ char *refname = r->name;
+ RangeTblEntry *rte;
+
+ if (refname == NULL)
+ refname = relname;
+
+ /*
+ * marks this entry to indicate it comes from the FROM clause. In
+ * SQL, the target list can only refer to range variables
+ * specified in the from clause but we follow the more powerful
+ * POSTQUEL semantics and automatically generate the range
+ * variable if not specified. However there are times we need to
+ * know whether the entries are legitimate.
+ *
+ * eg. select * from foo f where f.x = 1; will generate wrong answer
+ * if we expand * to foo.x.
+ */
+ rte = addRangeTableEntry(pstate, relname, refname, baserel->inh, TRUE);
+ }
+}
+
+/*
+ * makeRangeTable -
+ * make a range table with the specified relation (optional) and the
+ * from-clause.
+ */
+void
+makeRangeTable(ParseState *pstate, char *relname, List *frmList)
+{
+ RangeTblEntry *rte;
+
+ parseFromClause(pstate, frmList);
+
+ if (relname == NULL)
+ return;
+
+ if (refnameRangeTablePosn(pstate->p_rtable, relname) < 1)
+ rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE);
+ else
+ rte = refnameRangeTableEntry(pstate->p_rtable, relname);
+
+ pstate->p_target_rangetblentry = rte;
+ Assert(pstate->p_target_relation == NULL);
+ pstate->p_target_relation = heap_open(rte->relid);
+ Assert(pstate->p_target_relation != NULL);
+ /* will close relation later */
+}
+
+/*****************************************************************************
+ *
+ * Where Clause
+ *
+ *****************************************************************************/
+
+/*
+ * transformWhereClause -
+ * transforms the qualification and make sure it is of type Boolean
+ *
+ */
+Node *
+transformWhereClause(ParseState *pstate, Node *a_expr)
+{
+ Node *qual;
+
+ if (a_expr == NULL)
+ return (Node *) NULL; /* no qualifiers */
+
+ pstate->p_in_where_clause = true;
+ qual = transformExpr(pstate, a_expr, EXPR_COLUMN_FIRST);
+ pstate->p_in_where_clause = false;
+ if (exprType(qual) != BOOLOID)
+ {
+ elog(WARN,
+ "where clause must return type bool, not %s",
+ typeidTypeName(exprType(qual)));
+ }
+ return qual;
+}
+
+/*****************************************************************************
+ *
+ * Sort Clause
+ *
+ *****************************************************************************/
+
+/*
+ * find_targetlist_entry -
+ * returns the Resdom in the target list matching the specified varname
+ * and range
+ *
+ */
+TargetEntry *
+find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist)
+{
+ List *i;
+ int real_rtable_pos = 0,
+ target_pos = 0;
+ TargetEntry *target_result = NULL;
+
+ if (sortgroupby->range)
+ real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable,
+ sortgroupby->range);
+
+ foreach(i, tlist)
+ {
+ TargetEntry *target = (TargetEntry *) lfirst(i);
+ Resdom *resnode = target->resdom;
+ Var *var = (Var *) target->expr;
+ char *resname = resnode->resname;
+ int test_rtable_pos = var->varno;
+
+#ifdef PARSEDEBUG
+ printf("find_targetlist_entry- target name is %s, position %d, resno %d\n",
+ (sortgroupby->name ? sortgroupby->name : "(null)"), target_pos + 1, sortgroupby->resno);
+#endif
+
+ if (!sortgroupby->name)
+ {
+ if (sortgroupby->resno == ++target_pos)
+ {
+ target_result = target;
+ break;
+ }
+ }
+ else
+ {
+ if (!strcmp(resname, sortgroupby->name))
+ {
+ if (sortgroupby->range)
+ {
+ if (real_rtable_pos == test_rtable_pos)
+ {
+ if (target_result != NULL)
+ elog(WARN, "Order/Group By '%s' is ambiguous", sortgroupby->name);
+ else
+ target_result = target;
+ }
+ }
+ else
+ {
+ if (target_result != NULL)
+ elog(WARN, "Order/Group By '%s' is ambiguous", sortgroupby->name);
+ else
+ target_result = target;
+ }
+ }
+ }
+ }
+ return target_result;
+}
+
+/*
+ * transformGroupClause -
+ * transform a Group By clause
+ *
+ */
+List *
+transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
+{
+ List *glist = NIL,
+ *gl = NIL;
+
+ while (grouplist != NIL)
+ {
+ GroupClause *grpcl = makeNode(GroupClause);
+ TargetEntry *restarget;
+ Resdom *resdom;
+
+ restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist);
+
+ if (restarget == NULL)
+ elog(WARN, "The field being grouped by must appear in the target list");
+
+ grpcl->entry = restarget;
+ resdom = restarget->resdom;
+ grpcl->grpOpoid = oprid(oper("<",
+ resdom->restype,
+ resdom->restype, false));
+ if (glist == NIL)
+ gl = glist = lcons(grpcl, NIL);
+ else
+ {
+ List *i;
+
+ foreach (i, glist)
+ {
+ GroupClause *gcl = (GroupClause *) lfirst (i);
+
+ if ( gcl->entry == grpcl->entry )
+ break;
+ }
+ if ( i == NIL ) /* not in grouplist already */
+ {
+ lnext(gl) = lcons(grpcl, NIL);
+ gl = lnext(gl);
+ }
+ else
+ pfree (grpcl); /* get rid of this */
+ }
+ grouplist = lnext(grouplist);
+ }
+
+ return glist;
+}
+
+/*
+ * transformSortClause -
+ * transform an Order By clause
+ *
+ */
+List *
+transformSortClause(ParseState *pstate,
+ List *orderlist, List *targetlist,
+ char *uniqueFlag)
+{
+ List *sortlist = NIL;
+ List *s = NIL;
+
+ while (orderlist != NIL)
+ {
+ SortGroupBy *sortby = lfirst(orderlist);
+ SortClause *sortcl = makeNode(SortClause);
+ TargetEntry *restarget;
+ Resdom *resdom;
+
+ restarget = find_targetlist_entry(pstate, sortby, targetlist);
+ if (restarget == NULL)
+ elog(WARN, "The field being ordered by must appear in the target list");
+
+ sortcl->resdom = resdom = restarget->resdom;
+ sortcl->opoid = oprid(oper(sortby->useOp,
+ resdom->restype,
+ resdom->restype, false));
+ if (sortlist == NIL)
+ {
+ s = sortlist = lcons(sortcl, NIL);
+ }
+ else
+ {
+ List *i;
+
+ foreach (i, sortlist)
+ {
+ SortClause *scl = (SortClause *) lfirst (i);
+
+ if ( scl->resdom == sortcl->resdom )
+ break;
+ }
+ if ( i == NIL ) /* not in sortlist already */
+ {
+ lnext(s) = lcons(sortcl, NIL);
+ s = lnext(s);
+ }
+ else
+ pfree (sortcl); /* get rid of this */
+ }
+ orderlist = lnext(orderlist);
+ }
+
+ if (uniqueFlag)
+ {
+ List *i;
+
+ if (uniqueFlag[0] == '*')
+ {
+
+ /*
+ * concatenate all elements from target list that are not
+ * already in the sortby list
+ */
+ foreach(i, targetlist)
+ {
+ TargetEntry *tlelt = (TargetEntry *) lfirst(i);
+
+ s = sortlist;
+ while (s != NIL)
+ {
+ SortClause *sortcl = lfirst(s);
+
+ if (sortcl->resdom == tlelt->resdom)
+ break;
+ s = lnext(s);
+ }
+ if (s == NIL)
+ {
+ /* not a member of the sortclauses yet */
+ SortClause *sortcl = makeNode(SortClause);
+
+ sortcl->resdom = tlelt->resdom;
+ sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
+
+ sortlist = lappend(sortlist, sortcl);
+ }
+ }
+ }
+ else
+ {
+ TargetEntry *tlelt = NULL;
+ char *uniqueAttrName = uniqueFlag;
+
+ /* only create sort clause with the specified unique attribute */
+ foreach(i, targetlist)
+ {
+ tlelt = (TargetEntry *) lfirst(i);
+ if (strcmp(tlelt->resdom->resname, uniqueAttrName) == 0)
+ break;
+ }
+ if (i == NIL)
+ {
+ elog(WARN, "The field specified in the UNIQUE ON clause is not in the targetlist");
+ }
+ s = sortlist;
+ foreach(s, sortlist)
+ {
+ SortClause *sortcl = lfirst(s);
+
+ if (sortcl->resdom == tlelt->resdom)
+ break;
+ }
+ if (s == NIL)
+ {
+ /* not a member of the sortclauses yet */
+ SortClause *sortcl = makeNode(SortClause);
+
+ sortcl->resdom = tlelt->resdom;
+ sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
+
+ sortlist = lappend(sortlist, sortcl);
+ }
+ }
+
+ }
+
+ return sortlist;
+}