parse_agg.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:10k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * parse_agg.c
  4.  *   handle aggregates in parser
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.23 1999/06/21 01:18:02 tgl Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "postgres.h"
  18. #include "access/heapam.h"
  19. #include "catalog/pg_aggregate.h"
  20. #include "catalog/pg_type.h"
  21. #include "nodes/nodeFuncs.h"
  22. #include "nodes/primnodes.h"
  23. #include "nodes/relation.h"
  24. #include "optimizer/clauses.h"
  25. #include "parser/parse_agg.h"
  26. #include "parser/parse_expr.h"
  27. #include "parser/parse_node.h"
  28. #include "parser/parse_target.h"
  29. #include "parser/parse_coerce.h"
  30. #include "utils/syscache.h"
  31. #include "utils/lsyscache.h"
  32. static bool contain_agg_clause(Node *clause);
  33. static bool contain_agg_clause_walker(Node *node, void *context);
  34. static bool exprIsAggOrGroupCol(Node *expr, List *groupClauses);
  35. static bool exprIsAggOrGroupCol_walker(Node *node, List *groupClauses);
  36. /*
  37.  * contain_agg_clause
  38.  *   Recursively find aggref nodes within a clause.
  39.  *
  40.  *   Returns true if any aggregate found.
  41.  *
  42.  * NOTE: we assume that the given clause has been transformed suitably for
  43.  * parser output.  This means we can use the planner's expression_tree_walker.
  44.  */
  45. static bool
  46. contain_agg_clause(Node *clause)
  47. {
  48. return contain_agg_clause_walker(clause, NULL);
  49. }
  50. static bool
  51. contain_agg_clause_walker(Node *node, void *context)
  52. {
  53. if (node == NULL)
  54. return false;
  55. if (IsA(node, Aggref))
  56. return true; /* abort the tree traversal and return true */
  57. return expression_tree_walker(node, contain_agg_clause_walker, context);
  58. }
  59. /*
  60.  * exprIsAggOrGroupCol -
  61.  *   returns true if the expression does not contain non-group columns,
  62.  *   other than within the arguments of aggregate functions.
  63.  *
  64.  * NOTE: we assume that the given clause has been transformed suitably for
  65.  * parser output.  This means we can use the planner's expression_tree_walker.
  66.  *
  67.  * NOTE: in the case of a SubLink, expression_tree_walker does not descend
  68.  * into the subquery.  This means we will fail to detect ungrouped columns
  69.  * that appear as outer-level variables within a subquery.  That case seems
  70.  * unreasonably hard to handle here.  Instead, we expect the planner to check
  71.  * for ungrouped columns after it's found all the outer-level references
  72.  * inside the subquery and converted them into a list of parameters for the
  73.  * subquery.
  74.  */
  75. static bool
  76. exprIsAggOrGroupCol(Node *expr, List *groupClauses)
  77. {
  78. /* My walker returns TRUE if it finds a subexpression that is NOT
  79.  * acceptable (since we can abort the recursion at that point).
  80.  * So, invert its result.
  81.  */
  82. return ! exprIsAggOrGroupCol_walker(expr, groupClauses);
  83. }
  84. static bool
  85. exprIsAggOrGroupCol_walker(Node *node, List *groupClauses)
  86. {
  87. List    *gl;
  88. if (node == NULL)
  89. return false;
  90. if (IsA(node, Aggref))
  91. return false; /* OK; do not examine argument of aggregate */
  92. if (IsA(node, Const) || IsA(node, Param))
  93. return false; /* constants are always acceptable */
  94. /* Now check to see if expression as a whole matches any GROUP BY item.
  95.  * We need to do this at every recursion level so that we recognize
  96.  * GROUPed-BY expressions.
  97.  */
  98. foreach(gl, groupClauses)
  99. {
  100. if (equal(node, lfirst(gl)))
  101. return false; /* acceptable, do not descend more */
  102. }
  103. /* If we have an ungrouped Var, we have a failure --- unless it is an
  104.  * outer-level Var.  In that case it's a constant as far as this query
  105.  * level is concerned, and we can accept it.  (If it's ungrouped as far
  106.  * as the upper query is concerned, that's someone else's problem...)
  107.  */
  108. if (IsA(node, Var))
  109. {
  110. if (((Var *) node)->varlevelsup == 0)
  111. return true; /* found an ungrouped local variable */
  112. return false; /* outer-level Var is acceptable */
  113. }
  114. /* Otherwise, recurse. */
  115. return expression_tree_walker(node, exprIsAggOrGroupCol_walker,
  116.   (void *) groupClauses);
  117. }
  118. /*
  119.  * parseCheckAggregates
  120.  * Check for aggregates where they shouldn't be and improper grouping.
  121.  *
  122.  * Ideally this should be done earlier, but it's difficult to distinguish
  123.  * aggregates from plain functions at the grammar level.  So instead we
  124.  * check here.  This function should be called after the target list and
  125.  * qualifications are finalized.
  126.  */
  127. void
  128. parseCheckAggregates(ParseState *pstate, Query *qry)
  129. {
  130. List    *groupClauses = NIL;
  131. List    *tl;
  132. /* This should only be called if we found aggregates or grouping */
  133. Assert(pstate->p_hasAggs || qry->groupClause);
  134. /*
  135.  * Aggregates must never appear in WHERE clauses. (Note this check
  136.  * should appear first to deliver an appropriate error message;
  137.  * otherwise we are likely to generate the generic "illegal use of
  138.  * aggregates in target list" message, which is outright misleading if
  139.  * the problem is in WHERE.)
  140.  */
  141. if (contain_agg_clause(qry->qual))
  142. elog(ERROR, "Aggregates not allowed in WHERE clause");
  143. /*
  144.  * No aggregates allowed in GROUP BY clauses, either.
  145.  *
  146.  * While we are at it, build a list of the acceptable GROUP BY expressions
  147.  * for use by exprIsAggOrGroupCol() (this avoids repeated scans of the
  148.  * targetlist within the recursive routines...)
  149.  */
  150. foreach(tl, qry->groupClause)
  151. {
  152. GroupClause *grpcl = lfirst(tl);
  153. Node *expr;
  154. expr = (Node *) get_groupclause_expr(grpcl, qry->targetList);
  155. if (contain_agg_clause(expr))
  156. elog(ERROR, "Aggregates not allowed in GROUP BY clause");
  157. groupClauses = lcons(expr, groupClauses);
  158. }
  159. /*
  160.  * The target list can only contain aggregates, group columns and
  161.  * functions thereof.
  162.  */
  163. foreach(tl, qry->targetList)
  164. {
  165. TargetEntry *tle = lfirst(tl);
  166. if (!exprIsAggOrGroupCol(tle->expr, groupClauses))
  167. elog(ERROR,
  168.  "Illegal use of aggregates or non-group column in target list");
  169. }
  170. /*
  171.  * The expression specified in the HAVING clause has the same
  172.  * restriction as those in the target list.
  173.  */
  174. if (!exprIsAggOrGroupCol(qry->havingQual, groupClauses))
  175. elog(ERROR,
  176.  "Illegal use of aggregates or non-group column in HAVING clause");
  177. /* Release the list storage (but not the pointed-to expressions!) */
  178. freeList(groupClauses);
  179. }
  180. Aggref *
  181. ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
  182.  List *target, int precedence)
  183. {
  184. Oid fintype;
  185. Oid vartype;
  186. Oid xfn1;
  187. Form_pg_aggregate aggform;
  188. Aggref    *aggref;
  189. HeapTuple theAggTuple;
  190. bool usenulls = false;
  191. theAggTuple = SearchSysCacheTuple(AGGNAME,
  192.   PointerGetDatum(aggname),
  193.   ObjectIdGetDatum(basetype),
  194.   0, 0);
  195. if (!HeapTupleIsValid(theAggTuple))
  196. elog(ERROR, "Aggregate %s does not exist", aggname);
  197. /*
  198.  * We do a major hack for count(*) here.
  199.  *
  200.  * Count(*) poses several problems.  First, we need a field that is
  201.  * guaranteed to be in the range table, and unique.  Using a constant
  202.  * causes the optimizer to properly remove the aggragate from any
  203.  * elements of the query. Using just 'oid', which can not be null, in
  204.  * the parser fails on:
  205.  *
  206.  * select count(*) from tab1, tab2    -- oid is not unique select
  207.  * count(*) from viewtable -- views don't have real oids
  208.  *
  209.  * So, for an aggregate with parameter '*', we use the first valid range
  210.  * table entry, and pick the first column from the table. We set a
  211.  * flag to count nulls, because we could have nulls in that column.
  212.  *
  213.  * It's an ugly job, but someone has to do it. bjm 1998/1/18
  214.  */
  215. if (nodeTag(lfirst(target)) == T_Const)
  216. {
  217. Const    *con = (Const *) lfirst(target);
  218. if (con->consttype == UNKNOWNOID && VARSIZE(con->constvalue) == VARHDRSZ)
  219. {
  220. Attr    *attr = makeNode(Attr);
  221. List    *rtable,
  222.    *rlist;
  223. RangeTblEntry *first_valid_rte;
  224. Assert(lnext(target) == NULL);
  225. if (pstate->p_is_rule)
  226. rtable = lnext(lnext(pstate->p_rtable));
  227. else
  228. rtable = pstate->p_rtable;
  229. first_valid_rte = NULL;
  230. foreach(rlist, rtable)
  231. {
  232. RangeTblEntry *rte = lfirst(rlist);
  233. /* only entries on outer(non-function?) scope */
  234. if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
  235. continue;
  236. first_valid_rte = rte;
  237. break;
  238. }
  239. if (first_valid_rte == NULL)
  240. elog(ERROR, "Can't find column to do aggregate(*) on.");
  241. attr->relname = first_valid_rte->refname;
  242. attr->attrs = lcons(makeString(
  243.    get_attname(first_valid_rte->relid, 1)), NIL);
  244. lfirst(target) = transformExpr(pstate, (Node *) attr, precedence);
  245. usenulls = true;
  246. }
  247. }
  248. aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
  249. fintype = aggform->aggfinaltype;
  250. xfn1 = aggform->aggtransfn1;
  251. /* only aggregates with transfn1 need a base type */
  252. if (OidIsValid(xfn1))
  253. {
  254. basetype = aggform->aggbasetype;
  255. vartype = exprType(lfirst(target));
  256. if ((basetype != vartype)
  257. && (!IS_BINARY_COMPATIBLE(basetype, vartype)))
  258. {
  259. Type tp1,
  260. tp2;
  261. tp1 = typeidType(basetype);
  262. tp2 = typeidType(vartype);
  263. elog(ERROR, "Aggregate type mismatch"
  264.  "nt%s() works on %s, not on %s",
  265.  aggname, typeTypeName(tp1), typeTypeName(tp2));
  266. }
  267. }
  268. aggref = makeNode(Aggref);
  269. aggref->aggname = pstrdup(aggname);
  270. aggref->basetype = aggform->aggbasetype;
  271. aggref->aggtype = fintype;
  272. aggref->target = lfirst(target);
  273. if (usenulls)
  274. aggref->usenulls = true;
  275. pstate->p_hasAggs = true;
  276. return aggref;
  277. }
  278. /*
  279.  * Error message when aggregate lookup fails that gives details of the
  280.  * basetype
  281.  */
  282. void
  283. agg_error(char *caller, char *aggname, Oid basetypeID)
  284. {
  285. /*
  286.  * basetypeID that is Invalid (zero) means aggregate over all types.
  287.  * (count)
  288.  */
  289. if (basetypeID == InvalidOid)
  290. elog(ERROR, "%s: aggregate '%s' for all types does not exist", caller, aggname);
  291. else
  292. {
  293. elog(ERROR, "%s: aggregate '%s' for '%s' does not exist", caller, aggname,
  294.  typeidTypeName(basetypeID));
  295. }
  296. }