From c87f011a390efe1ee0b5f6f9971e5a5f64791a89 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 17 May 2018 15:39:53 -0400 Subject: [PATCH v1] Allow functions and procedures with the same name According to the SQL standard, functions and procedures should have separate name spaces. Implement this, by making prokind part of the primary key of pg_proc. prokind now only distinguishes functions and procedures. Aggregates and window functions are classified under functions and are distinguished by their old fields proisagg and proiswindow. So this partially reverts the changes in fd1a421fe66173fb9b85d3fe150afde8e812cbe4 that removed those fields. Various APIs are changed to pass the prokind along with the name and arguments for a function or procedure lookup. Conversely, we don't need to check after the lookup whether we got a function or procedure. FIXME: regproc and regprocedure currently have no way to pass in prokind. They will look for either and fail if the result is not unique (that is, like a generic "routine" lookup). --- doc/src/sgml/catalogs.sgml | 24 +- src/backend/catalog/aclchk.c | 4 +- src/backend/catalog/namespace.c | 8 +- src/backend/catalog/objectaddress.c | 8 +- src/backend/catalog/pg_aggregate.c | 6 +- src/backend/catalog/pg_proc.c | 60 ++-- src/backend/catalog/system_views.sql | 9 +- src/backend/commands/alter.c | 4 +- src/backend/commands/amcmds.c | 2 +- src/backend/commands/conversioncmds.c | 3 +- src/backend/commands/dropcmds.c | 2 +- src/backend/commands/event_trigger.c | 2 +- src/backend/commands/foreigncmds.c | 4 +- src/backend/commands/functioncmds.c | 35 +- src/backend/commands/operatorcmds.c | 11 +- src/backend/commands/proclang.c | 18 +- src/backend/commands/trigger.c | 2 +- src/backend/commands/tsearchcmds.c | 4 +- src/backend/commands/typecmds.c | 30 +- src/backend/executor/functions.c | 6 +- src/backend/optimizer/util/clauses.c | 3 +- src/backend/parser/analyze.c | 3 +- src/backend/parser/parse_clause.c | 3 +- src/backend/parser/parse_coerce.c | 3 +- src/backend/parser/parse_expr.c | 11 +- src/backend/parser/parse_func.c | 214 +++++------- src/backend/utils/adt/regproc.c | 10 +- src/backend/utils/adt/ruleutils.c | 7 +- src/backend/utils/cache/lsyscache.c | 12 +- src/backend/utils/cache/syscache.c | 8 +- src/bin/pg_dump/pg_dump.c | 44 ++- src/bin/pg_dump/t/002_pg_dump.pl | 4 + src/bin/psql/describe.c | 30 +- src/bin/psql/tab-complete.c | 52 +-- src/include/catalog/indexing.h | 4 +- src/include/catalog/namespace.h | 1 + src/include/catalog/pg_class.dat | 2 +- src/include/catalog/pg_proc.dat | 306 +++++++++--------- src/include/catalog/pg_proc.h | 11 +- src/include/commands/defrem.h | 4 +- src/include/parser/parse_func.h | 8 +- src/include/utils/lsyscache.h | 2 +- src/include/utils/syscache.h | 2 +- src/pl/tcl/pltcl.c | 2 +- src/test/regress/expected/alter_generic.out | 22 +- .../regress/expected/create_function_3.out | 10 +- .../regress/expected/create_procedure.out | 27 +- src/test/regress/expected/opr_sanity.out | 40 +-- src/test/regress/expected/privileges.out | 2 +- src/test/regress/expected/regex.out | 22 +- src/test/regress/expected/rules.out | 10 +- src/test/regress/sql/alter_generic.sql | 2 +- src/test/regress/sql/create_function_3.sql | 4 +- src/test/regress/sql/opr_sanity.sql | 40 +-- 54 files changed, 584 insertions(+), 583 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 3ed9021c2f..dde657b3ce 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -5118,14 +5118,14 @@ <structname>pg_proc</structname> The catalog pg_proc stores information about - functions, procedures, aggregate functions, and window functions + functions and procedures (collectively also known as routines). See , , and for more information. - If prokind indicates that the entry is for an + If proisagg indicates that the entry is for an aggregate function, there should be a matching row in pg_aggregate. @@ -5217,9 +5217,23 @@ <structname>pg_proc</structname> Columns prokind char - f for a normal function, p - for a procedure, a for an aggregate function, or - w for a window function + f for a function (which includes aggregate + functions and window functions), p for a + procedure + + + + proisagg + bool + + Function is an aggregate function + + + + proiswindow + bool + + Function is a window function diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 578e4c6592..366c452552 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -835,8 +835,8 @@ objectsInSchemaToOids(ObjectType objtype, List *nspnames) /* includes aggregates and window functions */ ScanKeyInit(&key[keycount++], Anum_pg_proc_prokind, - BTEqualStrategyNumber, F_CHARNE, - CharGetDatum(PROKIND_PROCEDURE)); + BTEqualStrategyNumber, F_CHAREQ, + CharGetDatum(PROKIND_FUNCTION)); else if (objtype == OBJECT_PROCEDURE) ScanKeyInit(&key[keycount++], Anum_pg_proc_prokind, diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 0f67a122ed..f12d06d482 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -919,7 +919,7 @@ TypeIsVisible(Oid typid) * candidate is found for other reasons. */ FuncCandidateList -FuncnameGetCandidates(List *names, int nargs, List *argnames, +FuncnameGetCandidates(List *names, char prokind, int nargs, List *argnames, bool expand_variadic, bool expand_defaults, bool missing_ok) { @@ -952,7 +952,7 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames, } /* Search syscache by name only */ - catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(funcname)); + catlist = SearchSysCacheList1(PROCNAMEARGSNSPKIND, CStringGetDatum(funcname)); for (i = 0; i < catlist->n_members; i++) { @@ -967,6 +967,9 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames, int *argnumbers = NULL; FuncCandidateList newResult; + if (prokind != PROKIND_ANY && procform->prokind != prokind) + continue; + if (OidIsValid(namespaceId)) { /* Consider only procs in specified namespace */ @@ -1428,6 +1431,7 @@ FunctionIsVisible(Oid funcid) visible = false; clist = FuncnameGetCandidates(list_make1(makeString(proname)), + procform->prokind, nargs, NIL, false, false, false); for (; clist; clist = clist->next) diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index d371c47842..64691776b1 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -224,7 +224,7 @@ static const ObjectPropertyType ObjectProperty[] = ProcedureRelationId, ProcedureOidIndexId, PROCOID, - -1, /* PROCNAMEARGSNSP also takes argument types */ + -1, /* PROCNAMEARGSNSPKIND also takes argument types */ Anum_pg_proc_proname, Anum_pg_proc_pronamespace, Anum_pg_proc_proowner, @@ -4047,10 +4047,10 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid) elog(ERROR, "cache lookup failed for procedure %u", procid); procForm = (Form_pg_proc) GETSTRUCT(procTup); - if (procForm->prokind == PROKIND_AGGREGATE) - appendStringInfoString(buffer, "aggregate"); - else if (procForm->prokind == PROKIND_PROCEDURE) + if (procForm->prokind == PROKIND_PROCEDURE) appendStringInfoString(buffer, "procedure"); + else if (procForm->proisagg) + appendStringInfoString(buffer, "aggregate"); else /* function or window function */ appendStringInfoString(buffer, "function"); diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 246776093e..23540ff00c 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -617,7 +617,9 @@ AggregateCreate(const char *aggName, InvalidOid, /* no validator */ "aggregate_dummy", /* placeholder proc */ NULL, /* probin */ - PROKIND_AGGREGATE, + PROKIND_FUNCTION, + true, /* isAgg */ + false, /* isWindowFunc */ false, /* security invoker (currently not * definable for agg) */ false, /* isLeakProof */ @@ -806,7 +808,7 @@ lookup_agg_function(List *fnName, * function's return value. it also returns the true argument types to * the function. */ - fdresult = func_get_detail(fnName, NIL, NIL, + fdresult = func_get_detail(fnName, PROKIND_FUNCTION, NIL, NIL, nargs, input_types, false, false, &fnOid, rettype, &retset, &nvargs, &vatype, diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index d783352911..710335f064 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -74,6 +74,8 @@ ProcedureCreate(const char *procedureName, const char *prosrc, const char *probin, char prokind, + bool isAgg, + bool isWindowFunc, bool security_definer, bool isLeakProof, bool isStrict, @@ -334,6 +336,8 @@ ProcedureCreate(const char *procedureName, values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType); values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid); values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind); + values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg); + values[Anum_pg_proc_proiswindow - 1] = BoolGetDatum(isWindowFunc); values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer); values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof); values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict); @@ -379,10 +383,11 @@ ProcedureCreate(const char *procedureName, tupDesc = RelationGetDescr(rel); /* Check for pre-existing definition */ - oldtup = SearchSysCache3(PROCNAMEARGSNSP, + oldtup = SearchSysCache4(PROCNAMEARGSNSPKIND, PointerGetDatum(procedureName), PointerGetDatum(parameterTypes), - ObjectIdGetDatum(procNamespace)); + ObjectIdGetDatum(procNamespace), + CharGetDatum(prokind)); if (HeapTupleIsValid(oldtup)) { @@ -400,21 +405,6 @@ ProcedureCreate(const char *procedureName, aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, procedureName); - /* Not okay to change routine kind */ - if (oldproc->prokind != prokind) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot change routine kind"), - (oldproc->prokind == PROKIND_AGGREGATE ? - errdetail("\"%s\" is an aggregate function.", procedureName) : - oldproc->prokind == PROKIND_FUNCTION ? - errdetail("\"%s\" is a function.", procedureName) : - oldproc->prokind == PROKIND_PROCEDURE ? - errdetail("\"%s\" is a procedure.", procedureName) : - oldproc->prokind == PROKIND_WINDOW ? - errdetail("\"%s\" is a window function.", procedureName) : - 0))); - /* * Not okay to change the return type of the existing proc, since * existing rules, views, etc may depend on the return type. @@ -458,7 +448,7 @@ ProcedureCreate(const char *procedureName, * names have not been changed, as this could break existing calls. We * allow adding names to formerly unnamed parameters, though. */ - proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, + proargnames = SysCacheGetAttr(PROCNAMEARGSNSPKIND, oldtup, Anum_pg_proc_proargnames, &isnull); if (!isnull) @@ -470,7 +460,7 @@ ProcedureCreate(const char *procedureName, int n_new_arg_names; int j; - proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, + proargmodes = SysCacheGetAttr(PROCNAMEARGSNSPKIND, oldtup, Anum_pg_proc_proargmodes, &isnull); if (isnull) @@ -519,7 +509,7 @@ ProcedureCreate(const char *procedureName, errhint("Use DROP FUNCTION %s first.", format_procedure(HeapTupleGetOid(oldtup))))); - proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, + proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSPKIND, oldtup, Anum_pg_proc_proargdefaults, &isnull); Assert(!isnull); @@ -548,7 +538,35 @@ ProcedureCreate(const char *procedureName, } } - /* + /* Can't change aggregate or window-function status, either */ + if (oldproc->proisagg != isAgg) + { + if (oldproc->proisagg) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("function \"%s\" is an aggregate function", + procedureName))); + else + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("function \"%s\" is not an aggregate function", + procedureName))); + } + if (oldproc->proiswindow != isWindowFunc) + { + if (oldproc->proiswindow) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("function \"%s\" is a window function", + procedureName))); + else + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("function \"%s\" is not a window function", + procedureName))); + } + + /* * Do not change existing ownership or permissions, either. Note * dependency-update code below has to agree with this decision. */ diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 8cd8bf40ac..be88e9fde6 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -332,11 +332,10 @@ CREATE VIEW pg_seclabels AS UNION ALL SELECT l.objoid, l.classoid, l.objsubid, - CASE pro.prokind - WHEN 'a' THEN 'aggregate'::text - WHEN 'f' THEN 'function'::text - WHEN 'p' THEN 'procedure'::text - WHEN 'w' THEN 'window'::text END AS objtype, + CASE WHEN pro.prokind = 'p' THEN 'procedure'::text + WHEN pro.proisagg THEN 'aggregate'::text + ELSE 'function'::text + END AS objtype, pro.pronamespace AS objnamespace, CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident(pro.proname) diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index eff325cc7d..3cc6fe0ced 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -245,7 +245,7 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name) { Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(oldtup); - IsThereFunctionInNamespace(new_name, proc->pronargs, + IsThereFunctionInNamespace(new_name, proc->prokind, proc->pronargs, &proc->proargtypes, proc->pronamespace); } else if (classId == CollationRelationId) @@ -738,7 +738,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid) { Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tup); - IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs, + IsThereFunctionInNamespace(NameStr(proc->proname), proc->prokind, proc->pronargs, &proc->proargtypes, nspOid); } else if (classId == CollationRelationId) diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c index f2173450ad..5f3679fad1 100644 --- a/src/backend/commands/amcmds.c +++ b/src/backend/commands/amcmds.c @@ -250,7 +250,7 @@ lookup_index_am_handler_func(List *handler_name, char amtype) errmsg("handler function is not specified"))); /* handlers have one argument of type internal */ - handlerOid = LookupFuncName(handler_name, 1, funcargtypes, false); + handlerOid = LookupFuncName(handler_name, PROKIND_FUNCTION, 1, funcargtypes, false); /* check that handler has the correct return type */ switch (amtype) diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c index e36fc23dd8..92e66cec44 100644 --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -18,6 +18,7 @@ #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/pg_conversion.h" +#include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/alter.h" #include "commands/conversioncmds.h" @@ -76,7 +77,7 @@ CreateConversionCommand(CreateConversionStmt *stmt) * Check the existence of the conversion function. Function name could be * a qualified name. */ - funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid), + funcoid = LookupFuncName(func_name, PROKIND_FUNCTION, sizeof(funcargs) / sizeof(Oid), funcargs, false); /* Check it returns VOID, else it's probably the wrong function */ diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index 4b38ef68d9..fc4ce8d22a 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -92,7 +92,7 @@ RemoveObjects(DropStmt *stmt) */ if (stmt->removeType == OBJECT_FUNCTION) { - if (get_func_prokind(address.objectId) == PROKIND_AGGREGATE) + if (get_func_isagg(address.objectId)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an aggregate function", diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index eecc85d14e..c8e51f8022 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -237,7 +237,7 @@ CreateEventTrigger(CreateEventTrigStmt *stmt) stmt->trigname))); /* Find and validate the trigger function. */ - funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false); + funcoid = LookupFuncName(stmt->funcname, PROKIND_FUNCTION, 0, fargtypes, false); funcrettype = get_func_rettype(funcoid); if (funcrettype != EVTTRIGGEROID) ereport(ERROR, diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index 5c53aeeaeb..4d9371fc64 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -478,7 +478,7 @@ lookup_fdw_handler_func(DefElem *handler) return InvalidOid; /* handlers have no arguments */ - handlerOid = LookupFuncName((List *) handler->arg, 0, funcargtypes, false); + handlerOid = LookupFuncName((List *) handler->arg, PROKIND_FUNCTION, 0, funcargtypes, false); /* check that handler has correct return type */ if (get_func_rettype(handlerOid) != FDW_HANDLEROID) @@ -505,7 +505,7 @@ lookup_fdw_validator_func(DefElem *validator) funcargtypes[0] = TEXTARRAYOID; funcargtypes[1] = OIDOID; - return LookupFuncName((List *) validator->arg, 2, funcargtypes, false); + return LookupFuncName((List *) validator->arg, PROKIND_FUNCTION, 2, funcargtypes, false); /* validator's return value is ignored, so we don't check the type */ } diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 8864d9ae44..48228fec42 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1099,7 +1099,9 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) languageValidator, prosrc_str, /* converted to text later */ probin_str, /* converted to text later */ - stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION), + stmt->is_procedure ? PROKIND_PROCEDURE : PROKIND_FUNCTION, + false, /* not an aggregate */ + isWindowFunc, security, isLeakProof, isStrict, @@ -1127,7 +1129,7 @@ RemoveFunctionById(Oid funcOid) { Relation relation; HeapTuple tup; - char prokind; + bool isagg; /* * Delete the pg_proc tuple. @@ -1138,7 +1140,7 @@ RemoveFunctionById(Oid funcOid) if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for function %u", funcOid); - prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind; + isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg; CatalogTupleDelete(relation, &tup->t_self); @@ -1149,7 +1151,7 @@ RemoveFunctionById(Oid funcOid) /* * If there's a pg_aggregate tuple, delete that too. */ - if (prokind == PROKIND_AGGREGATE) + if (isagg) { relation = heap_open(AggregateRelationId, RowExclusiveLock); @@ -1204,7 +1206,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) aclcheck_error(ACLCHECK_NOT_OWNER, stmt->objtype, NameListToString(stmt->func->objname)); - if (procForm->prokind == PROKIND_AGGREGATE) + if (procForm->proisagg) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an aggregate function", @@ -1526,10 +1528,14 @@ CreateCast(CreateCastStmt *stmt) (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("cast function must not be volatile"))); #endif - if (procstruct->prokind != PROKIND_FUNCTION) + if (procstruct->proisagg) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("cast function must be a normal function"))); + errmsg("cast function must not be an aggregate function"))); + if (procstruct->proiswindow) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cast function must not be a window function"))); if (procstruct->proretset) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), @@ -1774,10 +1780,14 @@ check_transform_function(Form_pg_proc procstruct) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("transform function must not be volatile"))); - if (procstruct->prokind != PROKIND_FUNCTION) + if (procstruct->proisagg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("transform function must not be an aggregate function"))); + if (procstruct->proiswindow) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("transform function must be a normal function"))); + errmsg("transform function must not be a window function"))); if (procstruct->proretset) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), @@ -2056,14 +2066,15 @@ DropTransformById(Oid transformOid) * namespace? If so, raise an appropriate error message. */ void -IsThereFunctionInNamespace(const char *proname, int pronargs, +IsThereFunctionInNamespace(const char *proname, char prokind, int pronargs, oidvector *proargtypes, Oid nspOid) { /* check for duplicate name (more friendly than unique-index failure) */ - if (SearchSysCacheExists3(PROCNAMEARGSNSP, + if (SearchSysCacheExists4(PROCNAMEARGSNSPKIND, CStringGetDatum(proname), PointerGetDatum(proargtypes), - ObjectIdGetDatum(nspOid))) + ObjectIdGetDatum(nspOid), + CharGetDatum(prokind))) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_FUNCTION), errmsg("function %s already exists in schema \"%s\"", diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index f0da4c5279..ec6cb90803 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -40,6 +40,7 @@ #include "catalog/indexing.h" #include "catalog/objectaccess.h" #include "catalog/pg_operator.h" +#include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/alter.h" #include "commands/defrem.h" @@ -205,7 +206,7 @@ DefineOperator(List *names, List *parameters) typeId[1] = typeId2; nargs = 2; } - functionOid = LookupFuncName(functionName, nargs, typeId, false); + functionOid = LookupFuncName(functionName, PROKIND_FUNCTION, nargs, typeId, false); /* * We require EXECUTE rights for the function. This isn't strictly @@ -268,7 +269,7 @@ ValidateRestrictionEstimator(List *restrictionName) typeId[2] = INTERNALOID; /* args list */ typeId[3] = INT4OID; /* varRelid */ - restrictionOid = LookupFuncName(restrictionName, 4, typeId, false); + restrictionOid = LookupFuncName(restrictionName, PROKIND_FUNCTION, 4, typeId, false); /* estimators must return float8 */ if (get_func_rettype(restrictionOid) != FLOAT8OID) @@ -309,12 +310,12 @@ ValidateJoinEstimator(List *joinName) * arguments, but we still allow the old 4-argument form. Try the * preferred form first. */ - joinOid = LookupFuncName(joinName, 5, typeId, true); + joinOid = LookupFuncName(joinName, PROKIND_FUNCTION, 5, typeId, true); if (!OidIsValid(joinOid)) - joinOid = LookupFuncName(joinName, 4, typeId, true); + joinOid = LookupFuncName(joinName, PROKIND_FUNCTION, 4, typeId, true); /* If not found, reference the 5-argument signature in error msg */ if (!OidIsValid(joinOid)) - joinOid = LookupFuncName(joinName, 5, typeId, false); + joinOid = LookupFuncName(joinName, PROKIND_FUNCTION, 5, typeId, false); /* estimators must return float8 */ if (get_func_rettype(joinOid) != FLOAT8OID) diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index c900ad9431..32851d5932 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -106,7 +106,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) * return type. */ funcname = SystemFuncName(pltemplate->tmplhandler); - handlerOid = LookupFuncName(funcname, 0, funcargtypes, true); + handlerOid = LookupFuncName(funcname, PROKIND_FUNCTION, 0, funcargtypes, true); if (OidIsValid(handlerOid)) { funcrettype = get_func_rettype(handlerOid); @@ -129,6 +129,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) pltemplate->tmplhandler, pltemplate->tmpllibrary, PROKIND_FUNCTION, + false, /* isAgg */ + false, /* isWindowFunc */ false, /* security_definer */ false, /* isLeakProof */ false, /* isStrict */ @@ -154,7 +156,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) { funcname = SystemFuncName(pltemplate->tmplinline); funcargtypes[0] = INTERNALOID; - inlineOid = LookupFuncName(funcname, 1, funcargtypes, true); + inlineOid = LookupFuncName(funcname, PROKIND_FUNCTION, 1, funcargtypes, true); if (!OidIsValid(inlineOid)) { tmpAddr = ProcedureCreate(pltemplate->tmplinline, @@ -168,6 +170,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) pltemplate->tmplinline, pltemplate->tmpllibrary, PROKIND_FUNCTION, + false, /* isAgg */ + false, /* isWindowFunc */ false, /* security_definer */ false, /* isLeakProof */ true, /* isStrict */ @@ -196,7 +200,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) { funcname = SystemFuncName(pltemplate->tmplvalidator); funcargtypes[0] = OIDOID; - valOid = LookupFuncName(funcname, 1, funcargtypes, true); + valOid = LookupFuncName(funcname, PROKIND_FUNCTION, 1, funcargtypes, true); if (!OidIsValid(valOid)) { tmpAddr = ProcedureCreate(pltemplate->tmplvalidator, @@ -210,6 +214,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) pltemplate->tmplvalidator, pltemplate->tmpllibrary, PROKIND_FUNCTION, + false, /* isAgg */ + false, /* isWindowFunc */ false, /* security_definer */ false, /* isLeakProof */ true, /* isStrict */ @@ -261,7 +267,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) * Lookup the PL handler function and check that it is of the expected * return type */ - handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false); + handlerOid = LookupFuncName(stmt->plhandler, PROKIND_FUNCTION, 0, funcargtypes, false); funcrettype = get_func_rettype(handlerOid); if (funcrettype != LANGUAGE_HANDLEROID) { @@ -290,7 +296,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) if (stmt->plinline) { funcargtypes[0] = INTERNALOID; - inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false); + inlineOid = LookupFuncName(stmt->plinline, PROKIND_FUNCTION, 1, funcargtypes, false); /* return value is ignored, so we don't check the type */ } else @@ -300,7 +306,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) if (stmt->plvalidator) { funcargtypes[0] = OIDOID; - valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false); + valOid = LookupFuncName(stmt->plvalidator, PROKIND_FUNCTION, 1, funcargtypes, false); /* return value is ignored, so we don't check the type */ } else diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 57519fe8d6..4d84dab02a 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -667,7 +667,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, * Find and validate the trigger function. */ if (!OidIsValid(funcoid)) - funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false); + funcoid = LookupFuncName(stmt->funcname, PROKIND_FUNCTION, 0, fargtypes, false); if (!isInternal) { aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE); diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index 3a843512d1..ede550a143 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -108,7 +108,7 @@ get_ts_parser_func(DefElem *defel, int attnum) nargs = 0; /* keep compiler quiet */ } - procOid = LookupFuncName(funcName, nargs, typeId, false); + procOid = LookupFuncName(funcName, PROKIND_FUNCTION, nargs, typeId, false); if (get_func_rettype(procOid) != retTypeId) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), @@ -672,7 +672,7 @@ get_ts_template_func(DefElem *defel, int attnum) nargs = 0; /* keep compiler quiet */ } - procOid = LookupFuncName(funcName, nargs, typeId, false); + procOid = LookupFuncName(funcName, PROKIND_FUNCTION, nargs, typeId, false); if (get_func_rettype(procOid) != retTypeId) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 175ecc8b48..9b953f94e0 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -1670,6 +1670,8 @@ makeRangeConstructors(const char *name, Oid namespace, prosrc[i], /* prosrc */ NULL, /* probin */ PROKIND_FUNCTION, + false, /* isAgg */ + false, /* isWindowFunc */ false, /* security_definer */ false, /* leakproof */ false, /* isStrict */ @@ -1717,28 +1719,28 @@ findTypeInputFunction(List *procname, Oid typeOid) */ argList[0] = CSTRINGOID; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (OidIsValid(procOid)) return procOid; argList[1] = OIDOID; argList[2] = INT4OID; - procOid = LookupFuncName(procname, 3, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 3, argList, true); if (OidIsValid(procOid)) return procOid; /* No luck, try it with OPAQUE */ argList[0] = OPAQUEOID; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (!OidIsValid(procOid)) { argList[1] = OIDOID; argList[2] = INT4OID; - procOid = LookupFuncName(procname, 3, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 3, argList, true); } if (OidIsValid(procOid)) @@ -1783,14 +1785,14 @@ findTypeOutputFunction(List *procname, Oid typeOid) */ argList[0] = typeOid; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (OidIsValid(procOid)) return procOid; /* No luck, try it with OPAQUE */ argList[0] = OPAQUEOID; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (OidIsValid(procOid)) { @@ -1832,14 +1834,14 @@ findTypeReceiveFunction(List *procname, Oid typeOid) */ argList[0] = INTERNALOID; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (OidIsValid(procOid)) return procOid; argList[1] = OIDOID; argList[2] = INT4OID; - procOid = LookupFuncName(procname, 3, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 3, argList, true); if (OidIsValid(procOid)) return procOid; @@ -1862,7 +1864,7 @@ findTypeSendFunction(List *procname, Oid typeOid) */ argList[0] = typeOid; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (OidIsValid(procOid)) return procOid; @@ -1885,7 +1887,7 @@ findTypeTypmodinFunction(List *procname) */ argList[0] = CSTRINGARRAYOID; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (!OidIsValid(procOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), @@ -1912,7 +1914,7 @@ findTypeTypmodoutFunction(List *procname) */ argList[0] = INT4OID; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (!OidIsValid(procOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), @@ -1939,7 +1941,7 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid) */ argList[0] = INTERNALOID; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (!OidIsValid(procOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), @@ -2015,7 +2017,7 @@ findRangeCanonicalFunction(List *procname, Oid typeOid) */ argList[0] = typeOid; - procOid = LookupFuncName(procname, 1, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 1, argList, true); if (!OidIsValid(procOid)) ereport(ERROR, @@ -2057,7 +2059,7 @@ findRangeSubtypeDiffFunction(List *procname, Oid subtype) argList[0] = subtype; argList[1] = subtype; - procOid = LookupFuncName(procname, 2, argList, true); + procOid = LookupFuncName(procname, PROKIND_FUNCTION, 2, argList, true); if (!OidIsValid(procOid)) ereport(ERROR, diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 23545896d4..584dad6d18 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -241,13 +241,13 @@ prepare_sql_fn_parse_info(HeapTuple procedureTuple, int n_arg_names; bool isNull; - proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple, + proargnames = SysCacheGetAttr(PROCNAMEARGSNSPKIND, procedureTuple, Anum_pg_proc_proargnames, &isNull); if (isNull) proargnames = PointerGetDatum(NULL); /* just to be sure */ - proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple, + proargmodes = SysCacheGetAttr(PROCNAMEARGSNSPKIND, procedureTuple, Anum_pg_proc_proargmodes, &isNull); if (isNull) @@ -390,7 +390,7 @@ sql_fn_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var) list_make1(param), pstate->p_last_srf, NULL, - false, + PROKIND_FUNCTION, cref->location); } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 505ae0af85..f5f615fd16 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -4482,10 +4482,9 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, /* * Forget it if the function is not SQL-language or has other showstopper - * properties. (The prokind and nargs checks are just paranoia.) + * properties. (The nargs check is just paranoia.) */ if (funcform->prolang != SQLlanguageId || - funcform->prokind != PROKIND_FUNCTION || funcform->prosecdef || funcform->proretset || funcform->prorettype == RECORDOID || diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 05f57591e4..aa3cde2d3f 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -25,6 +25,7 @@ #include "postgres.h" #include "access/sysattr.h" +#include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -2599,7 +2600,7 @@ transformCallStmt(ParseState *pstate, CallStmt *stmt) targs, pstate->p_last_srf, stmt->funccall, - true, + PROKIND_PROCEDURE, stmt->funccall->location); stmt->funcexpr = castNode(FuncExpr, node); diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index e1478805c2..99c00bc7ab 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -27,6 +27,7 @@ #include "catalog/pg_amproc.h" #include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" +#include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/defrem.h" #include "nodes/makefuncs.h" @@ -972,7 +973,7 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts) */ funcargtypes[0] = INTERNALOID; - handlerOid = LookupFuncName(rts->method, 1, funcargtypes, true); + handlerOid = LookupFuncName(rts->method, PROKIND_FUNCTION, 1, funcargtypes, true); /* we want error to complain about no-such-method, not no-such-function */ if (!OidIsValid(handlerOid)) diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index c31a5630b2..0764a67d67 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -834,7 +834,8 @@ build_coercion_expression(Node *node, */ /* Assert(targetTypeId == procstruct->prorettype); */ Assert(!procstruct->proretset); - Assert(procstruct->prokind == PROKIND_FUNCTION); + Assert(!procstruct->proisagg); + Assert(!procstruct->proiswindow); nargs = procstruct->pronargs; Assert(nargs >= 1 && nargs <= 3); /* Assert(procstruct->proargtypes.values[0] == exprType(node)); */ diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 385e54a9b6..6329db67d6 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -15,6 +15,7 @@ #include "postgres.h" +#include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/dbcommands.h" #include "miscadmin.h" @@ -480,7 +481,7 @@ transformIndirection(ParseState *pstate, A_Indirection *ind) list_make1(result), last_srf, NULL, - false, + PROKIND_FUNCTION, location); if (newresult == NULL) unknown_attribute(pstate, result, strVal(n), location); @@ -630,7 +631,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) list_make1(node), pstate->p_last_srf, NULL, - false, + PROKIND_FUNCTION, cref->location); } break; @@ -678,7 +679,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) list_make1(node), pstate->p_last_srf, NULL, - false, + PROKIND_FUNCTION, cref->location); } break; @@ -739,7 +740,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) list_make1(node), pstate->p_last_srf, NULL, - false, + PROKIND_FUNCTION, cref->location); } break; @@ -1481,7 +1482,7 @@ transformFuncCall(ParseState *pstate, FuncCall *fn) targs, last_srf, fn, - false, + PROKIND_FUNCTION, fn->location); } diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index ea5d5212b4..1a89085e7c 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -71,7 +71,7 @@ static Node *ParseComplexProjection(ParseState *pstate, const char *funcname, */ Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, - Node *last_srf, FuncCall *fn, bool proc_call, int location) + Node *last_srf, FuncCall *fn, char prokind, int location) { bool is_column = (fn == NULL); List *agg_order = (fn ? fn->agg_order : NIL); @@ -244,7 +244,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, setup_parser_errposition_callback(&pcbstate, pstate, location); - fdresult = func_get_detail(funcname, fargs, argnames, nargs, + fdresult = func_get_detail(funcname, prokind, fargs, argnames, nargs, actual_arg_types, !func_variadic, true, &funcid, &rettype, &retset, @@ -263,7 +263,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, actual_arg_types[0], rettype, -1, COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location); } - else if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE) + else if (fdresult == FUNCDETAIL_NORMAL) { /* * Normal function found; was there anything indicating it must be an @@ -306,26 +306,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, errmsg("OVER specified, but %s is not a window function nor an aggregate function", NameListToString(funcname)), parser_errposition(pstate, location))); - - if (fdresult == FUNCDETAIL_NORMAL && proc_call) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("%s is not a procedure", - func_signature_string(funcname, nargs, - argnames, - actual_arg_types)), - errhint("To call a function, use SELECT."), - parser_errposition(pstate, location))); - - if (fdresult == FUNCDETAIL_PROCEDURE && !proc_call) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("%s is a procedure", - func_signature_string(funcname, nargs, - argnames, - actual_arg_types)), - errhint("To call a procedure, use CALL."), - parser_errposition(pstate, location))); } else if (fdresult == FUNCDETAIL_AGGREGATE) { @@ -336,15 +316,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, Form_pg_aggregate classForm; int catDirectArgs; - if (proc_call) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("%s is not a procedure", - func_signature_string(funcname, nargs, - argnames, - actual_arg_types)), - parser_errposition(pstate, location))); - tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for aggregate %u", funcid); @@ -546,6 +517,15 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, "after all regular arguments of the aggregate."), parser_errposition(pstate, location))); } + else if (prokind == PROKIND_PROCEDURE) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("procedure %s does not exist", + func_signature_string(funcname, nargs, argnames, + actual_arg_types)), + errhint("No procedure matches the given name and argument types. " + "You might need to add explicit type casts."), + parser_errposition(pstate, location))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), @@ -664,7 +644,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, check_srf_call_placement(pstate, last_srf, location); /* build the appropriate output structure */ - if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE) + if (fdresult == FUNCDETAIL_NORMAL) { FuncExpr *funcexpr = makeNode(FuncExpr); @@ -1310,6 +1290,7 @@ func_select_candidate(int nargs, */ FuncDetailCode func_get_detail(List *funcname, + char prokind, List *fargs, List *fargnames, int nargs, @@ -1341,7 +1322,7 @@ func_get_detail(List *funcname, *argdefaults = NIL; /* Get list of possible candidates from namespace search */ - raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames, + raw_candidates = FuncnameGetCandidates(funcname, prokind, nargs, fargnames, expand_variadic, expand_defaults, false); @@ -1615,26 +1596,12 @@ func_get_detail(List *funcname, } } - switch (pform->prokind) - { - case PROKIND_AGGREGATE: - result = FUNCDETAIL_AGGREGATE; - break; - case PROKIND_FUNCTION: - result = FUNCDETAIL_NORMAL; - break; - case PROKIND_PROCEDURE: - result = FUNCDETAIL_PROCEDURE; - break; - case PROKIND_WINDOW: - result = FUNCDETAIL_WINDOWFUNC; - break; - default: - elog(ERROR, "unrecognized prokind: %c", pform->prokind); - result = FUNCDETAIL_NORMAL; /* keep compiler quiet */ - break; - } - + if (pform->proisagg) + result = FUNCDETAIL_AGGREGATE; + else if (pform->proiswindow) + result = FUNCDETAIL_WINDOWFUNC; + else + result = FUNCDETAIL_NORMAL; ReleaseSysCache(ftup); return result; } @@ -1971,14 +1938,14 @@ func_signature_string(List *funcname, int nargs, * else raise an error. */ Oid -LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError) +LookupFuncName(List *funcname, char prokind, int nargs, const Oid *argtypes, bool noError) { FuncCandidateList clist; /* Passing NULL for argtypes is no longer allowed */ Assert(argtypes); - clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError); + clist = FuncnameGetCandidates(funcname, prokind, nargs, NIL, false, false, noError); /* * If no arguments were specified, the name must yield a unique candidate. @@ -1990,11 +1957,20 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError) if (clist->next) { if (!noError) - ereport(ERROR, - (errcode(ERRCODE_AMBIGUOUS_FUNCTION), - errmsg("function name \"%s\" is not unique", - NameListToString(funcname)), - errhint("Specify the argument list to select the function unambiguously."))); + { + if (prokind == PROKIND_PROCEDURE) + ereport(ERROR, + (errcode(ERRCODE_AMBIGUOUS_FUNCTION), + errmsg("procedure name \"%s\" is not unique", + NameListToString(funcname)), + errhint("Specify the argument list to select the procedure unambiguously."))); + else + ereport(ERROR, + (errcode(ERRCODE_AMBIGUOUS_FUNCTION), + errmsg("function name \"%s\" is not unique", + NameListToString(funcname)), + errhint("Specify the argument list to select the function unambiguously."))); + } } else return clist->oid; @@ -2002,10 +1978,18 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError) else { if (!noError) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("could not find a function named \"%s\"", - NameListToString(funcname)))); + { + if (prokind == PROKIND_PROCEDURE) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("could not find a procedure named \"%s\"", + NameListToString(funcname)))); + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("could not find a function named \"%s\"", + NameListToString(funcname)))); + } } } @@ -2017,11 +2001,20 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError) } if (!noError) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function %s does not exist", - func_signature_string(funcname, nargs, - NIL, argtypes)))); + { + if (prokind == PROKIND_PROCEDURE) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("procedure %s does not exist", + func_signature_string(funcname, nargs, + NIL, argtypes)))); + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(funcname, nargs, + NIL, argtypes)))); + } return InvalidOid; } @@ -2040,16 +2033,29 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError) Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError) { + char prokind; Oid argoids[FUNC_MAX_ARGS]; int argcount; int i; ListCell *args_item; Oid oid; - Assert(objtype == OBJECT_AGGREGATE || - objtype == OBJECT_FUNCTION || - objtype == OBJECT_PROCEDURE || - objtype == OBJECT_ROUTINE); + switch (objtype) + { + case OBJECT_AGGREGATE: + case OBJECT_FUNCTION: + prokind = PROKIND_FUNCTION; + break; + case OBJECT_PROCEDURE: + prokind = PROKIND_PROCEDURE; + break; + case OBJECT_ROUTINE: + prokind = PROKIND_ANY; + break; + default: + elog(ERROR, "unexpected objtype: %d", (int) objtype); + prokind = 0; + } argcount = list_length(func->objargs); if (argcount > FUNC_MAX_ARGS) @@ -2069,60 +2075,14 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError) args_item = lnext(args_item); } + oid = LookupFuncName(func->objname, prokind, func->args_unspecified ? -1 : argcount, argoids, + objtype != OBJECT_AGGREGATE ? noError : true); + /* - * When looking for a function or routine, we pass noError through to - * LookupFuncName and let it make any error messages. Otherwise, we make - * our own errors for the aggregate and procedure cases. + * Handle error checking for OBJECT_AGGREGATE here, since LookupFuncName() + * doesn't distinguish aggregates. */ - oid = LookupFuncName(func->objname, func->args_unspecified ? -1 : argcount, argoids, - (objtype == OBJECT_FUNCTION || objtype == OBJECT_ROUTINE) ? noError : true); - - if (objtype == OBJECT_FUNCTION) - { - /* Make sure it's a function, not a procedure */ - if (oid && get_func_prokind(oid) == PROKIND_PROCEDURE) - { - if (noError) - return InvalidOid; - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s is not a function", - func_signature_string(func->objname, argcount, - NIL, argoids)))); - } - } - else if (objtype == OBJECT_PROCEDURE) - { - if (!OidIsValid(oid)) - { - if (noError) - return InvalidOid; - else if (func->args_unspecified) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("could not find a procedure named \"%s\"", - NameListToString(func->objname)))); - else - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("procedure %s does not exist", - func_signature_string(func->objname, argcount, - NIL, argoids)))); - } - - /* Make sure it's a procedure */ - if (get_func_prokind(oid) != PROKIND_PROCEDURE) - { - if (noError) - return InvalidOid; - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s is not a procedure", - func_signature_string(func->objname, argcount, - NIL, argoids)))); - } - } - else if (objtype == OBJECT_AGGREGATE) + if (objtype == OBJECT_AGGREGATE) { if (!OidIsValid(oid)) { @@ -2147,7 +2107,7 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError) } /* Make sure it's an aggregate */ - if (get_func_prokind(oid) != PROKIND_AGGREGATE) + if (!get_func_isagg(oid)) { if (noError) return InvalidOid; diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index a0079821fe..3c321b1a12 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -94,7 +94,7 @@ regprocin(PG_FUNCTION_ARGS) * pg_proc entries in the current search path. */ names = stringToQualifiedNameList(pro_name_or_oid); - clist = FuncnameGetCandidates(names, -1, NIL, false, false, false); + clist = FuncnameGetCandidates(names, PROKIND_ANY, -1, NIL, false, false, false); if (clist == NULL) ereport(ERROR, @@ -128,7 +128,7 @@ to_regproc(PG_FUNCTION_ARGS) * entries in the current search path. */ names = stringToQualifiedNameList(pro_name); - clist = FuncnameGetCandidates(names, -1, NIL, false, false, true); + clist = FuncnameGetCandidates(names, PROKIND_ANY, -1, NIL, false, false, true); if (clist == NULL || clist->next != NULL) PG_RETURN_NULL(); @@ -176,7 +176,7 @@ regprocout(PG_FUNCTION_ARGS) * qualify it. */ clist = FuncnameGetCandidates(list_make1(makeString(proname)), - -1, NIL, false, false, false); + PROKIND_ANY, -1, NIL, false, false, false); if (clist != NULL && clist->next == NULL && clist->oid == proid) nspname = NULL; @@ -263,7 +263,7 @@ regprocedurein(PG_FUNCTION_ARGS) */ parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes); - clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false); + clist = FuncnameGetCandidates(names, PROKIND_ANY, nargs, NIL, false, false, false); for (; clist; clist = clist->next) { @@ -302,7 +302,7 @@ to_regprocedure(PG_FUNCTION_ARGS) */ parseNameAndArgTypes(pro_name, false, &names, &nargs, argtypes); - clist = FuncnameGetCandidates(names, nargs, NIL, false, false, true); + clist = FuncnameGetCandidates(names, PROKIND_ANY, nargs, NIL, false, false, true); for (; clist; clist = clist->next) { diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 065238b0fe..e8cdb6d883 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -2514,7 +2514,7 @@ pg_get_functiondef(PG_FUNCTION_ARGS) proc = (Form_pg_proc) GETSTRUCT(proctup); name = NameStr(proc->proname); - if (proc->prokind == PROKIND_AGGREGATE) + if (proc->proisagg) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an aggregate function", name))); @@ -2546,7 +2546,7 @@ pg_get_functiondef(PG_FUNCTION_ARGS) /* Emit some miscellaneous options on one line */ oldlen = buf.len; - if (proc->prokind == PROKIND_WINDOW) + if (proc->proiswindow) appendStringInfoString(&buf, " WINDOW"); switch (proc->provolatile) { @@ -2854,7 +2854,7 @@ print_function_arguments(StringInfo buf, HeapTuple proctup, } /* Check for special treatment of ordered-set aggregates */ - if (proc->prokind == PROKIND_AGGREGATE) + if (proc->proisagg) { HeapTuple aggtup; Form_pg_aggregate agg; @@ -10785,6 +10785,7 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, */ if (!force_qualify) p_result = func_get_detail(list_make1(makeString(proname)), + procform->prokind, NIL, argnames, nargs, argtypes, !use_variadic, true, &p_funcid, &p_rettype, diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index bba595ad1d..51b6b4f7bb 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -1600,20 +1600,20 @@ func_parallel(Oid funcid) } /* - * get_func_prokind - * Given procedure id, return the routine kind. + * get_func_isagg + * Given procedure id, return the function's proisagg field. */ -char -get_func_prokind(Oid funcid) +bool +get_func_isagg(Oid funcid) { HeapTuple tp; - char result; + bool result; tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); - result = ((Form_pg_proc) GETSTRUCT(tp))->prokind; + result = ((Form_pg_proc) GETSTRUCT(tp))->proisagg; ReleaseSysCache(tp); return result; } diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 2b381782a3..aff1fc9171 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -584,14 +584,14 @@ static const struct cachedesc cacheinfo[] = { }, 32 }, - {ProcedureRelationId, /* PROCNAMEARGSNSP */ - ProcedureNameArgsNspIndexId, - 3, + {ProcedureRelationId, /* PROCNAMEARGSNSPKIND */ + ProcedureNameArgsNspKindIndexId, + 4, { Anum_pg_proc_proname, Anum_pg_proc_proargtypes, Anum_pg_proc_pronamespace, - 0 + Anum_pg_proc_prokind, }, 128 }, diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index d6ceb72c05..e58d83e754 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -5424,15 +5424,11 @@ getAggregates(Archive *fout, int *numAggs) PQExpBuffer racl_subquery = createPQExpBuffer(); PQExpBuffer initacl_subquery = createPQExpBuffer(); PQExpBuffer initracl_subquery = createPQExpBuffer(); - const char *agg_check; buildACLQueries(acl_subquery, racl_subquery, initacl_subquery, initracl_subquery, "p.proacl", "p.proowner", "'f'", dopt->binary_upgrade); - agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'" - : "p.proisagg"); - appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, " "p.proname AS aggname, " "p.pronamespace AS aggnamespace, " @@ -5447,7 +5443,7 @@ getAggregates(Archive *fout, int *numAggs) "(p.oid = pip.objoid " "AND pip.classoid = 'pg_proc'::regclass " "AND pip.objsubid = 0) " - "WHERE %s AND (" + "WHERE p.proisagg AND (" "p.pronamespace != " "(SELECT oid FROM pg_namespace " "WHERE nspname = 'pg_catalog') OR " @@ -5456,8 +5452,7 @@ getAggregates(Archive *fout, int *numAggs) acl_subquery->data, racl_subquery->data, initacl_subquery->data, - initracl_subquery->data, - agg_check); + initracl_subquery->data); if (dopt->binary_upgrade) appendPQExpBufferStr(query, " OR EXISTS(SELECT 1 FROM pg_depend WHERE " @@ -5638,15 +5633,11 @@ getFuncs(Archive *fout, int *numFuncs) PQExpBuffer racl_subquery = createPQExpBuffer(); PQExpBuffer initacl_subquery = createPQExpBuffer(); PQExpBuffer initracl_subquery = createPQExpBuffer(); - const char *not_agg_check; buildACLQueries(acl_subquery, racl_subquery, initacl_subquery, initracl_subquery, "p.proacl", "p.proowner", "'f'", dopt->binary_upgrade); - not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'" - : "NOT p.proisagg"); - appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, p.proname, p.prolang, " "p.pronargs, p.proargtypes, p.prorettype, " @@ -5661,7 +5652,7 @@ getFuncs(Archive *fout, int *numFuncs) "(p.oid = pip.objoid " "AND pip.classoid = 'pg_proc'::regclass " "AND pip.objsubid = 0) " - "WHERE %s" + "WHERE NOT p.proisagg" "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " "WHERE classid = 'pg_proc'::regclass AND " "objid = p.oid AND deptype = 'i')" @@ -5681,7 +5672,6 @@ getFuncs(Archive *fout, int *numFuncs) initacl_subquery->data, initracl_subquery->data, username_subquery, - not_agg_check, g_last_builtin_oid, g_last_builtin_oid); if (dopt->binary_upgrade) @@ -11474,6 +11464,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) char *proargnames; char *protrftypes; char *prokind; + char *proiswindow; char *provolatile; char *proisstrict; char *prosecdef; @@ -11514,7 +11505,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, " "pg_catalog.pg_get_function_result(oid) AS funcresult, " "array_to_string(protrftypes, ' ') AS protrftypes, " - "prokind, provolatile, proisstrict, prosecdef, " + "prokind, proiswindow, provolatile, proisstrict, prosecdef, " "proleakproof, proconfig, procost, prorows, " "proparallel, " "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " @@ -11533,8 +11524,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, " "pg_catalog.pg_get_function_result(oid) AS funcresult, " "array_to_string(protrftypes, ' ') AS protrftypes, " - "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, " - "provolatile, proisstrict, prosecdef, " + "'f' AS prokind, " + "proiswindow, provolatile, proisstrict, prosecdef, " "proleakproof, proconfig, procost, prorows, " "proparallel, " "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " @@ -11553,8 +11544,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, " "pg_catalog.pg_get_function_result(oid) AS funcresult, " "array_to_string(protrftypes, ' ') AS protrftypes, " - "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, " - "provolatile, proisstrict, prosecdef, " + "'f' AS prokind, " + "proiswindow, provolatile, proisstrict, prosecdef, " "proleakproof, proconfig, procost, prorows, " "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " "FROM pg_catalog.pg_proc " @@ -11571,8 +11562,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "pg_catalog.pg_get_function_arguments(oid) AS funcargs, " "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, " "pg_catalog.pg_get_function_result(oid) AS funcresult, " - "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, " - "provolatile, proisstrict, prosecdef, " + "'f' AS prokind, " + "proiswindow, provolatile, proisstrict, prosecdef, " "proleakproof, proconfig, procost, prorows, " "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " "FROM pg_catalog.pg_proc " @@ -11590,8 +11581,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "pg_catalog.pg_get_function_arguments(oid) AS funcargs, " "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, " "pg_catalog.pg_get_function_result(oid) AS funcresult, " - "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, " - "provolatile, proisstrict, prosecdef, " + "'f' AS prokind, " + "proiswindow, provolatile, proisstrict, prosecdef, " "false AS proleakproof, " " proconfig, procost, prorows, " "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " @@ -11604,7 +11595,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) appendPQExpBuffer(query, "SELECT proretset, prosrc, probin, " "proallargtypes, proargmodes, proargnames, " - "'f' AS prokind, " + "'f' AS prokind, false AS proiswindow, " "provolatile, proisstrict, prosecdef, " "false AS proleakproof, " "proconfig, procost, prorows, " @@ -11618,7 +11609,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) appendPQExpBuffer(query, "SELECT proretset, prosrc, probin, " "proallargtypes, proargmodes, proargnames, " - "'f' AS prokind, " + "'f' AS prokind, false AS proiswindow, " "provolatile, proisstrict, prosecdef, " "false AS proleakproof, " "null AS proconfig, 0 AS procost, 0 AS prorows, " @@ -11634,7 +11625,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "null AS proallargtypes, " "null AS proargmodes, " "proargnames, " - "'f' AS prokind, " + "'f' AS prokind, false AS proiswindow, " "provolatile, proisstrict, prosecdef, " "false AS proleakproof, " "null AS proconfig, 0 AS procost, 0 AS prorows, " @@ -11668,6 +11659,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) else protrftypes = NULL; prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind")); + proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow")); provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile")); proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict")); prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef")); @@ -11841,7 +11833,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) } } - if (prokind[0] == PROKIND_WINDOW) + if (proiswindow[0] == 't') appendPQExpBufferStr(q, " WINDOW"); if (provolatile[0] != PROVOLATILE_VOLATILE) diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index fe036b57ee..dc0883ca27 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -2995,6 +2995,8 @@ provariadic, protransform, prokind, + proisagg, + proiswindow, prosecdef, proleakproof, proisstrict, @@ -3027,6 +3029,8 @@ \QGRANT SELECT(provariadic) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(protransform) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(prokind) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proisagg) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proiswindow) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(prosecdef) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(proleakproof) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(proisstrict) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.* diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index e5b3c1ebf9..a71f2a67d6 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -100,20 +100,12 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem) " pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n", gettext_noop("Argument data types")); - if (pset.sversion >= 110000) - appendPQExpBuffer(&buf, - " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n" - "FROM pg_catalog.pg_proc p\n" - " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n" - "WHERE p.prokind = 'a'\n", - gettext_noop("Description")); - else - appendPQExpBuffer(&buf, - " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n" - "FROM pg_catalog.pg_proc p\n" - " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n" - "WHERE p.proisagg\n", - gettext_noop("Description")); + appendPQExpBuffer(&buf, + " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n" + "FROM pg_catalog.pg_proc p\n" + " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n" + "WHERE p.proisagg\n", + gettext_noop("Description")); if (!showSystem && !pattern) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" @@ -358,18 +350,18 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool appendPQExpBuffer(&buf, " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n" " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n" - " CASE p.prokind\n" - " WHEN 'a' THEN '%s'\n" - " WHEN 'w' THEN '%s'\n" - " WHEN 'p' THEN '%s'\n" + " CASE\n" + " WHEN p.prokind = 'p' THEN '%s'\n" + " WHEN p.proisagg THEN '%s'\n" + " WHEN p.proiswindow THEN '%s'\n" " ELSE '%s'\n" " END as \"%s\"", gettext_noop("Result data type"), gettext_noop("Argument data types"), + gettext_noop("proc"), /* translator: "agg" is short for "aggregate" */ gettext_noop("agg"), gettext_noop("window"), - gettext_noop("proc"), gettext_noop("func"), gettext_noop("Type")); else if (pset.sversion >= 80400) diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 7bb47eadc6..41b26accb3 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -389,39 +389,21 @@ do { \ * Assembly instructions for schema queries */ -static const SchemaQuery Query_for_list_of_aggregates[] = { - { - /* min_server_version */ - 110000, - /* catname */ - "pg_catalog.pg_proc p", - /* selcondition */ - "p.prokind = 'a'", - /* viscondition */ - "pg_catalog.pg_function_is_visible(p.oid)", - /* namespace */ - "p.pronamespace", - /* result */ - "pg_catalog.quote_ident(p.proname)", - /* qualresult */ - NULL - }, - { - /* min_server_version */ - 0, - /* catname */ - "pg_catalog.pg_proc p", - /* selcondition */ - "p.proisagg", - /* viscondition */ - "pg_catalog.pg_function_is_visible(p.oid)", - /* namespace */ - "p.pronamespace", - /* result */ - "pg_catalog.quote_ident(p.proname)", - /* qualresult */ - NULL - } +static const SchemaQuery Query_for_list_of_aggregates = { + /* min_server_version */ + 0, + /* catname */ + "pg_catalog.pg_proc p", + /* selcondition */ + "p.proisagg", + /* viscondition */ + "pg_catalog.pg_function_is_visible(p.oid)", + /* namespace */ + "p.pronamespace", + /* result */ + "pg_catalog.quote_ident(p.proname)", + /* qualresult */ + NULL }; static const SchemaQuery Query_for_list_of_datatypes = { @@ -1191,7 +1173,7 @@ typedef struct static const pgsql_thing_t words_after_create[] = { {"ACCESS METHOD", NULL, NULL, NULL, THING_NO_ALTER}, - {"AGGREGATE", NULL, NULL, Query_for_list_of_aggregates}, + {"AGGREGATE", NULL, NULL, &Query_for_list_of_aggregates}, {"CAST", NULL, NULL, NULL}, /* Casts have complex structures for names, so * skip it */ {"COLLATION", "SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding())) AND substring(pg_catalog.quote_ident(collname),1,%d)='%s'"}, @@ -3634,7 +3616,7 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_QUERY(Query_for_list_of_roles); } else if (TailMatchesCS1("\\da*")) - COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL); else if (TailMatchesCS1("\\dA*")) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods); else if (TailMatchesCS1("\\db*")) diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 24915824ca..4a82055982 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -215,8 +215,8 @@ DECLARE_UNIQUE_INDEX(pg_pltemplate_name_index, 1137, on pg_pltemplate using btre DECLARE_UNIQUE_INDEX(pg_proc_oid_index, 2690, on pg_proc using btree(oid oid_ops)); #define ProcedureOidIndexId 2690 -DECLARE_UNIQUE_INDEX(pg_proc_proname_args_nsp_index, 2691, on pg_proc using btree(proname name_ops, proargtypes oidvector_ops, pronamespace oid_ops)); -#define ProcedureNameArgsNspIndexId 2691 +DECLARE_UNIQUE_INDEX(pg_proc_proname_args_nsp_kind_index, 2691, on pg_proc using btree(proname name_ops, proargtypes oidvector_ops, pronamespace oid_ops, prokind char_ops)); +#define ProcedureNameArgsNspKindIndexId 2691 DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index, 2692, on pg_rewrite using btree(oid oid_ops)); #define RewriteOidIndexId 2692 diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index 7991de5e21..45c68c37cb 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -80,6 +80,7 @@ extern Oid TypenameGetTypid(const char *typname); extern bool TypeIsVisible(Oid typid); extern FuncCandidateList FuncnameGetCandidates(List *names, + char prokind, int nargs, List *argnames, bool expand_variadic, bool expand_defaults, diff --git a/src/include/catalog/pg_class.dat b/src/include/catalog/pg_class.dat index 9fffdef379..045f255359 100644 --- a/src/include/catalog/pg_class.dat +++ b/src/include/catalog/pg_class.dat @@ -47,7 +47,7 @@ reloftype => '0', relowner => 'PGUID', relam => '0', relfilenode => '0', reltablespace => '0', relpages => '0', reltuples => '0', relallvisible => '0', reltoastrelid => '0', relhasindex => 'f', relisshared => 'f', - relpersistence => 'p', relkind => 'r', relnatts => '28', relchecks => '0', + relpersistence => 'p', relkind => 'r', relnatts => '30', relchecks => '0', relhasoids => 't', relhasrules => 'f', relhastriggers => 'f', relhassubclass => 'f', relrowsecurity => 'f', relforcerowsecurity => 'f', relispopulated => 't', relreplident => 'n', relispartition => 'f', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 66c6c224a8..0f905ceca5 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -1618,7 +1618,7 @@ proname => 'array_agg_finalfn', proisstrict => 'f', prorettype => 'anyarray', proargtypes => 'internal anynonarray', prosrc => 'array_agg_finalfn' }, { oid => '2335', descr => 'concatenate aggregate input into an array', - proname => 'array_agg', prokind => 'a', proisstrict => 'f', + proname => 'array_agg', proisagg => 't', proisstrict => 'f', prorettype => 'anyarray', proargtypes => 'anynonarray', prosrc => 'aggregate_dummy' }, { oid => '4051', descr => 'aggregate transition function', @@ -1630,7 +1630,7 @@ prorettype => 'anyarray', proargtypes => 'internal anyarray', prosrc => 'array_agg_array_finalfn' }, { oid => '4053', descr => 'concatenate aggregate input into an array', - proname => 'array_agg', prokind => 'a', proisstrict => 'f', + proname => 'array_agg', proisagg => 't', proisstrict => 'f', prorettype => 'anyarray', proargtypes => 'anyarray', prosrc => 'aggregate_dummy' }, { oid => '3218', @@ -4776,7 +4776,7 @@ proname => 'string_agg_finalfn', proisstrict => 'f', prorettype => 'text', proargtypes => 'internal', prosrc => 'string_agg_finalfn' }, { oid => '3538', descr => 'concatenate aggregate input into a string', - proname => 'string_agg', prokind => 'a', proisstrict => 'f', + proname => 'string_agg', proisagg => 't', proisstrict => 'f', prorettype => 'text', proargtypes => 'text text', prosrc => 'aggregate_dummy' }, { oid => '3543', descr => 'aggregate transition function', @@ -4788,7 +4788,7 @@ prorettype => 'bytea', proargtypes => 'internal', prosrc => 'bytea_string_agg_finalfn' }, { oid => '3545', descr => 'concatenate aggregate input into a bytea', - proname => 'string_agg', prokind => 'a', proisstrict => 'f', + proname => 'string_agg', proisagg => 't', proisstrict => 'f', prorettype => 'bytea', proargtypes => 'bytea bytea', prosrc => 'aggregate_dummy' }, @@ -6145,408 +6145,408 @@ { oid => '2100', descr => 'the average (arithmetic mean) as numeric of all bigint values', - proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proname => 'avg', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2101', descr => 'the average (arithmetic mean) as numeric of all integer values', - proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proname => 'avg', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2102', descr => 'the average (arithmetic mean) as numeric of all smallint values', - proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proname => 'avg', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2103', descr => 'the average (arithmetic mean) as numeric of all numeric values', - proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proname => 'avg', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2104', descr => 'the average (arithmetic mean) as float8 of all float4 values', - proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proname => 'avg', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2105', descr => 'the average (arithmetic mean) as float8 of all float8 values', - proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proname => 'avg', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2106', descr => 'the average (arithmetic mean) as interval of all interval values', - proname => 'avg', prokind => 'a', proisstrict => 'f', + proname => 'avg', proisagg => 't', proisstrict => 'f', prorettype => 'interval', proargtypes => 'interval', prosrc => 'aggregate_dummy' }, { oid => '2107', descr => 'sum as numeric across all bigint input values', - proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proname => 'sum', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2108', descr => 'sum as bigint across all integer input values', - proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proname => 'sum', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2109', descr => 'sum as bigint across all smallint input values', - proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proname => 'sum', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2110', descr => 'sum as float4 across all float4 input values', - proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'float4', + proname => 'sum', proisagg => 't', proisstrict => 'f', prorettype => 'float4', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2111', descr => 'sum as float8 across all float8 input values', - proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proname => 'sum', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2112', descr => 'sum as money across all money input values', - proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'money', + proname => 'sum', proisagg => 't', proisstrict => 'f', prorettype => 'money', proargtypes => 'money', prosrc => 'aggregate_dummy' }, { oid => '2113', descr => 'sum as interval across all interval input values', - proname => 'sum', prokind => 'a', proisstrict => 'f', + proname => 'sum', proisagg => 't', proisstrict => 'f', prorettype => 'interval', proargtypes => 'interval', prosrc => 'aggregate_dummy' }, { oid => '2114', descr => 'sum as numeric across all numeric input values', - proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proname => 'sum', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2115', descr => 'maximum value of all bigint input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2116', descr => 'maximum value of all integer input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'int4', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'int4', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2117', descr => 'maximum value of all smallint input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'int2', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'int2', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2118', descr => 'maximum value of all oid input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'oid', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'oid', proargtypes => 'oid', prosrc => 'aggregate_dummy' }, { oid => '2119', descr => 'maximum value of all float4 input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'float4', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'float4', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2120', descr => 'maximum value of all float8 input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2121', descr => 'maximum value of all abstime input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'abstime', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'abstime', proargtypes => 'abstime', prosrc => 'aggregate_dummy' }, { oid => '2122', descr => 'maximum value of all date input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'date', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'date', proargtypes => 'date', prosrc => 'aggregate_dummy' }, { oid => '2123', descr => 'maximum value of all time input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'time', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'time', proargtypes => 'time', prosrc => 'aggregate_dummy' }, { oid => '2124', descr => 'maximum value of all time with time zone input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'timetz', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'timetz', proargtypes => 'timetz', prosrc => 'aggregate_dummy' }, { oid => '2125', descr => 'maximum value of all money input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'money', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'money', proargtypes => 'money', prosrc => 'aggregate_dummy' }, { oid => '2126', descr => 'maximum value of all timestamp input values', - proname => 'max', prokind => 'a', proisstrict => 'f', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'timestamp', proargtypes => 'timestamp', prosrc => 'aggregate_dummy' }, { oid => '2127', descr => 'maximum value of all timestamp with time zone input values', - proname => 'max', prokind => 'a', proisstrict => 'f', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'timestamptz', proargtypes => 'timestamptz', prosrc => 'aggregate_dummy' }, { oid => '2128', descr => 'maximum value of all interval input values', - proname => 'max', prokind => 'a', proisstrict => 'f', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'interval', proargtypes => 'interval', prosrc => 'aggregate_dummy' }, { oid => '2129', descr => 'maximum value of all text input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'text', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'text', proargtypes => 'text', prosrc => 'aggregate_dummy' }, { oid => '2130', descr => 'maximum value of all numeric input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2050', descr => 'maximum value of all anyarray input values', - proname => 'max', prokind => 'a', proisstrict => 'f', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'anyarray', proargtypes => 'anyarray', prosrc => 'aggregate_dummy' }, { oid => '2244', descr => 'maximum value of all bpchar input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'bpchar', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'bpchar', proargtypes => 'bpchar', prosrc => 'aggregate_dummy' }, { oid => '2797', descr => 'maximum value of all tid input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'tid', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'tid', proargtypes => 'tid', prosrc => 'aggregate_dummy' }, { oid => '3564', descr => 'maximum value of all inet input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'inet', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'inet', proargtypes => 'inet', prosrc => 'aggregate_dummy' }, { oid => '2131', descr => 'minimum value of all bigint input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2132', descr => 'minimum value of all integer input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int4', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'int4', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2133', descr => 'minimum value of all smallint input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int2', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'int2', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2134', descr => 'minimum value of all oid input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'oid', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'oid', proargtypes => 'oid', prosrc => 'aggregate_dummy' }, { oid => '2135', descr => 'minimum value of all float4 input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'float4', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'float4', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2136', descr => 'minimum value of all float8 input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2137', descr => 'minimum value of all abstime input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'abstime', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'abstime', proargtypes => 'abstime', prosrc => 'aggregate_dummy' }, { oid => '2138', descr => 'minimum value of all date input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'date', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'date', proargtypes => 'date', prosrc => 'aggregate_dummy' }, { oid => '2139', descr => 'minimum value of all time input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'time', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'time', proargtypes => 'time', prosrc => 'aggregate_dummy' }, { oid => '2140', descr => 'minimum value of all time with time zone input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'timetz', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'timetz', proargtypes => 'timetz', prosrc => 'aggregate_dummy' }, { oid => '2141', descr => 'minimum value of all money input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'money', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'money', proargtypes => 'money', prosrc => 'aggregate_dummy' }, { oid => '2142', descr => 'minimum value of all timestamp input values', - proname => 'min', prokind => 'a', proisstrict => 'f', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'timestamp', proargtypes => 'timestamp', prosrc => 'aggregate_dummy' }, { oid => '2143', descr => 'minimum value of all timestamp with time zone input values', - proname => 'min', prokind => 'a', proisstrict => 'f', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'timestamptz', proargtypes => 'timestamptz', prosrc => 'aggregate_dummy' }, { oid => '2144', descr => 'minimum value of all interval input values', - proname => 'min', prokind => 'a', proisstrict => 'f', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'interval', proargtypes => 'interval', prosrc => 'aggregate_dummy' }, { oid => '2145', descr => 'minimum value of all text values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'text', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'text', proargtypes => 'text', prosrc => 'aggregate_dummy' }, { oid => '2146', descr => 'minimum value of all numeric input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2051', descr => 'minimum value of all anyarray input values', - proname => 'min', prokind => 'a', proisstrict => 'f', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'anyarray', proargtypes => 'anyarray', prosrc => 'aggregate_dummy' }, { oid => '2245', descr => 'minimum value of all bpchar input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'bpchar', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'bpchar', proargtypes => 'bpchar', prosrc => 'aggregate_dummy' }, { oid => '2798', descr => 'minimum value of all tid input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'tid', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'tid', proargtypes => 'tid', prosrc => 'aggregate_dummy' }, { oid => '3565', descr => 'minimum value of all inet input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'inet', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'inet', proargtypes => 'inet', prosrc => 'aggregate_dummy' }, # count has two forms: count(any) and count(*) { oid => '2147', descr => 'number of input rows for which the input expression is not null', - proname => 'count', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proname => 'count', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'any', prosrc => 'aggregate_dummy' }, { oid => '2803', descr => 'number of input rows', - proname => 'count', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proname => 'count', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => '', prosrc => 'aggregate_dummy' }, { oid => '2718', descr => 'population variance of bigint input values (square of the population standard deviation)', - proname => 'var_pop', prokind => 'a', proisstrict => 'f', + proname => 'var_pop', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2719', descr => 'population variance of integer input values (square of the population standard deviation)', - proname => 'var_pop', prokind => 'a', proisstrict => 'f', + proname => 'var_pop', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2720', descr => 'population variance of smallint input values (square of the population standard deviation)', - proname => 'var_pop', prokind => 'a', proisstrict => 'f', + proname => 'var_pop', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2721', descr => 'population variance of float4 input values (square of the population standard deviation)', - proname => 'var_pop', prokind => 'a', proisstrict => 'f', + proname => 'var_pop', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2722', descr => 'population variance of float8 input values (square of the population standard deviation)', - proname => 'var_pop', prokind => 'a', proisstrict => 'f', + proname => 'var_pop', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2723', descr => 'population variance of numeric input values (square of the population standard deviation)', - proname => 'var_pop', prokind => 'a', proisstrict => 'f', + proname => 'var_pop', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2641', descr => 'sample variance of bigint input values (square of the sample standard deviation)', - proname => 'var_samp', prokind => 'a', proisstrict => 'f', + proname => 'var_samp', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2642', descr => 'sample variance of integer input values (square of the sample standard deviation)', - proname => 'var_samp', prokind => 'a', proisstrict => 'f', + proname => 'var_samp', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2643', descr => 'sample variance of smallint input values (square of the sample standard deviation)', - proname => 'var_samp', prokind => 'a', proisstrict => 'f', + proname => 'var_samp', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2644', descr => 'sample variance of float4 input values (square of the sample standard deviation)', - proname => 'var_samp', prokind => 'a', proisstrict => 'f', + proname => 'var_samp', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2645', descr => 'sample variance of float8 input values (square of the sample standard deviation)', - proname => 'var_samp', prokind => 'a', proisstrict => 'f', + proname => 'var_samp', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2646', descr => 'sample variance of numeric input values (square of the sample standard deviation)', - proname => 'var_samp', prokind => 'a', proisstrict => 'f', + proname => 'var_samp', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2148', descr => 'historical alias for var_samp', - proname => 'variance', prokind => 'a', proisstrict => 'f', + proname => 'variance', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2149', descr => 'historical alias for var_samp', - proname => 'variance', prokind => 'a', proisstrict => 'f', + proname => 'variance', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2150', descr => 'historical alias for var_samp', - proname => 'variance', prokind => 'a', proisstrict => 'f', + proname => 'variance', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2151', descr => 'historical alias for var_samp', - proname => 'variance', prokind => 'a', proisstrict => 'f', + proname => 'variance', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2152', descr => 'historical alias for var_samp', - proname => 'variance', prokind => 'a', proisstrict => 'f', + proname => 'variance', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2153', descr => 'historical alias for var_samp', - proname => 'variance', prokind => 'a', proisstrict => 'f', + proname => 'variance', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2724', descr => 'population standard deviation of bigint input values', - proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + proname => 'stddev_pop', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2725', descr => 'population standard deviation of integer input values', - proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + proname => 'stddev_pop', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2726', descr => 'population standard deviation of smallint input values', - proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + proname => 'stddev_pop', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2727', descr => 'population standard deviation of float4 input values', - proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + proname => 'stddev_pop', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2728', descr => 'population standard deviation of float8 input values', - proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + proname => 'stddev_pop', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2729', descr => 'population standard deviation of numeric input values', - proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + proname => 'stddev_pop', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2712', descr => 'sample standard deviation of bigint input values', - proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + proname => 'stddev_samp', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2713', descr => 'sample standard deviation of integer input values', - proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + proname => 'stddev_samp', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2714', descr => 'sample standard deviation of smallint input values', - proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + proname => 'stddev_samp', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2715', descr => 'sample standard deviation of float4 input values', - proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + proname => 'stddev_samp', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2716', descr => 'sample standard deviation of float8 input values', - proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + proname => 'stddev_samp', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2717', descr => 'sample standard deviation of numeric input values', - proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + proname => 'stddev_samp', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2154', descr => 'historical alias for stddev_samp', - proname => 'stddev', prokind => 'a', proisstrict => 'f', + proname => 'stddev', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2155', descr => 'historical alias for stddev_samp', - proname => 'stddev', prokind => 'a', proisstrict => 'f', + proname => 'stddev', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2156', descr => 'historical alias for stddev_samp', - proname => 'stddev', prokind => 'a', proisstrict => 'f', + proname => 'stddev', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2157', descr => 'historical alias for stddev_samp', - proname => 'stddev', prokind => 'a', proisstrict => 'f', + proname => 'stddev', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' }, { oid => '2158', descr => 'historical alias for stddev_samp', - proname => 'stddev', prokind => 'a', proisstrict => 'f', + proname => 'stddev', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' }, { oid => '2159', descr => 'historical alias for stddev_samp', - proname => 'stddev', prokind => 'a', proisstrict => 'f', + proname => 'stddev', proisagg => 't', proisstrict => 'f', prorettype => 'numeric', proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, { oid => '2818', descr => 'number of input rows in which both expressions are not null', - proname => 'regr_count', prokind => 'a', proisstrict => 'f', + proname => 'regr_count', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2819', descr => 'sum of squares of the independent variable (sum(X^2) - sum(X)^2/N)', - proname => 'regr_sxx', prokind => 'a', proisstrict => 'f', + proname => 'regr_sxx', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2820', descr => 'sum of squares of the dependent variable (sum(Y^2) - sum(Y)^2/N)', - proname => 'regr_syy', prokind => 'a', proisstrict => 'f', + proname => 'regr_syy', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2821', descr => 'sum of products of independent times dependent variable (sum(X*Y) - sum(X) * sum(Y)/N)', - proname => 'regr_sxy', prokind => 'a', proisstrict => 'f', + proname => 'regr_sxy', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2822', descr => 'average of the independent variable (sum(X)/N)', - proname => 'regr_avgx', prokind => 'a', proisstrict => 'f', + proname => 'regr_avgx', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2823', descr => 'average of the dependent variable (sum(Y)/N)', - proname => 'regr_avgy', prokind => 'a', proisstrict => 'f', + proname => 'regr_avgy', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2824', descr => 'square of the correlation coefficient', - proname => 'regr_r2', prokind => 'a', proisstrict => 'f', + proname => 'regr_r2', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2825', descr => 'slope of the least-squares-fit linear equation determined by the (X, Y) pairs', - proname => 'regr_slope', prokind => 'a', proisstrict => 'f', + proname => 'regr_slope', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2826', descr => 'y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs', - proname => 'regr_intercept', prokind => 'a', proisstrict => 'f', + proname => 'regr_intercept', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2827', descr => 'population covariance', - proname => 'covar_pop', prokind => 'a', proisstrict => 'f', + proname => 'covar_pop', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2828', descr => 'sample covariance', - proname => 'covar_samp', prokind => 'a', proisstrict => 'f', + proname => 'covar_samp', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2829', descr => 'correlation coefficient', - proname => 'corr', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proname => 'corr', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '2160', @@ -7731,41 +7731,41 @@ proname => 'bool_anytrue', prorettype => 'bool', proargtypes => 'internal', prosrc => 'bool_anytrue' }, { oid => '2517', descr => 'boolean-and aggregate', - proname => 'bool_and', prokind => 'a', proisstrict => 'f', + proname => 'bool_and', proisagg => 't', proisstrict => 'f', prorettype => 'bool', proargtypes => 'bool', prosrc => 'aggregate_dummy' }, # ANY, SOME? These names conflict with subquery operators. See doc. { oid => '2518', descr => 'boolean-or aggregate', - proname => 'bool_or', prokind => 'a', proisstrict => 'f', + proname => 'bool_or', proisagg => 't', proisstrict => 'f', prorettype => 'bool', proargtypes => 'bool', prosrc => 'aggregate_dummy' }, { oid => '2519', descr => 'boolean-and aggregate', - proname => 'every', prokind => 'a', proisstrict => 'f', prorettype => 'bool', + proname => 'every', proisagg => 't', proisstrict => 'f', prorettype => 'bool', proargtypes => 'bool', prosrc => 'aggregate_dummy' }, # bitwise integer aggregates { oid => '2236', descr => 'bitwise-and smallint aggregate', - proname => 'bit_and', prokind => 'a', proisstrict => 'f', + proname => 'bit_and', proisagg => 't', proisstrict => 'f', prorettype => 'int2', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2237', descr => 'bitwise-or smallint aggregate', - proname => 'bit_or', prokind => 'a', proisstrict => 'f', prorettype => 'int2', + proname => 'bit_or', proisagg => 't', proisstrict => 'f', prorettype => 'int2', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, { oid => '2238', descr => 'bitwise-and integer aggregate', - proname => 'bit_and', prokind => 'a', proisstrict => 'f', + proname => 'bit_and', proisagg => 't', proisstrict => 'f', prorettype => 'int4', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2239', descr => 'bitwise-or integer aggregate', - proname => 'bit_or', prokind => 'a', proisstrict => 'f', prorettype => 'int4', + proname => 'bit_or', proisagg => 't', proisstrict => 'f', prorettype => 'int4', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, { oid => '2240', descr => 'bitwise-and bigint aggregate', - proname => 'bit_and', prokind => 'a', proisstrict => 'f', + proname => 'bit_and', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2241', descr => 'bitwise-or bigint aggregate', - proname => 'bit_or', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proname => 'bit_or', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, { oid => '2242', descr => 'bitwise-and bit aggregate', - proname => 'bit_and', prokind => 'a', proisstrict => 'f', prorettype => 'bit', + proname => 'bit_and', proisagg => 't', proisstrict => 'f', prorettype => 'bit', proargtypes => 'bit', prosrc => 'aggregate_dummy' }, { oid => '2243', descr => 'bitwise-or bit aggregate', - proname => 'bit_or', prokind => 'a', proisstrict => 'f', prorettype => 'bit', + proname => 'bit_or', proisagg => 't', proisstrict => 'f', prorettype => 'bit', proargtypes => 'bit', prosrc => 'aggregate_dummy' }, # formerly-missing interval + datetime operators @@ -8076,7 +8076,7 @@ proname => 'xmlconcat2', proisstrict => 'f', prorettype => 'xml', proargtypes => 'xml xml', prosrc => 'xmlconcat2' }, { oid => '2901', descr => 'concatenate XML values', - proname => 'xmlagg', prokind => 'a', proisstrict => 'f', prorettype => 'xml', + proname => 'xmlagg', proisagg => 't', proisstrict => 'f', prorettype => 'xml', proargtypes => 'xml', prosrc => 'aggregate_dummy' }, { oid => '2922', descr => 'serialize an XML value to a character string', proname => 'text', prorettype => 'text', proargtypes => 'xml', @@ -8228,7 +8228,7 @@ proname => 'json_agg_finalfn', proisstrict => 'f', prorettype => 'json', proargtypes => 'internal', prosrc => 'json_agg_finalfn' }, { oid => '3175', descr => 'aggregate input into json', - proname => 'json_agg', prokind => 'a', proisstrict => 'f', provolatile => 's', + proname => 'json_agg', proisagg => 't', proisstrict => 'f', provolatile => 's', prorettype => 'json', proargtypes => 'anyelement', prosrc => 'aggregate_dummy' }, { oid => '3180', descr => 'json object aggregate transition function', @@ -8240,7 +8240,7 @@ prorettype => 'json', proargtypes => 'internal', prosrc => 'json_object_agg_finalfn' }, { oid => '3197', descr => 'aggregate input into a json object', - proname => 'json_object_agg', prokind => 'a', proisstrict => 'f', + proname => 'json_object_agg', proisagg => 't', proisstrict => 'f', provolatile => 's', prorettype => 'json', proargtypes => 'any any', prosrc => 'aggregate_dummy' }, { oid => '3198', descr => 'build a json array from any inputs', @@ -8483,10 +8483,10 @@ proname => 'enum_larger', prorettype => 'anyenum', proargtypes => 'anyenum anyenum', prosrc => 'enum_larger' }, { oid => '3526', descr => 'maximum value of all enum input values', - proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'anyenum', + proname => 'max', proisagg => 't', proisstrict => 'f', prorettype => 'anyenum', proargtypes => 'anyenum', prosrc => 'aggregate_dummy' }, { oid => '3527', descr => 'minimum value of all enum input values', - proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'anyenum', + proname => 'min', proisagg => 't', proisstrict => 'f', prorettype => 'anyenum', proargtypes => 'anyenum', prosrc => 'aggregate_dummy' }, { oid => '3528', descr => 'first value of the input enum type', proname => 'enum_first', proisstrict => 'f', provolatile => 's', @@ -9082,7 +9082,7 @@ prorettype => 'jsonb', proargtypes => 'internal', prosrc => 'jsonb_agg_finalfn' }, { oid => '3267', descr => 'aggregate input into jsonb', - proname => 'jsonb_agg', prokind => 'a', proisstrict => 'f', + proname => 'jsonb_agg', proisagg => 't', proisstrict => 'f', provolatile => 's', prorettype => 'jsonb', proargtypes => 'anyelement', prosrc => 'aggregate_dummy' }, { oid => '3268', descr => 'jsonb object aggregate transition function', @@ -9094,7 +9094,7 @@ prorettype => 'jsonb', proargtypes => 'internal', prosrc => 'jsonb_object_agg_finalfn' }, { oid => '3270', descr => 'aggregate inputs into jsonb object', - proname => 'jsonb_object_agg', prokind => 'a', proisstrict => 'f', + proname => 'jsonb_object_agg', proisagg => 't', proisstrict => 'f', prorettype => 'jsonb', proargtypes => 'any any', prosrc => 'aggregate_dummy' }, { oid => '3271', descr => 'build a jsonb array from any inputs', @@ -9412,51 +9412,51 @@ # SQL-spec window functions { oid => '3100', descr => 'row number within partition', - proname => 'row_number', prokind => 'w', proisstrict => 'f', + proname => 'row_number', proiswindow => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => '', prosrc => 'window_row_number' }, { oid => '3101', descr => 'integer rank with gaps', - proname => 'rank', prokind => 'w', proisstrict => 'f', prorettype => 'int8', + proname => 'rank', proiswindow => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => '', prosrc => 'window_rank' }, { oid => '3102', descr => 'integer rank without gaps', - proname => 'dense_rank', prokind => 'w', proisstrict => 'f', + proname => 'dense_rank', proiswindow => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => '', prosrc => 'window_dense_rank' }, { oid => '3103', descr => 'fractional rank within partition', - proname => 'percent_rank', prokind => 'w', proisstrict => 'f', + proname => 'percent_rank', proiswindow => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => '', prosrc => 'window_percent_rank' }, { oid => '3104', descr => 'fractional row number within partition', - proname => 'cume_dist', prokind => 'w', proisstrict => 'f', + proname => 'cume_dist', proiswindow => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => '', prosrc => 'window_cume_dist' }, { oid => '3105', descr => 'split rows into N groups', - proname => 'ntile', prokind => 'w', prorettype => 'int4', + proname => 'ntile', proiswindow => 't', prorettype => 'int4', proargtypes => 'int4', prosrc => 'window_ntile' }, { oid => '3106', descr => 'fetch the preceding row value', - proname => 'lag', prokind => 'w', prorettype => 'anyelement', + proname => 'lag', proiswindow => 't', prorettype => 'anyelement', proargtypes => 'anyelement', prosrc => 'window_lag' }, { oid => '3107', descr => 'fetch the Nth preceding row value', - proname => 'lag', prokind => 'w', prorettype => 'anyelement', + proname => 'lag', proiswindow => 't', prorettype => 'anyelement', proargtypes => 'anyelement int4', prosrc => 'window_lag_with_offset' }, { oid => '3108', descr => 'fetch the Nth preceding row value with default', - proname => 'lag', prokind => 'w', prorettype => 'anyelement', + proname => 'lag', proiswindow => 't', prorettype => 'anyelement', proargtypes => 'anyelement int4 anyelement', prosrc => 'window_lag_with_offset_and_default' }, { oid => '3109', descr => 'fetch the following row value', - proname => 'lead', prokind => 'w', prorettype => 'anyelement', + proname => 'lead', proiswindow => 't', prorettype => 'anyelement', proargtypes => 'anyelement', prosrc => 'window_lead' }, { oid => '3110', descr => 'fetch the Nth following row value', - proname => 'lead', prokind => 'w', prorettype => 'anyelement', + proname => 'lead', proiswindow => 't', prorettype => 'anyelement', proargtypes => 'anyelement int4', prosrc => 'window_lead_with_offset' }, { oid => '3111', descr => 'fetch the Nth following row value with default', - proname => 'lead', prokind => 'w', prorettype => 'anyelement', + proname => 'lead', proiswindow => 't', prorettype => 'anyelement', proargtypes => 'anyelement int4 anyelement', prosrc => 'window_lead_with_offset_and_default' }, { oid => '3112', descr => 'fetch the first row value', - proname => 'first_value', prokind => 'w', prorettype => 'anyelement', + proname => 'first_value', proiswindow => 't', prorettype => 'anyelement', proargtypes => 'anyelement', prosrc => 'window_first_value' }, { oid => '3113', descr => 'fetch the last row value', - proname => 'last_value', prokind => 'w', prorettype => 'anyelement', + proname => 'last_value', proiswindow => 't', prorettype => 'anyelement', proargtypes => 'anyelement', prosrc => 'window_last_value' }, { oid => '3114', descr => 'fetch the Nth row value', - proname => 'nth_value', prokind => 'w', prorettype => 'anyelement', + proname => 'nth_value', proiswindow => 't', prorettype => 'anyelement', proargtypes => 'anyelement int4', prosrc => 'window_nth_value' }, # functions for range types @@ -9899,7 +9899,7 @@ # inverse distribution aggregates (and their support functions) { oid => '3972', descr => 'discrete percentile', - proname => 'percentile_disc', prokind => 'a', proisstrict => 'f', + proname => 'percentile_disc', proisagg => 't', proisstrict => 'f', prorettype => 'anyelement', proargtypes => 'float8 anyelement', prosrc => 'aggregate_dummy' }, { oid => '3973', descr => 'aggregate final function', @@ -9907,7 +9907,7 @@ prorettype => 'anyelement', proargtypes => 'internal float8 anyelement', prosrc => 'percentile_disc_final' }, { oid => '3974', descr => 'continuous distribution percentile', - proname => 'percentile_cont', prokind => 'a', proisstrict => 'f', + proname => 'percentile_cont', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, { oid => '3975', descr => 'aggregate final function', @@ -9915,7 +9915,7 @@ prorettype => 'float8', proargtypes => 'internal float8', prosrc => 'percentile_cont_float8_final' }, { oid => '3976', descr => 'continuous distribution percentile', - proname => 'percentile_cont', prokind => 'a', proisstrict => 'f', + proname => 'percentile_cont', proisagg => 't', proisstrict => 'f', prorettype => 'interval', proargtypes => 'float8 interval', prosrc => 'aggregate_dummy' }, { oid => '3977', descr => 'aggregate final function', @@ -9923,7 +9923,7 @@ prorettype => 'interval', proargtypes => 'internal float8', prosrc => 'percentile_cont_interval_final' }, { oid => '3978', descr => 'multiple discrete percentiles', - proname => 'percentile_disc', prokind => 'a', proisstrict => 'f', + proname => 'percentile_disc', proisagg => 't', proisstrict => 'f', prorettype => 'anyarray', proargtypes => '_float8 anyelement', prosrc => 'aggregate_dummy' }, { oid => '3979', descr => 'aggregate final function', @@ -9931,7 +9931,7 @@ prorettype => 'anyarray', proargtypes => 'internal _float8 anyelement', prosrc => 'percentile_disc_multi_final' }, { oid => '3980', descr => 'multiple continuous percentiles', - proname => 'percentile_cont', prokind => 'a', proisstrict => 'f', + proname => 'percentile_cont', proisagg => 't', proisstrict => 'f', prorettype => '_float8', proargtypes => '_float8 float8', prosrc => 'aggregate_dummy' }, { oid => '3981', descr => 'aggregate final function', @@ -9939,7 +9939,7 @@ prorettype => '_float8', proargtypes => 'internal _float8', prosrc => 'percentile_cont_float8_multi_final' }, { oid => '3982', descr => 'multiple continuous percentiles', - proname => 'percentile_cont', prokind => 'a', proisstrict => 'f', + proname => 'percentile_cont', proisagg => 't', proisstrict => 'f', prorettype => '_interval', proargtypes => '_float8 interval', prosrc => 'aggregate_dummy' }, { oid => '3983', descr => 'aggregate final function', @@ -9947,7 +9947,7 @@ prorettype => '_interval', proargtypes => 'internal _float8', prosrc => 'percentile_cont_interval_multi_final' }, { oid => '3984', descr => 'most common value', - proname => 'mode', prokind => 'a', proisstrict => 'f', + proname => 'mode', proisagg => 't', proisstrict => 'f', prorettype => 'anyelement', proargtypes => 'anyelement', prosrc => 'aggregate_dummy' }, { oid => '3985', descr => 'aggregate final function', @@ -9956,7 +9956,7 @@ # hypothetical-set aggregates (and their support functions) { oid => '3986', descr => 'rank of hypothetical row', - proname => 'rank', provariadic => 'any', prokind => 'a', proisstrict => 'f', + proname => 'rank', provariadic => 'any', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'any', proallargtypes => '{any}', proargmodes => '{v}', prosrc => 'aggregate_dummy' }, { oid => '3987', descr => 'aggregate final function', @@ -9965,7 +9965,7 @@ proallargtypes => '{internal,any}', proargmodes => '{i,v}', prosrc => 'hypothetical_rank_final' }, { oid => '3988', descr => 'fractional rank of hypothetical row', - proname => 'percent_rank', provariadic => 'any', prokind => 'a', + proname => 'percent_rank', provariadic => 'any', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'any', proallargtypes => '{any}', proargmodes => '{v}', prosrc => 'aggregate_dummy' }, @@ -9975,7 +9975,7 @@ proallargtypes => '{internal,any}', proargmodes => '{i,v}', prosrc => 'hypothetical_percent_rank_final' }, { oid => '3990', descr => 'cumulative distribution of hypothetical row', - proname => 'cume_dist', provariadic => 'any', prokind => 'a', + proname => 'cume_dist', provariadic => 'any', proisagg => 't', proisstrict => 'f', prorettype => 'float8', proargtypes => 'any', proallargtypes => '{any}', proargmodes => '{v}', prosrc => 'aggregate_dummy' }, @@ -9985,7 +9985,7 @@ proallargtypes => '{internal,any}', proargmodes => '{i,v}', prosrc => 'hypothetical_cume_dist_final' }, { oid => '3992', descr => 'rank of hypothetical row without gaps', - proname => 'dense_rank', provariadic => 'any', prokind => 'a', + proname => 'dense_rank', provariadic => 'any', proisagg => 't', proisstrict => 'f', prorettype => 'int8', proargtypes => 'any', proallargtypes => '{any}', proargmodes => '{v}', prosrc => 'aggregate_dummy' }, diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index a34b2596fa..8b31d47a77 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -57,6 +57,12 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce /* see PROKIND_ categories below */ char prokind BKI_DEFAULT(f); + /* is it an aggregate? */ + bool proisagg BKI_DEFAULT(f); + + /* is it a window function? */ + bool proiswindow BKI_DEFAULT(f); + /* security definer */ bool prosecdef BKI_DEFAULT(f); @@ -136,9 +142,8 @@ typedef FormData_pg_proc *Form_pg_proc; /* * Symbolic values for prokind column */ +#define PROKIND_ANY '\0' #define PROKIND_FUNCTION 'f' -#define PROKIND_AGGREGATE 'a' -#define PROKIND_WINDOW 'w' #define PROKIND_PROCEDURE 'p' /* @@ -187,6 +192,8 @@ extern ObjectAddress ProcedureCreate(const char *procedureName, const char *prosrc, const char *probin, char prokind, + bool isAgg, + bool isWindowFunc, bool security_definer, bool isLeakProof, bool isStrict, diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 8fc9e424cf..a3e8c2253d 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -60,8 +60,8 @@ extern ObjectAddress CreateCast(CreateCastStmt *stmt); extern void DropCastById(Oid castOid); extern ObjectAddress CreateTransform(CreateTransformStmt *stmt); extern void DropTransformById(Oid transformOid); -extern void IsThereFunctionInNamespace(const char *proname, int pronargs, - oidvector *proargtypes, Oid nspOid); +extern void IsThereFunctionInNamespace(const char *proname, char prokind, int pronargs, + oidvector *proargtypes, Oid nspOid); extern void ExecuteDoStmt(DoStmt *stmt, bool atomic); extern void ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest); extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok); diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h index 11f9046e38..7380d3abed 100644 --- a/src/include/parser/parse_func.h +++ b/src/include/parser/parse_func.h @@ -23,8 +23,7 @@ typedef enum { FUNCDETAIL_NOTFOUND, /* no matching function */ FUNCDETAIL_MULTIPLE, /* too many matching functions */ - FUNCDETAIL_NORMAL, /* found a matching regular function */ - FUNCDETAIL_PROCEDURE, /* found a matching procedure */ + FUNCDETAIL_NORMAL, /* found a matching regular function or procedure */ FUNCDETAIL_AGGREGATE, /* found a matching aggregate function */ FUNCDETAIL_WINDOWFUNC, /* found a matching window function */ FUNCDETAIL_COERCION /* it's a type coercion request */ @@ -32,10 +31,11 @@ typedef enum extern Node *ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, - Node *last_srf, FuncCall *fn, bool proc_call, + Node *last_srf, FuncCall *fn, char prokind, int location); extern FuncDetailCode func_get_detail(List *funcname, + char prokind, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, @@ -62,7 +62,7 @@ extern const char *funcname_signature_string(const char *funcname, int nargs, extern const char *func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes); -extern Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, +extern Oid LookupFuncName(List *funcname, char prokind, int nargs, const Oid *argtypes, bool noError); extern Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError); diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index e55ea4035b..1f6c04a8f3 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -117,7 +117,7 @@ extern bool get_func_retset(Oid funcid); extern bool func_strict(Oid funcid); extern char func_volatile(Oid funcid); extern char func_parallel(Oid funcid); -extern char get_func_prokind(Oid funcid); +extern bool get_func_isagg(Oid funcid); extern bool get_func_leakproof(Oid funcid); extern float4 get_func_cost(Oid funcid); extern float4 get_func_rows(Oid funcid); diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 4f333586ee..b8adc9d6d7 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -73,7 +73,7 @@ enum SysCacheIdentifier OPFAMILYAMNAMENSP, OPFAMILYOID, PARTRELID, - PROCNAMEARGSNSP, + PROCNAMEARGSNSPKIND, PROCOID, PUBLICATIONNAME, PUBLICATIONOID, diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 12f7b13780..42da52b9ca 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -620,7 +620,7 @@ call_pltcl_start_proc(Oid prolang, bool pltrusted) /* Parse possibly-qualified identifier and look up the function */ namelist = stringToQualifiedNameList(start_proc); - procOid = LookupFuncName(namelist, 0, fargtypes, false); + procOid = LookupFuncName(namelist, PROKIND_FUNCTION, 0, fargtypes, false); /* Current user must have permission to call function */ aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE); diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out index f24a17f40e..e135c6a0ef 100644 --- a/src/test/regress/expected/alter_generic.out +++ b/src/test/regress/expected/alter_generic.out @@ -83,21 +83,21 @@ ERROR: must be owner of function alt_agg3 ALTER AGGREGATE alt_agg2(int) SET SCHEMA alt_nsp2; -- failed (name conflict) ERROR: function alt_agg2(integer) already exists in schema "alt_nsp2" RESET SESSION AUTHORIZATION; -SELECT n.nspname, proname, prorettype::regtype, prokind, a.rolname +SELECT n.nspname, proname, prorettype::regtype, proisagg, a.rolname FROM pg_proc p, pg_namespace n, pg_authid a WHERE p.pronamespace = n.oid AND p.proowner = a.oid AND n.nspname IN ('alt_nsp1', 'alt_nsp2') ORDER BY nspname, proname; - nspname | proname | prorettype | prokind | rolname -----------+-----------+------------+---------+----------------------------- - alt_nsp1 | alt_agg2 | integer | a | regress_alter_generic_user2 - alt_nsp1 | alt_agg3 | integer | a | regress_alter_generic_user1 - alt_nsp1 | alt_agg4 | integer | a | regress_alter_generic_user2 - alt_nsp1 | alt_func2 | integer | f | regress_alter_generic_user2 - alt_nsp1 | alt_func3 | integer | f | regress_alter_generic_user1 - alt_nsp1 | alt_func4 | integer | f | regress_alter_generic_user2 - alt_nsp2 | alt_agg2 | integer | a | regress_alter_generic_user3 - alt_nsp2 | alt_func2 | integer | f | regress_alter_generic_user3 + nspname | proname | prorettype | proisagg | rolname +----------+-----------+------------+----------+----------------------------- + alt_nsp1 | alt_agg2 | integer | t | regress_alter_generic_user2 + alt_nsp1 | alt_agg3 | integer | t | regress_alter_generic_user1 + alt_nsp1 | alt_agg4 | integer | t | regress_alter_generic_user2 + alt_nsp1 | alt_func2 | integer | f | regress_alter_generic_user2 + alt_nsp1 | alt_func3 | integer | f | regress_alter_generic_user1 + alt_nsp1 | alt_func4 | integer | f | regress_alter_generic_user2 + alt_nsp2 | alt_agg2 | integer | t | regress_alter_generic_user3 + alt_nsp2 | alt_func2 | integer | f | regress_alter_generic_user3 (8 rows) -- diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out index 3301885fc8..76de12be52 100644 --- a/src/test/regress/expected/create_function_3.out +++ b/src/test/regress/expected/create_function_3.out @@ -278,12 +278,12 @@ HINT: Specify the argument list to select the function unambiguously. -- CREATE OR REPLACE tests CREATE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1'; CREATE OR REPLACE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1'; -ERROR: cannot change routine kind -DETAIL: "functest1" is a function. -CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1'; -ERROR: cannot change routine kind -DETAIL: "functest1" is a function. +ERROR: function "functest1" is not a window function +CREATE FUNCTION functest2(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1'; +CREATE OR REPLACE FUNCTION functest2(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1'; +ERROR: function "functest2" is a window function DROP FUNCTION functest1(a int); +DROP FUNCTION functest2(a int); -- Check behavior of VOID-returning SQL functions CREATE FUNCTION voidtest1(a int) RETURNS VOID LANGUAGE SQL AS $$ SELECT a + 1 $$; diff --git a/src/test/regress/expected/create_procedure.out b/src/test/regress/expected/create_procedure.out index 67d671727c..3305e2330f 100644 --- a/src/test/regress/expected/create_procedure.out +++ b/src/test/regress/expected/create_procedure.out @@ -1,13 +1,13 @@ CALL nonexistent(); -- error -ERROR: function nonexistent() does not exist +ERROR: procedure nonexistent() does not exist LINE 1: CALL nonexistent(); ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. +HINT: No procedure matches the given name and argument types. You might need to add explicit type casts. CALL random(); -- error -ERROR: random() is not a procedure +ERROR: procedure random() does not exist LINE 1: CALL random(); ^ -HINT: To call a function, use SELECT. +HINT: No procedure matches the given name and argument types. You might need to add explicit type casts. CREATE FUNCTION cp_testfunc1(a int) RETURNS int LANGUAGE SQL AS $$ SELECT a $$; CREATE TABLE cp_test (a int, b text); CREATE PROCEDURE ptest1(x text) @@ -16,10 +16,10 @@ AS $$ INSERT INTO cp_test VALUES (1, x); $$; SELECT ptest1('x'); -- error -ERROR: ptest1(unknown) is a procedure +ERROR: function ptest1(unknown) does not exist LINE 1: SELECT ptest1('x'); ^ -HINT: To call a procedure, use CALL. +HINT: No function matches the given name and argument types. You might need to add explicit type casts. CALL ptest1('a'); -- ok CALL ptest1('xy' || 'zzy'); -- ok, constant-folded arg CALL ptest1(substring(random()::numeric(20,15)::text, 1, 1)); -- ok, volatile arg @@ -118,14 +118,15 @@ SELECT * FROM cp_test; -- various error cases CALL version(); -- error: not a procedure -ERROR: version() is not a procedure +ERROR: procedure version() does not exist LINE 1: CALL version(); ^ -HINT: To call a function, use SELECT. +HINT: No procedure matches the given name and argument types. You might need to add explicit type casts. CALL sum(1); -- error: not a procedure -ERROR: sum(integer) is not a procedure +ERROR: procedure sum(integer) does not exist LINE 1: CALL sum(1); ^ +HINT: No procedure matches the given name and argument types. You might need to add explicit type casts. CREATE PROCEDURE ptestx() LANGUAGE SQL WINDOW AS $$ INSERT INTO cp_test VALUES (1, 'a') $$; ERROR: invalid attribute in procedure definition LINE 1: CREATE PROCEDURE ptestx() LANGUAGE SQL WINDOW AS $$ INSERT I... @@ -142,15 +143,15 @@ ERROR: invalid attribute in procedure definition LINE 1: ALTER PROCEDURE ptest1(text) STRICT; ^ ALTER FUNCTION ptest1(text) VOLATILE; -- error: not a function -ERROR: ptest1(text) is not a function +ERROR: function ptest1(text) does not exist ALTER PROCEDURE cp_testfunc1(int) VOLATILE; -- error: not a procedure -ERROR: cp_testfunc1(integer) is not a procedure +ERROR: procedure cp_testfunc1(integer) does not exist ALTER PROCEDURE nonexistent() VOLATILE; ERROR: procedure nonexistent() does not exist DROP FUNCTION ptest1(text); -- error: not a function -ERROR: ptest1(text) is not a function +ERROR: function ptest1(text) does not exist DROP PROCEDURE cp_testfunc1(int); -- error: not a procedure -ERROR: cp_testfunc1(integer) is not a procedure +ERROR: procedure cp_testfunc1(integer) does not exist DROP PROCEDURE nonexistent(); ERROR: procedure nonexistent() does not exist -- privileges diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index a1e18a6ceb..a97bb457fd 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -74,7 +74,7 @@ WHERE p1.prolang = 0 OR p1.prorettype = 0 OR 0::oid = ANY (p1.proargtypes) OR procost <= 0 OR CASE WHEN proretset THEN prorows <= 0 ELSE prorows != 0 END OR - prokind NOT IN ('f', 'a', 'w', 'p') OR + prokind NOT IN ('f', 'p') OR provolatile NOT IN ('i', 's', 'v') OR proparallel NOT IN ('s', 'r', 'u'); oid | proname @@ -89,10 +89,10 @@ WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-'; -----+--------- (0 rows) --- proretset should only be set for normal functions +-- proiswindow shouldn't be set together with proisagg or proretset SELECT p1.oid, p1.proname FROM pg_proc AS p1 -WHERE proretset AND prokind != 'f'; +WHERE proiswindow AND (proisagg OR proretset); oid | proname -----+--------- (0 rows) @@ -155,9 +155,9 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid < p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - (p1.prokind != 'a' OR p2.prokind != 'a') AND + (NOT p1.proisagg OR NOT p2.proisagg) AND (p1.prolang != p2.prolang OR - p1.prokind != p2.prokind OR + p1.proisagg != p2.proisagg OR p1.prosecdef != p2.prosecdef OR p1.proleakproof != p2.proleakproof OR p1.proisstrict != p2.proisstrict OR @@ -183,7 +183,7 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.prorettype < p2.prorettype) @@ -199,7 +199,7 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.proargtypes[0] < p2.proargtypes[0]) @@ -217,7 +217,7 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.proargtypes[1] < p2.proargtypes[1]) @@ -234,7 +234,7 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[2] < p2.proargtypes[2]) ORDER BY 1, 2; proargtypes | proargtypes @@ -247,7 +247,7 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[3] < p2.proargtypes[3]) ORDER BY 1, 2; proargtypes | proargtypes @@ -260,7 +260,7 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[4] < p2.proargtypes[4]) ORDER BY 1, 2; proargtypes | proargtypes @@ -272,7 +272,7 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[5] < p2.proargtypes[5]) ORDER BY 1, 2; proargtypes | proargtypes @@ -284,7 +284,7 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[6] < p2.proargtypes[6]) ORDER BY 1, 2; proargtypes | proargtypes @@ -296,7 +296,7 @@ FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[7] < p2.proargtypes[7]) ORDER BY 1, 2; proargtypes | proargtypes @@ -1294,15 +1294,15 @@ WHERE aggfnoid = 0 OR aggtransfn = 0 OR SELECT a.aggfnoid::oid, p.proname FROM pg_aggregate as a, pg_proc as p WHERE a.aggfnoid = p.oid AND - (p.prokind != 'a' OR p.proretset OR p.pronargs < a.aggnumdirectargs); + (NOT p.proisagg OR p.proretset OR p.pronargs < a.aggnumdirectargs); aggfnoid | proname ----------+--------- (0 rows) --- Make sure there are no prokind = PROKIND_AGGREGATE pg_proc entries without matches. +-- Make sure there are no proisagg pg_proc entries without matches. SELECT oid, proname FROM pg_proc as p -WHERE p.prokind = 'a' AND +WHERE p.proisagg AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid); oid | proname -----+--------- @@ -1641,7 +1641,7 @@ ORDER BY 1, 2; SELECT p1.oid::regprocedure, p2.oid::regprocedure FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND - p1.prokind = 'a' AND p2.prokind = 'a' AND + p1.proisagg AND p2.proisagg AND array_dims(p1.proargtypes) != array_dims(p2.proargtypes) ORDER BY 1; oid | oid @@ -1652,7 +1652,7 @@ ORDER BY 1; -- For the same reason, built-in aggregates with default arguments are no good. SELECT oid, proname FROM pg_proc AS p -WHERE prokind = 'a' AND proargdefaults IS NOT NULL; +WHERE proisagg AND proargdefaults IS NOT NULL; oid | proname -----+--------- (0 rows) @@ -1662,7 +1662,7 @@ WHERE prokind = 'a' AND proargdefaults IS NOT NULL; -- that is not subject to the misplaced ORDER BY issue). SELECT p.oid, proname FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid -WHERE prokind = 'a' AND provariadic != 0 AND a.aggkind = 'n'; +WHERE proisagg AND provariadic != 0 AND a.aggkind = 'n'; oid | proname -----+--------- (0 rows) diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index ac8968d24f..4a433a8d1b 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -656,7 +656,7 @@ CREATE PROCEDURE priv_testproc1(int) AS 'select $1;' LANGUAGE sql; REVOKE ALL ON FUNCTION priv_testfunc1(int), priv_testfunc2(int), priv_testagg1(int) FROM PUBLIC; GRANT EXECUTE ON FUNCTION priv_testfunc1(int), priv_testfunc2(int), priv_testagg1(int) TO regress_priv_user2; REVOKE ALL ON FUNCTION priv_testproc1(int) FROM PUBLIC; -- fail, not a function -ERROR: priv_testproc1(integer) is not a function +ERROR: function priv_testproc1(integer) does not exist REVOKE ALL ON PROCEDURE priv_testproc1(int) FROM PUBLIC; GRANT EXECUTE ON PROCEDURE priv_testproc1(int) TO regress_priv_user2; GRANT USAGE ON FUNCTION priv_testfunc1(int) TO regress_priv_user3; -- semantic error diff --git a/src/test/regress/expected/regex.out b/src/test/regress/expected/regex.out index 79a7fa7a84..b28256ef24 100644 --- a/src/test/regress/expected/regex.out +++ b/src/test/regress/expected/regex.out @@ -298,15 +298,15 @@ explain (costs off) select * from pg_proc where proname ~ 'abc'; explain (costs off) select * from pg_proc where proname ~ '^abc'; QUERY PLAN ---------------------------------------------------------------------- - Index Scan using pg_proc_proname_args_nsp_index on pg_proc + Index Scan using pg_proc_proname_args_nsp_kind_index on pg_proc Index Cond: ((proname >= 'abc'::name) AND (proname < 'abd'::name)) Filter: (proname ~ '^abc'::text) (3 rows) explain (costs off) select * from pg_proc where proname ~ '^abc$'; - QUERY PLAN ------------------------------------------------------------- - Index Scan using pg_proc_proname_args_nsp_index on pg_proc + QUERY PLAN +----------------------------------------------------------------- + Index Scan using pg_proc_proname_args_nsp_kind_index on pg_proc Index Cond: (proname = 'abc'::name) Filter: (proname ~ '^abc$'::text) (3 rows) @@ -314,7 +314,7 @@ explain (costs off) select * from pg_proc where proname ~ '^abc$'; explain (costs off) select * from pg_proc where proname ~ '^abcd*e'; QUERY PLAN ---------------------------------------------------------------------- - Index Scan using pg_proc_proname_args_nsp_index on pg_proc + Index Scan using pg_proc_proname_args_nsp_kind_index on pg_proc Index Cond: ((proname >= 'abc'::name) AND (proname < 'abd'::name)) Filter: (proname ~ '^abcd*e'::text) (3 rows) @@ -322,7 +322,7 @@ explain (costs off) select * from pg_proc where proname ~ '^abcd*e'; explain (costs off) select * from pg_proc where proname ~ '^abc+d'; QUERY PLAN ---------------------------------------------------------------------- - Index Scan using pg_proc_proname_args_nsp_index on pg_proc + Index Scan using pg_proc_proname_args_nsp_kind_index on pg_proc Index Cond: ((proname >= 'abc'::name) AND (proname < 'abd'::name)) Filter: (proname ~ '^abc+d'::text) (3 rows) @@ -330,15 +330,15 @@ explain (costs off) select * from pg_proc where proname ~ '^abc+d'; explain (costs off) select * from pg_proc where proname ~ '^(abc)(def)'; QUERY PLAN ---------------------------------------------------------------------------- - Index Scan using pg_proc_proname_args_nsp_index on pg_proc + Index Scan using pg_proc_proname_args_nsp_kind_index on pg_proc Index Cond: ((proname >= 'abcdef'::name) AND (proname < 'abcdeg'::name)) Filter: (proname ~ '^(abc)(def)'::text) (3 rows) explain (costs off) select * from pg_proc where proname ~ '^(abc)$'; - QUERY PLAN ------------------------------------------------------------- - Index Scan using pg_proc_proname_args_nsp_index on pg_proc + QUERY PLAN +----------------------------------------------------------------- + Index Scan using pg_proc_proname_args_nsp_kind_index on pg_proc Index Cond: (proname = 'abc'::name) Filter: (proname ~ '^(abc)$'::text) (3 rows) @@ -353,7 +353,7 @@ explain (costs off) select * from pg_proc where proname ~ '^(abc)?d'; explain (costs off) select * from pg_proc where proname ~ '^abcd(x|(?=\w\w)q)'; QUERY PLAN ------------------------------------------------------------------------ - Index Scan using pg_proc_proname_args_nsp_index on pg_proc + Index Scan using pg_proc_proname_args_nsp_kind_index on pg_proc Index Cond: ((proname >= 'abcd'::name) AND (proname < 'abce'::name)) Filter: (proname ~ '^abcd(x|(?=\w\w)q)'::text) (3 rows) diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index ae0cd253d5..aaddb8822d 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1521,12 +1521,10 @@ UNION ALL SELECT l.objoid, l.classoid, l.objsubid, - CASE pro.prokind - WHEN 'a'::"char" THEN 'aggregate'::text - WHEN 'f'::"char" THEN 'function'::text - WHEN 'p'::"char" THEN 'procedure'::text - WHEN 'w'::"char" THEN 'window'::text - ELSE NULL::text + CASE + WHEN (pro.prokind = 'p'::"char") THEN 'procedure'::text + WHEN pro.proisagg THEN 'aggregate'::text + ELSE 'function'::text END AS objtype, pro.pronamespace AS objnamespace, ((( diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql index 84fd900b24..35172aad74 100644 --- a/src/test/regress/sql/alter_generic.sql +++ b/src/test/regress/sql/alter_generic.sql @@ -81,7 +81,7 @@ CREATE AGGREGATE alt_agg2 ( RESET SESSION AUTHORIZATION; -SELECT n.nspname, proname, prorettype::regtype, prokind, a.rolname +SELECT n.nspname, proname, prorettype::regtype, proisagg, a.rolname FROM pg_proc p, pg_namespace n, pg_authid a WHERE p.pronamespace = n.oid AND p.proowner = a.oid AND n.nspname IN ('alt_nsp1', 'alt_nsp2') diff --git a/src/test/regress/sql/create_function_3.sql b/src/test/regress/sql/create_function_3.sql index 24bb900990..3f473f38c3 100644 --- a/src/test/regress/sql/create_function_3.sql +++ b/src/test/regress/sql/create_function_3.sql @@ -186,8 +186,10 @@ CREATE FUNCTION functest_B_2(bigint) RETURNS bool LANGUAGE 'sql' CREATE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1'; CREATE OR REPLACE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1'; -CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1'; +CREATE FUNCTION functest2(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1'; +CREATE OR REPLACE FUNCTION functest2(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1'; DROP FUNCTION functest1(a int); +DROP FUNCTION functest2(a int); -- Check behavior of VOID-returning SQL functions diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index a593d37643..3302bebfe2 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -82,7 +82,7 @@ 0::oid = ANY (p1.proargtypes) OR procost <= 0 OR CASE WHEN proretset THEN prorows <= 0 ELSE prorows != 0 END OR - prokind NOT IN ('f', 'a', 'w', 'p') OR + prokind NOT IN ('f', 'p') OR provolatile NOT IN ('i', 's', 'v') OR proparallel NOT IN ('s', 'r', 'u'); @@ -91,10 +91,10 @@ FROM pg_proc as p1 WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-'; --- proretset should only be set for normal functions +-- proiswindow shouldn't be set together with proisagg or proretset SELECT p1.oid, p1.proname FROM pg_proc AS p1 -WHERE proretset AND prokind != 'f'; +WHERE proiswindow AND (proisagg OR proretset); -- currently, no built-in functions should be SECURITY DEFINER; -- this might change in future, but there will probably never be many. @@ -141,9 +141,9 @@ WHERE p1.oid < p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - (p1.prokind != 'a' OR p2.prokind != 'a') AND + (NOT p1.proisagg OR NOT p2.proisagg) AND (p1.prolang != p2.prolang OR - p1.prokind != p2.prokind OR + p1.proisagg != p2.proisagg OR p1.prosecdef != p2.prosecdef OR p1.proleakproof != p2.proleakproof OR p1.proisstrict != p2.proisstrict OR @@ -167,7 +167,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.prorettype < p2.prorettype) @@ -178,7 +178,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.proargtypes[0] < p2.proargtypes[0]) @@ -189,7 +189,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.proargtypes[1] < p2.proargtypes[1]) @@ -200,7 +200,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[2] < p2.proargtypes[2]) ORDER BY 1, 2; @@ -209,7 +209,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[3] < p2.proargtypes[3]) ORDER BY 1, 2; @@ -218,7 +218,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[4] < p2.proargtypes[4]) ORDER BY 1, 2; @@ -227,7 +227,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[5] < p2.proargtypes[5]) ORDER BY 1, 2; @@ -236,7 +236,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[6] < p2.proargtypes[6]) ORDER BY 1, 2; @@ -245,7 +245,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - p1.prokind != 'a' AND p2.prokind != 'a' AND + NOT p1.proisagg AND NOT p2.proisagg AND (p1.proargtypes[7] < p2.proargtypes[7]) ORDER BY 1, 2; @@ -805,13 +805,13 @@ SELECT a.aggfnoid::oid, p.proname FROM pg_aggregate as a, pg_proc as p WHERE a.aggfnoid = p.oid AND - (p.prokind != 'a' OR p.proretset OR p.pronargs < a.aggnumdirectargs); + (NOT p.proisagg OR p.proretset OR p.pronargs < a.aggnumdirectargs); --- Make sure there are no prokind = PROKIND_AGGREGATE pg_proc entries without matches. +-- Make sure there are no proisagg pg_proc entries without matches. SELECT oid, proname FROM pg_proc as p -WHERE p.prokind = 'a' AND +WHERE p.proisagg AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid); -- If there is no finalfn then the output type must be the transtype. @@ -1090,7 +1090,7 @@ SELECT p1.oid::regprocedure, p2.oid::regprocedure FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND - p1.prokind = 'a' AND p2.prokind = 'a' AND + p1.proisagg AND p2.proisagg AND array_dims(p1.proargtypes) != array_dims(p2.proargtypes) ORDER BY 1; @@ -1098,7 +1098,7 @@ SELECT oid, proname FROM pg_proc AS p -WHERE prokind = 'a' AND proargdefaults IS NOT NULL; +WHERE proisagg AND proargdefaults IS NOT NULL; -- For the same reason, we avoid creating built-in variadic aggregates, except -- that variadic ordered-set aggregates are OK (since they have special syntax @@ -1106,7 +1106,7 @@ SELECT p.oid, proname FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid -WHERE prokind = 'a' AND provariadic != 0 AND a.aggkind = 'n'; +WHERE proisagg AND provariadic != 0 AND a.aggkind = 'n'; -- **************** pg_opfamily **************** base-commit: b2b82228ee5dc08f0341b5480546479c19e84baf -- 2.17.0