Commit e3b1b6c0 authored by Tom Lane's avatar Tom Lane

Aggregates can be polymorphic, using polymorphic implementation functions.

It also works to create a non-polymorphic aggregate from polymorphic
functions, should you want to do that.  Regression test added, docs still
lacking.  By Joe Conway, with some kibitzing from Tom Lane.
parent 02b5d8e3
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.58 2003/06/25 21:30:25 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.59 2003/07/01 19:10:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -29,6 +29,10 @@
#include "utils/syscache.h"
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
Oid *rettype);
/*
* AggregateCreate
*/
......@@ -48,9 +52,10 @@ AggregateCreate(const char *aggName,
Form_pg_proc proc;
Oid transfn;
Oid finalfn = InvalidOid; /* can be omitted */
Oid rettype;
Oid finaltype;
Oid fnArgs[FUNC_MAX_ARGS];
int nargs;
int nargs_transfn;
Oid procOid;
TupleDesc tupDesc;
int i;
......@@ -64,28 +69,49 @@ AggregateCreate(const char *aggName,
if (!aggtransfnName)
elog(ERROR, "aggregate must have a transition function");
/*
* If transtype is polymorphic, basetype must be polymorphic also;
* else we will have no way to deduce the actual transtype.
*/
if ((aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID) &&
!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
elog(ERROR, "an aggregate using ANYARRAY or ANYELEMENT as trans type "
"must also have one of them as its base type");
/* handle transfn */
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
fnArgs[0] = aggTransType;
if (aggBaseType == ANYOID)
nargs = 1;
nargs_transfn = 1;
else
{
fnArgs[1] = aggBaseType;
nargs = 2;
nargs_transfn = 2;
}
transfn = LookupFuncName(aggtransfnName, nargs, fnArgs);
if (!OidIsValid(transfn))
func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs,
&rettype);
/*
* Return type of transfn (possibly after refinement by
* enforce_generic_type_consistency, if transtype isn't polymorphic)
* must exactly match declared transtype.
*
* In the non-polymorphic-transtype case, it might be okay to allow
* a rettype that's binary-coercible to transtype, but I'm not quite
* convinced that it's either safe or useful. When transtype is
* polymorphic we *must* demand exact equality.
*/
if (rettype != aggTransType)
elog(ERROR, "return type of transition function %s is not %s",
NameListToString(aggtransfnName), format_type_be(aggTransType));
tup = SearchSysCache(PROCOID,
ObjectIdGetDatum(transfn),
0, 0, 0);
if (!HeapTupleIsValid(tup))
func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
func_error("AggregateCreate", aggtransfnName,
nargs_transfn, fnArgs, NULL);
proc = (Form_pg_proc) GETSTRUCT(tup);
if (proc->prorettype != aggTransType)
elog(ERROR, "return type of transition function %s is not %s",
NameListToString(aggtransfnName), format_type_be(aggTransType));
/*
* If the transfn is strict and the initval is NULL, make sure input
......@@ -105,17 +131,8 @@ AggregateCreate(const char *aggName,
{
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
fnArgs[0] = aggTransType;
finalfn = LookupFuncName(aggfinalfnName, 1, fnArgs);
if (!OidIsValid(finalfn))
func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
tup = SearchSysCache(PROCOID,
ObjectIdGetDatum(finalfn),
0, 0, 0);
if (!HeapTupleIsValid(tup))
func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
proc = (Form_pg_proc) GETSTRUCT(tup);
finaltype = proc->prorettype;
ReleaseSysCache(tup);
finalfn = lookup_agg_function(aggfinalfnName, 1, fnArgs,
&finaltype);
}
else
{
......@@ -126,6 +143,19 @@ AggregateCreate(const char *aggName,
}
Assert(OidIsValid(finaltype));
/*
* If finaltype (i.e. aggregate return type) is polymorphic,
* basetype must be polymorphic also, else parser will fail to deduce
* result type. (Note: given the previous test on transtype and basetype,
* this cannot happen, unless someone has snuck a finalfn definition
* into the catalogs that itself violates the rule against polymorphic
* result with no polymorphic input.)
*/
if ((finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID) &&
!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
elog(ERROR, "an aggregate returning ANYARRAY or ANYELEMENT "
"must also have one of them as its base type");
/*
* Everything looks okay. Try to create the pg_proc entry for the
* aggregate. (This could fail if there's already a conflicting
......@@ -207,3 +237,71 @@ AggregateCreate(const char *aggName,
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
}
/*
* lookup_agg_function -- common code for finding both transfn and finalfn
*/
static Oid
lookup_agg_function(List *fnName,
int nargs,
Oid *input_types,
Oid *rettype)
{
Oid fnOid;
bool retset;
Oid *true_oid_array;
FuncDetailCode fdresult;
/*
* func_get_detail looks up the function in the catalogs, does
* disambiguation for polymorphic functions, handles inheritance, and
* returns the funcid and type and set or singleton status of the
* function's return value. it also returns the true argument types
* to the function.
*/
fdresult = func_get_detail(fnName, NIL, nargs, input_types,
&fnOid, rettype, &retset,
&true_oid_array);
/* only valid case is a normal function not returning a set */
if (fdresult != FUNCDETAIL_NORMAL ||
!OidIsValid(fnOid) ||
retset)
func_error("AggregateCreate", fnName, nargs, input_types, NULL);
/*
* If the given type(s) are all polymorphic, there's nothing we
* can check. Otherwise, enforce consistency, and possibly refine
* the result type.
*/
if ((input_types[0] == ANYARRAYOID || input_types[0] == ANYELEMENTOID) &&
(nargs == 1 ||
(input_types[1] == ANYARRAYOID || input_types[1] == ANYELEMENTOID)))
{
/* nothing to check here */
}
else
{
*rettype = enforce_generic_type_consistency(input_types,
true_oid_array,
nargs,
*rettype);
}
/*
* func_get_detail will find functions requiring run-time argument type
* coercion, but nodeAgg.c isn't prepared to deal with that
*/
if (true_oid_array[0] != ANYARRAYOID &&
true_oid_array[0] != ANYELEMENTOID &&
!IsBinaryCoercible(input_types[0], true_oid_array[0]))
func_error("AggregateCreate", fnName, nargs, input_types, NULL);
if (nargs == 2 &&
true_oid_array[1] != ANYARRAYOID &&
true_oid_array[1] != ANYELEMENTOID &&
!IsBinaryCoercible(input_types[1], true_oid_array[1]))
func_error("AggregateCreate", fnName, nargs, input_types, NULL);
return fnOid;
}
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.8 2003/06/27 14:45:27 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.9 2003/07/01 19:10:52 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
......@@ -120,7 +120,9 @@ DefineAggregate(List *names, List *parameters)
baseTypeId = typenameTypeId(baseType);
transTypeId = typenameTypeId(transType);
if (get_typtype(transTypeId) == 'p')
if (get_typtype(transTypeId) == 'p' &&
transTypeId != ANYARRAYOID &&
transTypeId != ANYELEMENTOID)
elog(ERROR, "Aggregate transition datatype cannot be %s",
format_type_be(transTypeId));
......
......@@ -45,7 +45,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.109 2003/06/25 21:30:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.110 2003/07/01 19:10:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -59,6 +59,7 @@
#include "executor/nodeAgg.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
......@@ -1182,11 +1183,15 @@ ExecInitAgg(Agg *node, EState *estate)
AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(alist);
Aggref *aggref = (Aggref *) aggrefstate->xprstate.expr;
AggStatePerAgg peraggstate;
Oid inputType;
HeapTuple aggTuple;
Form_pg_aggregate aggform;
Oid aggtranstype;
AclResult aclresult;
Oid transfn_oid,
finalfn_oid;
Expr *transfnexpr,
*finalfnexpr;
Datum textInitVal;
int i;
......@@ -1217,6 +1222,13 @@ ExecInitAgg(Agg *node, EState *estate)
peraggstate->aggrefstate = aggrefstate;
peraggstate->aggref = aggref;
/*
* Get actual datatype of the input. We need this because it may
* be different from the agg's declared input type, when the agg
* accepts ANY (eg, COUNT(*)) or ANYARRAY or ANYELEMENT.
*/
inputType = exprType((Node *) aggref->target);
aggTuple = SearchSysCache(AGGFNOID,
ObjectIdGetDatum(aggref->aggfnoid),
0, 0, 0);
......@@ -1231,10 +1243,47 @@ ExecInitAgg(Agg *node, EState *estate)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_func_name(aggref->aggfnoid));
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
/* resolve actual type of transition state, if polymorphic */
aggtranstype = aggform->aggtranstype;
if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
{
/* have to fetch the agg's declared input type... */
Oid agg_arg_types[FUNC_MAX_ARGS];
int agg_nargs;
(void) get_func_signature(aggref->aggfnoid,
agg_arg_types, &agg_nargs);
Assert(agg_nargs == 1);
aggtranstype = resolve_generic_type(aggtranstype,
inputType,
agg_arg_types[0]);
}
/* build expression trees using actual argument & result types */
build_aggregate_fnexprs(inputType,
aggtranstype,
aggref->aggtype,
transfn_oid,
finalfn_oid,
&transfnexpr,
&finalfnexpr);
fmgr_info(transfn_oid, &peraggstate->transfn);
peraggstate->transfn.fn_expr = (Node *) transfnexpr;
if (OidIsValid(finalfn_oid))
{
fmgr_info(finalfn_oid, &peraggstate->finalfn);
peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
}
get_typlenbyval(aggref->aggtype,
&peraggstate->resulttypeLen,
&peraggstate->resulttypeByVal);
get_typlenbyval(aggform->aggtranstype,
get_typlenbyval(aggtranstype,
&peraggstate->transtypeLen,
&peraggstate->transtypeByVal);
......@@ -1250,14 +1299,7 @@ ExecInitAgg(Agg *node, EState *estate)
peraggstate->initValue = (Datum) 0;
else
peraggstate->initValue = GetAggInitVal(textInitVal,
aggform->aggtranstype);
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
fmgr_info(transfn_oid, &peraggstate->transfn);
if (OidIsValid(finalfn_oid))
fmgr_info(finalfn_oid, &peraggstate->finalfn);
aggtranstype);
/*
* If the transfn is strict and the initval is NULL, make sure
......@@ -1268,26 +1310,13 @@ ExecInitAgg(Agg *node, EState *estate)
*/
if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
{
/*
* Note: use the type from the input expression here, not from
* pg_proc.proargtypes, because the latter might be 0.
* (Consider COUNT(*).)
*/
Oid inputType = exprType((Node *) aggref->target);
if (!IsBinaryCoercible(inputType, aggform->aggtranstype))
if (!IsBinaryCoercible(inputType, aggtranstype))
elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
aggref->aggfnoid);
}
if (aggref->aggdistinct)
{
/*
* Note: use the type from the input expression here, not from
* pg_proc.proargtypes, because the latter might be a pseudotype.
* (Consider COUNT(*).)
*/
Oid inputType = exprType((Node *) aggref->target);
Oid eq_function;
/* We don't implement DISTINCT aggs in the HASHED case */
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.39 2003/05/06 00:20:32 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.40 2003/07/01 19:10:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -251,3 +251,24 @@ makeTypeName(char *typnam)
n->typmod = -1;
return n;
}
/*
* makeFuncExpr -
* build an expression tree representing a function call.
*
* The argument expressions must have been transformed already.
*/
FuncExpr *
makeFuncExpr(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
{
FuncExpr *funcexpr;
funcexpr = makeNode(FuncExpr);
funcexpr->funcid = funcid;
funcexpr->funcresulttype = rettype;
funcexpr->funcretset = false; /* only allowed case here */
funcexpr->funcformat = fformat;
funcexpr->args = args;
return funcexpr;
}
......@@ -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);
}
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.101 2003/06/27 00:33:25 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.102 2003/07/01 19:10:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -32,8 +32,6 @@
static Node *coerce_type_typmod(Node *node,
Oid targetTypeId, int32 targetTypMod,
CoercionForm cformat, bool isExplicit);
static Node *build_func_call(Oid funcid, Oid rettype, List *args,
CoercionForm fformat);
/*
......@@ -275,8 +273,9 @@ coerce_type(ParseState *pstate, Node *node,
*/
Oid baseTypeId = getBaseType(targetTypeId);
result = build_func_call(funcId, baseTypeId, makeList1(node),
cformat);
result = (Node *) makeFuncExpr(funcId, baseTypeId,
makeList1(node),
cformat);
/*
* If domain, coerce to the domain type and relabel with
......@@ -534,7 +533,7 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
args = lappend(args, cons);
}
node = build_func_call(funcId, targetTypeId, args, cformat);
node = (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat);
}
return node;
......@@ -935,6 +934,76 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
return rettype;
}
/*
* resolve_generic_type()
* Deduce an individual actual datatype on the assumption that
* the rules for ANYARRAY/ANYELEMENT are being followed.
*
* declared_type is the declared datatype we want to resolve.
* context_actual_type is the actual input datatype to some argument
* that has declared datatype context_declared_type.
*
* If declared_type isn't polymorphic, we just return it. Otherwise,
* context_declared_type must be polymorphic, and we deduce the correct
* return type based on the relationship of the two polymorphic types.
*/
Oid
resolve_generic_type(Oid declared_type,
Oid context_actual_type,
Oid context_declared_type)
{
if (declared_type == ANYARRAYOID)
{
if (context_declared_type == ANYARRAYOID)
{
/* Use actual type, but it must be an array */
Oid array_typelem = get_element_type(context_actual_type);
if (!OidIsValid(array_typelem))
elog(ERROR, "Argument declared ANYARRAY is not an array: %s",
format_type_be(context_actual_type));
return context_actual_type;
}
else if (context_declared_type == ANYELEMENTOID)
{
/* Use the array type corresponding to actual type */
Oid array_typeid = get_array_type(context_actual_type);
if (!OidIsValid(array_typeid))
elog(ERROR, "Cannot find array type for datatype %s",
format_type_be(context_actual_type));
return array_typeid;
}
}
else if (declared_type == ANYELEMENTOID)
{
if (context_declared_type == ANYARRAYOID)
{
/* Use the element type corresponding to actual type */
Oid array_typelem = get_element_type(context_actual_type);
if (!OidIsValid(array_typelem))
elog(ERROR, "Argument declared ANYARRAY is not an array: %s",
format_type_be(context_actual_type));
return array_typelem;
}
else if (context_declared_type == ANYELEMENTOID)
{
/* Use the actual type; it doesn't matter if array or not */
return context_actual_type;
}
}
else
{
/* declared_type isn't polymorphic, so return it as-is */
return declared_type;
}
/* If we get here, declared_type is polymorphic and context isn't */
/* NB: this is a calling-code logic error, not a user error */
elog(ERROR, "Cannot determine ANYARRAY/ANYELEMENT type because context isn't polymorphic");
return InvalidOid; /* keep compiler quiet */
}
/* TypeCategory()
* Assign a category to the specified type OID.
......@@ -1417,23 +1486,3 @@ find_typmod_coercion_function(Oid typeId, int *nargs)
return funcid;
}
/*
* Build an expression tree representing a function call.
*
* The argument expressions must have been transformed already.
*/
static Node *
build_func_call(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
{
FuncExpr *funcexpr;
funcexpr = makeNode(FuncExpr);
funcexpr->funcid = funcid;
funcexpr->funcresulttype = rettype;
funcexpr->funcretset = false; /* only possible case here */
funcexpr->funcformat = fformat;
funcexpr->args = args;
return (Node *) funcexpr;
}
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.100 2003/06/27 00:33:25 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.101 2003/07/01 19:10:53 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
......@@ -718,6 +718,36 @@ get_func_rettype(Oid funcid)
return result;
}
/*
* get_func_signature
* Given procedure id, return the function's argument and result types.
* (The return value is the result type.)
*
* argtypes must point to a vector of size FUNC_MAX_ARGS.
*/
Oid
get_func_signature(Oid funcid, Oid *argtypes, int *nargs)
{
HeapTuple tp;
Form_pg_proc procstruct;
Oid result;
tp = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "Function OID %u does not exist", funcid);
procstruct = (Form_pg_proc) GETSTRUCT(tp);
result = procstruct->prorettype;
memcpy(argtypes, procstruct->proargtypes, FUNC_MAX_ARGS * sizeof(Oid));
*nargs = (int) procstruct->pronargs;
ReleaseSysCache(tp);
return result;
}
/*
* get_func_retset
* Given procedure id, return the function's proretset flag.
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: makefuncs.h,v 1.44 2003/02/10 04:44:46 tgl Exp $
* $Id: makefuncs.h,v 1.45 2003/07/01 19:10:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -56,4 +56,7 @@ extern RangeVar *makeRangeVar(char *schemaname, char *relname);
extern TypeName *makeTypeName(char *typnam);
extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype,
List *args, CoercionForm fformat);
#endif /* MAKEFUNC_H */
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_agg.h,v 1.26 2003/06/06 15:04:03 tgl Exp $
* $Id: parse_agg.h,v 1.27 2003/07/01 19:10:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -19,4 +19,12 @@ extern void transformAggregateCall(ParseState *pstate, Aggref *agg);
extern void parseCheckAggregates(ParseState *pstate, Query *qry);
extern 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);
#endif /* PARSE_AGG_H */
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_coerce.h,v 1.51 2003/04/29 22:13:11 tgl Exp $
* $Id: parse_coerce.h,v 1.52 2003/07/01 19:10:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -67,6 +67,9 @@ extern Oid enforce_generic_type_consistency(Oid *actual_arg_types,
Oid *declared_arg_types,
int nargs,
Oid rettype);
extern Oid resolve_generic_type(Oid declared_type,
Oid context_actual_type,
Oid context_declared_type);
extern bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
CoercionContext ccontext,
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: lsyscache.h,v 1.75 2003/06/27 00:33:26 tgl Exp $
* $Id: lsyscache.h,v 1.76 2003/07/01 19:10:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -50,6 +50,7 @@ extern RegProcedure get_oprrest(Oid opno);
extern RegProcedure get_oprjoin(Oid opno);
extern char *get_func_name(Oid funcid);
extern Oid get_func_rettype(Oid funcid);
extern Oid get_func_signature(Oid funcid, Oid *argtypes, int *nargs);
extern bool get_func_retset(Oid funcid);
extern bool func_strict(Oid funcid);
extern char func_volatile(Oid funcid);
......
This diff is collapsed.
......@@ -74,4 +74,4 @@ test: select_views portals_p2 rules foreign_key cluster
# The sixth group of parallel test
# ----------
# "plpgsql" cannot run concurrently with "rules"
test: limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence
test: limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism
# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.19 2003/03/20 07:02:11 momjian Exp $
# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.20 2003/07/01 19:10:53 tgl Exp $
# This should probably be in an order similar to parallel_schedule.
test: boolean
test: char
......@@ -91,3 +91,4 @@ test: conversion
test: truncate
test: alter_table
test: sequence
test: polymorphism
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment