aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_agg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_agg.c')
-rw-r--r--src/backend/parser/parse_agg.c93
1 files changed, 92 insertions, 1 deletions
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 49d952bf8af..306a64735b9 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,18 +8,21 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.53 2003/06/06 15:04:02 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.54 2003/07/01 19:10:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include "nodes/makefuncs.h"
+#include "nodes/params.h"
#include "optimizer/clauses.h"
#include "optimizer/tlist.h"
#include "optimizer/var.h"
#include "parser/parse_agg.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
+#include "utils/lsyscache.h"
typedef struct
@@ -312,3 +315,91 @@ check_ungrouped_columns_walker(Node *node,
return expression_tree_walker(node, check_ungrouped_columns_walker,
(void *) context);
}
+
+/*
+ * Create expression trees for the transition and final functions
+ * of an aggregate. These are needed so that polymorphic functions
+ * can be used within an aggregate --- without the expression trees,
+ * such functions would not know the datatypes they are supposed to use.
+ * (The trees will never actually be executed, however, so we can skimp
+ * a bit on correctness.)
+ *
+ * agg_input_type, agg_state_type, agg_result_type identify the input,
+ * transition, and result types of the aggregate. These should all be
+ * resolved to actual types (ie, none should ever be ANYARRAY or ANYELEMENT).
+ *
+ * transfn_oid and finalfn_oid identify the funcs to be called; the latter
+ * may be InvalidOid.
+ *
+ * Pointers to the constructed trees are returned into *transfnexpr and
+ * *finalfnexpr. The latter is set to NULL if there's no finalfn.
+ */
+void
+build_aggregate_fnexprs(Oid agg_input_type,
+ Oid agg_state_type,
+ Oid agg_result_type,
+ Oid transfn_oid,
+ Oid finalfn_oid,
+ Expr **transfnexpr,
+ Expr **finalfnexpr)
+{
+ Oid transfn_arg_types[FUNC_MAX_ARGS];
+ int transfn_nargs;
+ Param *arg0;
+ Param *arg1;
+ List *args;
+
+ /* get the transition function signature (only need nargs) */
+ (void) get_func_signature(transfn_oid, transfn_arg_types, &transfn_nargs);
+
+ /*
+ * Build arg list to use in the transfn FuncExpr node. We really
+ * only care that transfn can discover the actual argument types
+ * at runtime using get_fn_expr_argtype(), so it's okay to use
+ * Param nodes that don't correspond to any real Param.
+ */
+ arg0 = makeNode(Param);
+ arg0->paramkind = PARAM_EXEC;
+ arg0->paramid = -1;
+ arg0->paramtype = agg_state_type;
+
+ if (transfn_nargs == 2)
+ {
+ arg1 = makeNode(Param);
+ arg1->paramkind = PARAM_EXEC;
+ arg1->paramid = -1;
+ arg1->paramtype = agg_input_type;
+
+ args = makeList2(arg0, arg1);
+ }
+ else
+ {
+ args = makeList1(arg0);
+ }
+
+ *transfnexpr = (Expr *) makeFuncExpr(transfn_oid,
+ agg_state_type,
+ args,
+ COERCE_DONTCARE);
+
+ /* see if we have a final function */
+ if (!OidIsValid(finalfn_oid))
+ {
+ *finalfnexpr = NULL;
+ return;
+ }
+
+ /*
+ * Build expr tree for final function
+ */
+ arg0 = makeNode(Param);
+ arg0->paramkind = PARAM_EXEC;
+ arg0->paramid = -1;
+ arg0->paramtype = agg_state_type;
+ args = makeList1(arg0);
+
+ *finalfnexpr = (Expr *) makeFuncExpr(finalfn_oid,
+ agg_result_type,
+ args,
+ COERCE_DONTCARE);
+}