diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/aggregatecmds.c | 55 | ||||
-rw-r--r-- | src/backend/commands/functioncmds.c | 66 |
2 files changed, 84 insertions, 37 deletions
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index 4a03786210a..78af0924654 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -45,10 +45,12 @@ * * "oldstyle" signals the old (pre-8.2) style where the aggregate input type * is specified by a BASETYPE element in the parameters. Otherwise, - * "args" defines the input type(s). + * "args" is a list of FunctionParameter structs defining the agg's arguments. + * "parameters" is a list of DefElem representing the agg's definition clauses. */ Oid -DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) +DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, + const char *queryString) { char *aggName; Oid aggNamespace; @@ -59,8 +61,12 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) TypeName *baseType = NULL; TypeName *transType = NULL; char *initval = NULL; - Oid *aggArgTypes; int numArgs; + oidvector *parameterTypes; + ArrayType *allParameterTypes; + ArrayType *parameterModes; + ArrayType *parameterNames; + List *parameterDefaults; Oid transTypeId; char transTypeType; ListCell *pl; @@ -131,6 +137,8 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) * Historically we allowed the command to look like basetype = 'ANY' * so we must do a case-insensitive comparison for the name ANY. Ugh. */ + Oid aggArgTypes[1]; + if (baseType == NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), @@ -139,22 +147,26 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0) { numArgs = 0; - aggArgTypes = NULL; + aggArgTypes[0] = InvalidOid; } else { numArgs = 1; - aggArgTypes = (Oid *) palloc(sizeof(Oid)); aggArgTypes[0] = typenameTypeId(NULL, baseType); } + parameterTypes = buildoidvector(aggArgTypes, numArgs); + allParameterTypes = NULL; + parameterModes = NULL; + parameterNames = NULL; + parameterDefaults = NIL; } else { /* - * New style: args is a list of TypeNames (possibly zero of 'em). + * New style: args is a list of FunctionParameters (possibly zero of + * 'em). We share functioncmds.c's code for processing them. */ - ListCell *lc; - int i = 0; + Oid requiredResultType; if (baseType != NULL) ereport(ERROR, @@ -162,13 +174,20 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) errmsg("basetype is redundant with aggregate input type specification"))); numArgs = list_length(args); - aggArgTypes = (Oid *) palloc(sizeof(Oid) * numArgs); - foreach(lc, args) - { - TypeName *curTypeName = (TypeName *) lfirst(lc); - - aggArgTypes[i++] = typenameTypeId(NULL, curTypeName); - } + interpret_function_parameter_list(args, + InvalidOid, + true, /* is an aggregate */ + queryString, + ¶meterTypes, + &allParameterTypes, + ¶meterModes, + ¶meterNames, + ¶meterDefaults, + &requiredResultType); + /* Parameter defaults are not currently allowed by the grammar */ + Assert(parameterDefaults == NIL); + /* There shouldn't have been any OUT parameters, either */ + Assert(requiredResultType == InvalidOid); } /* @@ -219,8 +238,12 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) */ return AggregateCreate(aggName, /* aggregate name */ aggNamespace, /* namespace */ - aggArgTypes, /* input data type(s) */ numArgs, + parameterTypes, + PointerGetDatum(allParameterTypes), + PointerGetDatum(parameterModes), + PointerGetDatum(parameterNames), + parameterDefaults, transfuncName, /* step function name */ finalfuncName, /* final function name */ sortoperatorName, /* sort operator name */ diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 0a9facfbaaa..ca754b47ff9 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -88,7 +88,6 @@ compute_return_type(TypeName *returnType, Oid languageOid, typtup = LookupTypeName(NULL, returnType, NULL); - if (typtup) { if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) @@ -158,22 +157,31 @@ compute_return_type(TypeName *returnType, Oid languageOid, } /* - * Interpret the parameter list of the CREATE FUNCTION statement. + * Interpret the function parameter list of a CREATE FUNCTION or + * CREATE AGGREGATE statement. + * + * Input parameters: + * parameters: list of FunctionParameter structs + * languageOid: OID of function language (InvalidOid if it's CREATE AGGREGATE) + * is_aggregate: needed only to determine error handling + * queryString: likewise, needed only for error handling * * Results are stored into output parameters. parameterTypes must always * be created, but the other arrays are set to NULL if not needed. * requiredResultType is set to InvalidOid if there are no OUT parameters, * else it is set to the OID of the implied result type. */ -static void -examine_parameter_list(List *parameters, Oid languageOid, - const char *queryString, - oidvector **parameterTypes, - ArrayType **allParameterTypes, - ArrayType **parameterModes, - ArrayType **parameterNames, - List **parameterDefaults, - Oid *requiredResultType) +void +interpret_function_parameter_list(List *parameters, + Oid languageOid, + bool is_aggregate, + const char *queryString, + oidvector **parameterTypes, + ArrayType **allParameterTypes, + ArrayType **parameterModes, + ArrayType **parameterNames, + List **parameterDefaults, + Oid *requiredResultType) { int parameterCount = list_length(parameters); Oid *inTypes; @@ -223,6 +231,12 @@ examine_parameter_list(List *parameters, Oid languageOid, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SQL function cannot accept shell type %s", TypeNameToString(t)))); + /* We don't allow creating aggregates on shell types either */ + else if (is_aggregate) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("aggregate cannot accept shell type %s", + TypeNameToString(t)))); else ereport(NOTICE, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -246,9 +260,16 @@ examine_parameter_list(List *parameters, Oid languageOid, aclcheck_error_type(aclresult, toid); if (t->setof) - ereport(ERROR, - (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("functions cannot accept set arguments"))); + { + if (is_aggregate) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("aggregates cannot accept set arguments"))); + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("functions cannot accept set arguments"))); + } /* handle input parameters */ if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE) @@ -890,13 +911,16 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) * Convert remaining parameters of CREATE to form wanted by * ProcedureCreate. */ - examine_parameter_list(stmt->parameters, languageOid, queryString, - ¶meterTypes, - &allParameterTypes, - ¶meterModes, - ¶meterNames, - ¶meterDefaults, - &requiredResultType); + interpret_function_parameter_list(stmt->parameters, + languageOid, + false, /* not an aggregate */ + queryString, + ¶meterTypes, + &allParameterTypes, + ¶meterModes, + ¶meterNames, + ¶meterDefaults, + &requiredResultType); if (stmt->returnType) { |