88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.186 2004/12/31 22:00:23 pgsql Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.187 2005/01/28 19:34:07 tgl Exp $
1212 *
1313 * HISTORY
1414 * AUTHORDATEMAJOR EVENT
1919
2020#include "postgres.h"
2121
22+ #include "catalog/pg_aggregate.h"
2223#include "catalog/pg_language.h"
2324#include "catalog/pg_proc.h"
2425#include "catalog/pg_type.h"
3334#include "optimizer/var.h"
3435#include "parser/analyze.h"
3536#include "parser/parse_clause.h"
37+ #include "parser/parse_coerce.h"
3638#include "parser/parse_expr.h"
3739#include "tcop/tcopprot.h"
3840#include "utils/acl.h"
@@ -58,8 +60,7 @@ typedef struct
5860}substitute_actual_parameters_context ;
5961
6062static bool contain_agg_clause_walker (Node * node ,void * context );
61- static bool contain_distinct_agg_clause_walker (Node * node ,void * context );
62- static bool count_agg_clause_walker (Node * node ,int * count );
63+ static bool count_agg_clauses_walker (Node * node ,AggClauseCounts * counts );
6364static bool expression_returns_set_walker (Node * node ,void * context );
6465static bool contain_subplans_walker (Node * node ,void * context );
6566static bool contain_mutable_functions_walker (Node * node ,void * context );
@@ -358,71 +359,108 @@ contain_agg_clause_walker(Node *node, void *context)
358359}
359360
360361/*
361- * contain_distinct_agg_clause
362- * Recursively search for DISTINCT Aggref nodes within a clause.
362+ * count_agg_clauses
363+ * Recursively count the Aggref nodes in an expression tree.
364+ *
365+ * Note: this also checks for nested aggregates, which are an error.
363366 *
364- * Returns true if any DISTINCT aggregate found.
367+ * We not only count the nodes, but attempt to estimate the total space
368+ * needed for their transition state values if all are evaluated in parallel
369+ * (as would be done in a HashAgg plan). See AggClauseCounts for the exact
370+ * set of statistics returned.
371+ *
372+ * NOTE that the counts are ADDED to those already in *counts ... so the
373+ * caller is responsible for zeroing the struct initially.
365374 *
366375 * This does not descend into subqueries, and so should be used only after
367376 * reduction of sublinks to subplans, or in contexts where it's known there
368377 * are no subqueries. There mustn't be outer-aggregate references either.
369378 */
370- bool
371- contain_distinct_agg_clause (Node * clause )
379+ void
380+ count_agg_clauses (Node * clause , AggClauseCounts * counts )
372381{
373- return contain_distinct_agg_clause_walker (clause ,NULL );
382+ /* no setup needed */
383+ count_agg_clauses_walker (clause ,counts );
374384}
375385
376386static bool
377- contain_distinct_agg_clause_walker (Node * node ,void * context )
387+ count_agg_clauses_walker (Node * node ,AggClauseCounts * counts )
378388{
379389if (node == NULL )
380390return false;
381391if (IsA (node ,Aggref ))
382392{
383- Assert (((Aggref * )node )-> agglevelsup == 0 );
384- if (((Aggref * )node )-> aggdistinct )
385- return true;/* abort the tree traversal and return
386- * true */
387- }
388- Assert (!IsA (node ,SubLink ));
389- return expression_tree_walker (node ,contain_distinct_agg_clause_walker ,context );
390- }
393+ Aggref * aggref = (Aggref * )node ;
394+ Oid inputType ;
395+ HeapTuple aggTuple ;
396+ Form_pg_aggregate aggform ;
397+ Oid aggtranstype ;
398+
399+ Assert (aggref -> agglevelsup == 0 );
400+ counts -> numAggs ++ ;
401+ if (aggref -> aggdistinct )
402+ counts -> numDistinctAggs ++ ;
403+
404+ inputType = exprType ((Node * )aggref -> target );
405+
406+ /* fetch aggregate transition datatype from pg_aggregate */
407+ aggTuple = SearchSysCache (AGGFNOID ,
408+ ObjectIdGetDatum (aggref -> aggfnoid ),
409+ 0 ,0 ,0 );
410+ if (!HeapTupleIsValid (aggTuple ))
411+ elog (ERROR ,"cache lookup failed for aggregate %u" ,
412+ aggref -> aggfnoid );
413+ aggform = (Form_pg_aggregate )GETSTRUCT (aggTuple );
414+ aggtranstype = aggform -> aggtranstype ;
415+ ReleaseSysCache (aggTuple );
416+
417+ /* resolve actual type of transition state, if polymorphic */
418+ if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID )
419+ {
420+ /* have to fetch the agg's declared input type... */
421+ Oid agg_arg_types [FUNC_MAX_ARGS ];
422+ int agg_nargs ;
423+
424+ (void )get_func_signature (aggref -> aggfnoid ,
425+ agg_arg_types ,& agg_nargs );
426+ Assert (agg_nargs == 1 );
427+ aggtranstype = resolve_generic_type (aggtranstype ,
428+ inputType ,
429+ agg_arg_types [0 ]);
430+ }
391431
392- /*
393- * count_agg_clause
394- * Recursively count the Aggref nodes in an expression tree.
395- *
396- * Note: this also checks for nested aggregates, which are an error.
397- *
398- * This does not descend into subqueries, and so should be used only after
399- * reduction of sublinks to subplans, or in contexts where it's known there
400- * are no subqueries. There mustn't be outer-aggregate references either.
401- */
402- int
403- count_agg_clause (Node * clause )
404- {
405- int result = 0 ;
432+ /*
433+ * If the transition type is pass-by-value then it doesn't add
434+ * anything to the required size of the hashtable. If it is
435+ * pass-by-reference then we have to add the estimated size of
436+ * the value itself, plus palloc overhead.
437+ */
438+ if (!get_typbyval (aggtranstype ))
439+ {
440+ int32 aggtranstypmod ;
441+ int32 avgwidth ;
406442
407- count_agg_clause_walker (clause ,& result );
408- return result ;
409- }
443+ /*
444+ * If transition state is of same type as input, assume it's the
445+ * same typmod (same width) as well. This works for cases like
446+ * MAX/MIN and is probably somewhat reasonable otherwise.
447+ */
448+ if (aggtranstype == inputType )
449+ aggtranstypmod = exprTypmod ((Node * )aggref -> target );
450+ else
451+ aggtranstypmod = -1 ;
410452
411- static bool
412- count_agg_clause_walker (Node * node ,int * count )
413- {
414- if (node == NULL )
415- return false;
416- if (IsA (node ,Aggref ))
417- {
418- Assert (((Aggref * )node )-> agglevelsup == 0 );
419- (* count )++ ;
453+ avgwidth = get_typavgwidth (aggtranstype ,aggtranstypmod );
454+ avgwidth = MAXALIGN (avgwidth );
455+
456+ counts -> transitionSpace += avgwidth + 2 * sizeof (void * );
457+ }
420458
421459/*
422460 * Complain if the aggregate's argument contains any aggregates;
423461 * nested agg functions are semantically nonsensical.
424462 */
425- if (contain_agg_clause ((Node * )(( Aggref * ) node ) -> target ))
463+ if (contain_agg_clause ((Node * )aggref -> target ))
426464ereport (ERROR ,
427465(errcode (ERRCODE_GROUPING_ERROR ),
428466errmsg ("aggregate function calls may not be nested" )));
@@ -433,8 +471,8 @@ count_agg_clause_walker(Node *node, int *count)
433471return false;
434472}
435473Assert (!IsA (node ,SubLink ));
436- return expression_tree_walker (node ,count_agg_clause_walker ,
437- (void * )count );
474+ return expression_tree_walker (node ,count_agg_clauses_walker ,
475+ (void * )counts );
438476}
439477
440478