From 7e21a05d3f43f8d29f4592fa1d547bde9378c1fa Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Wed, 3 Jan 2018 18:21:20 -0500 Subject: [PATCH v2 1/2] Add prokind column, replacing proisagg and proiswindow The new column distinguishes normal functions, procedures, aggregates, and window functions. This replaces the existing columns proisagg and proiswindow, and replaces the convention that procedures are indicated by prorettype == 0. --- doc/src/sgml/catalogs.sgml | 29 ++++++------ src/backend/catalog/aclchk.c | 18 +++---- src/backend/catalog/information_schema.sql | 4 +- src/backend/catalog/objectaddress.c | 6 +-- src/backend/catalog/pg_aggregate.c | 3 +- src/backend/catalog/pg_proc.c | 49 +++++++------------ src/backend/catalog/system_views.sql | 8 ++-- src/backend/commands/functioncmds.c | 29 ++++-------- src/backend/commands/proclang.c | 9 ++-- src/backend/commands/typecmds.c | 3 +- src/backend/parser/parse_coerce.c | 3 +- src/backend/parser/parse_func.c | 27 +++++++---- src/backend/utils/adt/ruleutils.c | 10 ++-- src/backend/utils/cache/lsyscache.c | 4 +- src/bin/pg_dump/pg_dump.c | 17 +++++-- src/bin/pg_dump/t/002_pg_dump.pl | 6 +-- src/bin/psql/describe.c | 62 +++++++++++++++++++------ src/bin/psql/tab-complete.c | 6 +-- src/include/catalog/pg_class.h | 2 +- src/include/catalog/pg_proc.h | 54 +++++++++++---------- src/include/catalog/pg_proc_fn.h | 3 +- src/pl/plpython/plpy_procedure.c | 2 +- src/pl/tcl/pltcl.c | 2 +- src/test/regress/expected/alter_generic.out | 2 +- src/test/regress/expected/create_function_3.out | 9 ++++ src/test/regress/expected/opr_sanity.out | 38 +++++++-------- src/test/regress/expected/rules.out | 8 ++-- src/test/regress/sql/alter_generic.sql | 2 +- src/test/regress/sql/create_function_3.sql | 8 ++++ src/test/regress/sql/opr_sanity.sql | 38 +++++++-------- 30 files changed, 252 insertions(+), 209 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 71e20f2740..19a40b9992 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -5062,15 +5062,17 @@ <structname>pg_proc</structname> - The catalog pg_proc stores information about functions (or procedures). - See - and for more information. + The catalog pg_proc stores information about + functions, procedures, aggregate functions, and window functions + (collectively also known as routines). See , , and + for more information. - The table contains data for aggregate functions as well as plain functions. - If proisagg is true, there should be a matching - row in pg_aggregate. + If prokind indicates that the entry is for an + aggregate function, there should be a matching row in + pg_aggregate. @@ -5157,17 +5159,12 @@ <structname>pg_proc</structname> Columns - proisagg + prokind bool - Function is an aggregate function - - - - proiswindow - bool - - Function is a window function + f for a normal function, p + for a procedure, a for an aggregate function, + w for a window function @@ -5264,7 +5261,7 @@ <structname>pg_proc</structname> Columns prorettype oid pg_type.oid - Data type of the return value, or null for a procedure + Data type of the return value diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 1156627b9e..3f2c629c47 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -830,21 +830,17 @@ objectsInSchemaToOids(ObjectType objtype, List *nspnames) BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(namespaceId)); - /* - * When looking for functions, check for return type <>0. - * When looking for procedures, check for return type ==0. - * When looking for routines, don't check the return type. - */ if (objtype == OBJECT_FUNCTION) + /* includes aggregates and window functions */ ScanKeyInit(&key[keycount++], - Anum_pg_proc_prorettype, - BTEqualStrategyNumber, F_OIDNE, - InvalidOid); + Anum_pg_proc_prokind, + BTEqualStrategyNumber, F_CHARNE, + CharGetDatum(PROKIND_PROCEDURE)); else if (objtype == OBJECT_PROCEDURE) ScanKeyInit(&key[keycount++], - Anum_pg_proc_prorettype, - BTEqualStrategyNumber, F_OIDEQ, - InvalidOid); + Anum_pg_proc_prokind, + BTEqualStrategyNumber, F_CHAREQ, + CharGetDatum(PROKIND_PROCEDURE)); rel = heap_open(ProcedureRelationId, AccessShareLock); scan = heap_beginscan_catalog(rel, keycount, key); diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index 686528c354..aab9956335 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -1413,7 +1413,7 @@ CREATE VIEW routines AS CAST(current_database() AS sql_identifier) AS routine_catalog, CAST(n.nspname AS sql_identifier) AS routine_schema, CAST(p.proname AS sql_identifier) AS routine_name, - CAST(CASE WHEN p.prorettype <> 0 THEN 'FUNCTION' ELSE 'PROCEDURE' END + CAST(CASE p.prokind WHEN 'f' THEN 'FUNCTION' WHEN 'p' THEN 'PROCEDURE' END AS character_data) AS routine_type, CAST(null AS sql_identifier) AS module_catalog, CAST(null AS sql_identifier) AS module_schema, @@ -1464,7 +1464,7 @@ CREATE VIEW routines AS CAST('GENERAL' AS character_data) AS parameter_style, CAST(CASE WHEN p.provolatile = 'i' THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_deterministic, CAST('MODIFIES' AS character_data) AS sql_data_access, - CAST(CASE WHEN p.prorettype <> 0 THEN + CAST(CASE WHEN p.prokind <> 'p' THEN CASE WHEN p.proisstrict THEN 'YES' ELSE 'NO' END END AS yes_or_no) AS is_null_call, CAST(null AS character_data) AS sql_path, CAST('YES' AS yes_or_no) AS schema_level_routine, diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 80f561df1c..4e7817712d 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4047,11 +4047,11 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid) elog(ERROR, "cache lookup failed for procedure %u", procid); procForm = (Form_pg_proc) GETSTRUCT(procTup); - if (procForm->proisagg) + if (procForm->prokind == PROKIND_AGGREGATE) appendStringInfoString(buffer, "aggregate"); - else if (procForm->prorettype == InvalidOid) + else if (procForm->prokind == PROKIND_PROCEDURE) appendStringInfoString(buffer, "procedure"); - else + else /* function or window function */ appendStringInfoString(buffer, "function"); ReleaseSysCache(procTup); diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index f14ea26fcb..50d8d81f2c 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -616,8 +616,7 @@ AggregateCreate(const char *aggName, InvalidOid, /* no validator */ "aggregate_dummy", /* placeholder proc */ NULL, /* probin */ - true, /* isAgg */ - false, /* isWindowFunc */ + PROKIND_AGGREGATE, false, /* security invoker (currently not * definable for agg) */ false, /* isLeakProof */ diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index b59fadbf76..491eee84c3 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -74,8 +74,7 @@ ProcedureCreate(const char *procedureName, Oid languageValidator, const char *prosrc, const char *probin, - bool isAgg, - bool isWindowFunc, + char prokind, bool security_definer, bool isLeakProof, bool isStrict, @@ -335,8 +334,7 @@ ProcedureCreate(const char *procedureName, values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows); values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType); values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg); - values[Anum_pg_proc_proiswindow - 1] = BoolGetDatum(isWindowFunc); + values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind); 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); @@ -403,6 +401,21 @@ ProcedureCreate(const char *procedureName, aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, procedureName); + /* Can't change aggregate or window-function status, either */ + if (oldproc->prokind != prokind) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change routine type"), + (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. @@ -535,34 +548,6 @@ 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 5652e9ee6d..5e6e8a64f6 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -332,9 +332,11 @@ CREATE VIEW pg_seclabels AS UNION ALL SELECT l.objoid, l.classoid, l.objsubid, - CASE WHEN pro.proisagg = true THEN 'aggregate'::text - WHEN pro.proisagg = false THEN 'function'::text - END AS objtype, + 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, pro.pronamespace AS objnamespace, CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident(pro.proname) diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index abdfa249c0..29380f61c3 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1097,8 +1097,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) languageValidator, prosrc_str, /* converted to text later */ probin_str, /* converted to text later */ - false, /* not an aggregate */ - isWindowFunc, + stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION), security, isLeakProof, isStrict, @@ -1126,7 +1125,7 @@ RemoveFunctionById(Oid funcOid) { Relation relation; HeapTuple tup; - bool isagg; + char prokind; /* * Delete the pg_proc tuple. @@ -1137,7 +1136,7 @@ RemoveFunctionById(Oid funcOid) if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for function %u", funcOid); - isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg; + prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind; CatalogTupleDelete(relation, &tup->t_self); @@ -1148,7 +1147,7 @@ RemoveFunctionById(Oid funcOid) /* * If there's a pg_aggregate tuple, delete that too. */ - if (isagg) + if (prokind == PROKIND_AGGREGATE) { relation = heap_open(AggregateRelationId, RowExclusiveLock); @@ -1203,13 +1202,13 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) aclcheck_error(ACLCHECK_NOT_OWNER, stmt->objtype, NameListToString(stmt->func->objname)); - if (procForm->proisagg) + if (procForm->prokind == PROKIND_AGGREGATE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an aggregate function", NameListToString(stmt->func->objname)))); - is_procedure = (procForm->prorettype == InvalidOid); + is_procedure = (procForm->prokind == PROKIND_PROCEDURE); /* Examine requested actions. */ foreach(l, stmt->actions) @@ -1525,14 +1524,10 @@ CreateCast(CreateCastStmt *stmt) (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("cast function must not be volatile"))); #endif - if (procstruct->proisagg) + if (procstruct->prokind != PROKIND_FUNCTION) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - 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"))); + errmsg("cast function must be a normal function"))); if (procstruct->proretset) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), @@ -1777,14 +1772,10 @@ check_transform_function(Form_pg_proc procstruct) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("transform function must not be volatile"))); - if (procstruct->proisagg) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("transform function must not be an aggregate function"))); - if (procstruct->proiswindow) + if (procstruct->prokind != PROKIND_FUNCTION) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("transform function must not be a window function"))); + errmsg("transform function must be a normal function"))); if (procstruct->proretset) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 2ec96242ae..447bd49f89 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -129,8 +129,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) F_FMGR_C_VALIDATOR, pltemplate->tmplhandler, pltemplate->tmpllibrary, - false, /* isAgg */ - false, /* isWindowFunc */ + PROKIND_FUNCTION, false, /* security_definer */ false, /* isLeakProof */ false, /* isStrict */ @@ -169,8 +168,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) F_FMGR_C_VALIDATOR, pltemplate->tmplinline, pltemplate->tmpllibrary, - false, /* isAgg */ - false, /* isWindowFunc */ + PROKIND_FUNCTION, false, /* security_definer */ false, /* isLeakProof */ true, /* isStrict */ @@ -212,8 +210,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) F_FMGR_C_VALIDATOR, pltemplate->tmplvalidator, pltemplate->tmpllibrary, - false, /* isAgg */ - false, /* isWindowFunc */ + PROKIND_FUNCTION, false, /* security_definer */ false, /* isLeakProof */ true, /* isStrict */ diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 899a5c4cd4..bf3cd3a454 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -1672,8 +1672,7 @@ makeRangeConstructors(const char *name, Oid namespace, F_FMGR_INTERNAL_VALIDATOR, /* language validator */ prosrc[i], /* prosrc */ NULL, /* probin */ - false, /* isAgg */ - false, /* isWindowFunc */ + PROKIND_FUNCTION, false, /* security_definer */ false, /* leakproof */ false, /* isStrict */ diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 085aa8766c..665d3327a0 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -834,8 +834,7 @@ build_coercion_expression(Node *node, */ /* Assert(targetTypeId == procstruct->prorettype); */ Assert(!procstruct->proretset); - Assert(!procstruct->proisagg); - Assert(!procstruct->proiswindow); + Assert(procstruct->prokind == PROKIND_FUNCTION); nargs = procstruct->pronargs; Assert(nargs >= 1 && nargs <= 3); /* Assert(procstruct->proargtypes.values[0] == exprType(node)); */ diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 2a4ac09d5c..9dbf2c2b63 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -1614,14 +1614,25 @@ func_get_detail(List *funcname, *argdefaults = defaults; } } - if (pform->proisagg) - result = FUNCDETAIL_AGGREGATE; - else if (pform->proiswindow) - result = FUNCDETAIL_WINDOWFUNC; - else if (pform->prorettype == InvalidOid) - result = FUNCDETAIL_PROCEDURE; - else - result = FUNCDETAIL_NORMAL; + + 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); + } + ReleaseSysCache(ftup); return result; } diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index ba9fab4582..b32f776450 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -2468,12 +2468,12 @@ pg_get_functiondef(PG_FUNCTION_ARGS) proc = (Form_pg_proc) GETSTRUCT(proctup); name = NameStr(proc->proname); - if (proc->proisagg) + if (proc->prokind == PROKIND_AGGREGATE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an aggregate function", name))); - isfunction = (proc->prorettype != InvalidOid); + isfunction = (proc->prokind == PROKIND_FUNCTION); /* * We always qualify the function name, to ensure the right function gets @@ -2500,7 +2500,7 @@ pg_get_functiondef(PG_FUNCTION_ARGS) /* Emit some miscellaneous options on one line */ oldlen = buf.len; - if (proc->proiswindow) + if (proc->prokind == PROKIND_WINDOW) appendStringInfoString(&buf, " WINDOW"); switch (proc->provolatile) { @@ -2704,7 +2704,7 @@ pg_get_function_result(PG_FUNCTION_ARGS) if (!HeapTupleIsValid(proctup)) PG_RETURN_NULL(); - if (((Form_pg_proc) GETSTRUCT(proctup))->prorettype == InvalidOid) + if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE) { ReleaseSysCache(proctup); PG_RETURN_NULL(); @@ -2804,7 +2804,7 @@ print_function_arguments(StringInfo buf, HeapTuple proctup, } /* Check for special treatment of ordered-set aggregates */ - if (proc->proisagg) + if (proc->prokind == PROKIND_AGGREGATE) { HeapTuple aggtup; Form_pg_aggregate agg; diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 51b6b4f7bb..161470aa34 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -1601,7 +1601,7 @@ func_parallel(Oid funcid) /* * get_func_isagg - * Given procedure id, return the function's proisagg field. + * Given procedure id, return whether the function is an aggregate. */ bool get_func_isagg(Oid funcid) @@ -1613,7 +1613,7 @@ get_func_isagg(Oid funcid) if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); - result = ((Form_pg_proc) GETSTRUCT(tp))->proisagg; + result = ((Form_pg_proc) GETSTRUCT(tp))->prokind == PROKIND_AGGREGATE; ReleaseSysCache(tp); return result; } diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index f7a079f0b1..a1e9a48ab3 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -5432,7 +5432,7 @@ getAggregates(Archive *fout, int *numAggs) "(p.oid = pip.objoid " "AND pip.classoid = 'pg_proc'::regclass " "AND pip.objsubid = 0) " - "WHERE p.proisagg AND (" + "WHERE %s AND (" "p.pronamespace != " "(SELECT oid FROM pg_namespace " "WHERE nspname = 'pg_catalog') OR " @@ -5441,7 +5441,10 @@ getAggregates(Archive *fout, int *numAggs) acl_subquery->data, racl_subquery->data, initacl_subquery->data, - initracl_subquery->data); + initracl_subquery->data, + (fout->remoteVersion >= 110000 ? + "p.prokind = 'a'" : + "p.proisagg")); if (dopt->binary_upgrade) appendPQExpBufferStr(query, " OR EXISTS(SELECT 1 FROM pg_depend WHERE " @@ -5644,7 +5647,7 @@ getFuncs(Archive *fout, int *numFuncs) "(p.oid = pip.objoid " "AND pip.classoid = 'pg_proc'::regclass " "AND pip.objsubid = 0) " - "WHERE NOT proisagg" + "WHERE NOT %s" "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " "WHERE classid = 'pg_proc'::regclass AND " "objid = p.oid AND deptype = 'i')" @@ -5664,6 +5667,9 @@ getFuncs(Archive *fout, int *numFuncs) initacl_subquery->data, initracl_subquery->data, username_subquery, + (fout->remoteVersion >= 110000 ? + "prokind = 'a'" : + "proisagg"), g_last_builtin_oid, g_last_builtin_oid); if (dopt->binary_upgrade) @@ -11638,12 +11644,15 @@ 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, " - "proiswindow, provolatile, proisstrict, prosecdef, " + "%s, provolatile, proisstrict, prosecdef, " "proleakproof, proconfig, procost, prorows, " "proparallel, " "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " "FROM pg_catalog.pg_proc " "WHERE oid = '%u'::pg_catalog.oid", + (fout->remoteVersion >= 110000 ? + "prokind = 'w' AS proiswindow" : + "proiswindow"), finfo->dobj.catId.oid); } else if (fout->remoteVersion >= 90500) diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index ac9cfa04c1..0044e2e114 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -6257,8 +6257,7 @@ prorows, provariadic, protransform, - proisagg, - proiswindow, + prokind, prosecdef, proleakproof, proisstrict, @@ -6290,8 +6289,7 @@ \QGRANT SELECT(prorows) ON TABLE pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(provariadic) ON TABLE pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(protransform) ON TABLE pg_proc TO PUBLIC;\E\n.* - \QGRANT SELECT(proisagg) ON TABLE pg_proc TO PUBLIC;\E\n.* - \QGRANT SELECT(proiswindow) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(prokind) ON TABLE pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(prosecdef) ON TABLE pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(proleakproof) ON TABLE pg_proc TO PUBLIC;\E\n.* \QGRANT SELECT(proisstrict) ON TABLE pg_proc TO PUBLIC;\E\n.* diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 466a78004b..0c3be1f504 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -100,12 +100,20 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem) " pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n", gettext_noop("Argument data types")); - 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 (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")); if (!showSystem && !pattern) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" @@ -346,14 +354,31 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool gettext_noop("Schema"), gettext_noop("Name")); - if (pset.sversion >= 80400) + if (pset.sversion >= 110000) + 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" + " ELSE '%s'\n" + " END as \"%s\"", + gettext_noop("Result data type"), + gettext_noop("Argument data types"), + /* 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) 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\n" " WHEN p.proisagg THEN '%s'\n" " WHEN p.proiswindow THEN '%s'\n" - " WHEN p.prorettype = 0 THEN '%s'\n" " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n" " ELSE '%s'\n" " END as \"%s\"", @@ -362,7 +387,6 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool /* translator: "agg" is short for "aggregate" */ gettext_noop("agg"), gettext_noop("window"), - gettext_noop("proc"), gettext_noop("trigger"), gettext_noop("func"), gettext_noop("Type")); @@ -494,7 +518,10 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool appendPQExpBufferStr(&buf, "WHERE "); have_where = true; } - appendPQExpBufferStr(&buf, "NOT p.proisagg\n"); + if (pset.sversion >= 110000) + appendPQExpBufferStr(&buf, "p.prokind <> 'a'\n"); + else + appendPQExpBufferStr(&buf, "NOT p.proisagg\n"); } if (!showTrigger) { @@ -516,7 +543,10 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool appendPQExpBufferStr(&buf, "WHERE "); have_where = true; } - appendPQExpBufferStr(&buf, "NOT p.proiswindow\n"); + if (pset.sversion >= 110000) + appendPQExpBufferStr(&buf, "p.prokind <> 'w'\n"); + else + appendPQExpBufferStr(&buf, "NOT p.proiswindow\n"); } } else @@ -528,7 +558,10 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool /* Note: at least one of these must be true ... */ if (showAggregate) { - appendPQExpBufferStr(&buf, "p.proisagg\n"); + if (pset.sversion >= 110000) + appendPQExpBufferStr(&buf, "p.prokind = 'a'\n"); + else + appendPQExpBufferStr(&buf, "p.proisagg\n"); needs_or = true; } if (showTrigger) @@ -543,7 +576,10 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool { if (needs_or) appendPQExpBufferStr(&buf, " OR "); - appendPQExpBufferStr(&buf, "p.proiswindow\n"); + if (pset.sversion >= 110000) + appendPQExpBufferStr(&buf, "p.prokind = 'w'\n"); + else + appendPQExpBufferStr(&buf, "p.proiswindow\n"); needs_or = true; } appendPQExpBufferStr(&buf, " )\n"); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 8bc4a194a5..cf23d13d1e 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -349,7 +349,7 @@ static const SchemaQuery Query_for_list_of_aggregates = { /* catname */ "pg_catalog.pg_proc p", /* selcondition */ - "p.proisagg", + "p.prokind = 'a'", /* viscondition */ "pg_catalog.pg_function_is_visible(p.oid)", /* namespace */ @@ -397,7 +397,7 @@ static const SchemaQuery Query_for_list_of_functions = { /* catname */ "pg_catalog.pg_proc p", /* selcondition */ - "p.prorettype <> 0", + "p.prokind IN ('f', 'w')", /* viscondition */ "pg_catalog.pg_function_is_visible(p.oid)", /* namespace */ @@ -428,7 +428,7 @@ static const SchemaQuery Query_for_list_of_procedures = { /* catname */ "pg_catalog.pg_proc p", /* selcondition */ - "p.prorettype = 0", + "p.prokind = 'p'", /* viscondition */ "pg_catalog.pg_function_is_visible(p.oid)", /* namespace */ diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 26b1866c69..01cf59e7a3 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -151,7 +151,7 @@ DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 30 0 t DESCR(""); DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 22 0 f f f f f f f t n f 3 1 _null_ _null_ _null_)); DESCR(""); -DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f f f t n f 3 1 _null_ _null_ _null_)); +DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 28 0 t f f f f f f t n f 3 1 _null_ _null_ _null_)); DESCR(""); DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 33 0 t f f f f f f t n f 3 1 _null_ _null_ _null_)); DESCR(""); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 62e16514cc..fac91685c4 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -43,8 +43,7 @@ CATALOG(pg_proc,1255) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81) BKI_SCHEMA_MACRO float4 prorows; /* estimated # of rows out (if proretset) */ Oid provariadic; /* element type of variadic array, or 0 */ regproc protransform; /* transforms calls to it during planning */ - bool proisagg; /* is it an aggregate? */ - bool proiswindow; /* is it a window function? */ + char prokind; /* see PROKIND_ categories below */ bool prosecdef; /* security definer */ bool proleakproof; /* is it a leak-proof function? */ bool proisstrict; /* strict with respect to NULLs? */ @@ -86,7 +85,7 @@ typedef FormData_pg_proc *Form_pg_proc; * compiler constants for pg_proc * ---------------- */ -#define Natts_pg_proc 29 +#define Natts_pg_proc 28 #define Anum_pg_proc_proname 1 #define Anum_pg_proc_pronamespace 2 #define Anum_pg_proc_proowner 3 @@ -95,27 +94,26 @@ typedef FormData_pg_proc *Form_pg_proc; #define Anum_pg_proc_prorows 6 #define Anum_pg_proc_provariadic 7 #define Anum_pg_proc_protransform 8 -#define Anum_pg_proc_proisagg 9 -#define Anum_pg_proc_proiswindow 10 -#define Anum_pg_proc_prosecdef 11 -#define Anum_pg_proc_proleakproof 12 -#define Anum_pg_proc_proisstrict 13 -#define Anum_pg_proc_proretset 14 -#define Anum_pg_proc_provolatile 15 -#define Anum_pg_proc_proparallel 16 -#define Anum_pg_proc_pronargs 17 -#define Anum_pg_proc_pronargdefaults 18 -#define Anum_pg_proc_prorettype 19 -#define Anum_pg_proc_proargtypes 20 -#define Anum_pg_proc_proallargtypes 21 -#define Anum_pg_proc_proargmodes 22 -#define Anum_pg_proc_proargnames 23 -#define Anum_pg_proc_proargdefaults 24 -#define Anum_pg_proc_protrftypes 25 -#define Anum_pg_proc_prosrc 26 -#define Anum_pg_proc_probin 27 -#define Anum_pg_proc_proconfig 28 -#define Anum_pg_proc_proacl 29 +#define Anum_pg_proc_prokind 9 +#define Anum_pg_proc_prosecdef 10 +#define Anum_pg_proc_proleakproof 11 +#define Anum_pg_proc_proisstrict 12 +#define Anum_pg_proc_proretset 13 +#define Anum_pg_proc_provolatile 14 +#define Anum_pg_proc_proparallel 15 +#define Anum_pg_proc_pronargs 16 +#define Anum_pg_proc_pronargdefaults 17 +#define Anum_pg_proc_prorettype 18 +#define Anum_pg_proc_proargtypes 19 +#define Anum_pg_proc_proallargtypes 20 +#define Anum_pg_proc_proargmodes 21 +#define Anum_pg_proc_proargnames 22 +#define Anum_pg_proc_proargdefaults 23 +#define Anum_pg_proc_protrftypes 24 +#define Anum_pg_proc_prosrc 25 +#define Anum_pg_proc_probin 26 +#define Anum_pg_proc_proconfig 27 +#define Anum_pg_proc_proacl 28 /* ---------------- * initial contents of pg_proc @@ -5569,6 +5567,14 @@ DESCR("list of files in the WAL directory"); DATA(insert OID = 5028 ( satisfies_hash_partition PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 4 0 16 "26 23 23 2276" _null_ "{i,i,i,v}" _null_ _null_ _null_ satisfies_hash_partition _null_ _null_ _null_ )); DESCR("hash partition CHECK constraint"); +/* + * Symbolic values for prokind column + */ +#define PROKIND_FUNCTION 'f' +#define PROKIND_AGGREGATE 'a' +#define PROKIND_WINDOW 'w' +#define PROKIND_PROCEDURE 'p' + /* * Symbolic values for provolatile column: these indicate whether the result * of a function is dependent *only* on the values of its explicit arguments, diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h index 098e2e6f07..b66871bc46 100644 --- a/src/include/catalog/pg_proc_fn.h +++ b/src/include/catalog/pg_proc_fn.h @@ -27,8 +27,7 @@ extern ObjectAddress ProcedureCreate(const char *procedureName, Oid languageValidator, const char *prosrc, const char *probin, - bool isAgg, - bool isWindowFunc, + char prokind, bool security_definer, bool isLeakProof, bool isStrict, diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c index 4e06413cd4..64dc0187eb 100644 --- a/src/pl/plpython/plpy_procedure.c +++ b/src/pl/plpython/plpy_procedure.c @@ -188,7 +188,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) proc->fn_tid = procTup->t_self; proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE); proc->is_setof = procStruct->proretset; - proc->is_procedure = (procStruct->prorettype == InvalidOid); + proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE); proc->src = NULL; proc->argnames = NULL; proc->args = NULL; diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 5df4dfdf55..7e09fbf4e2 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -1523,7 +1523,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, * Get the required information for input conversion of the * return value. ************************************************************/ - prodesc->fn_is_procedure = (procStruct->prorettype == InvalidOid); + prodesc->fn_is_procedure = (procStruct->prokind == PROKIND_PROCEDURE); if (!is_trigger && !is_event_trigger && procStruct->prorettype) { diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out index 44356dea0b..db9d761adf 100644 --- a/src/test/regress/expected/alter_generic.out +++ b/src/test/regress/expected/alter_generic.out @@ -83,7 +83,7 @@ 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, proisagg, a.rolname +SELECT n.nspname, proname, prorettype::regtype, prokind = 'a' AS 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/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out index 5ff1e0dd86..0bac62d858 100644 --- a/src/test/regress/expected/create_function_3.out +++ b/src/test/regress/expected/create_function_3.out @@ -271,6 +271,15 @@ ERROR: could not find a function named "functest_b_1" DROP FUNCTION functest_b_2; -- error, ambiguous ERROR: function name "functest_b_2" is not unique 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 type +DETAIL: functest1" is a function. +CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1'; +ERROR: cannot change routine type +DETAIL: functest1" is a function. +DROP FUNCTION functest1(a int); -- Cleanups DROP SCHEMA temp_func_test CASCADE; NOTICE: drop cascades to 16 other objects diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 6616cc1bf0..5336c44808 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -88,10 +88,10 @@ WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-'; -----+--------- (0 rows) --- proiswindow shouldn't be set together with proisagg or proretset +-- proretset should only be set for normal functions SELECT p1.oid, p1.proname FROM pg_proc AS p1 -WHERE proiswindow AND (proisagg OR proretset); +WHERE proretset AND prokind != 'f'; oid | proname -----+--------- (0 rows) @@ -154,9 +154,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.proisagg = false OR p2.proisagg = false) AND + (p1.prokind != 'a' OR p2.prokind != 'a') AND (p1.prolang != p2.prolang OR - p1.proisagg != p2.proisagg OR + p1.prokind != p2.prokind OR p1.prosecdef != p2.prosecdef OR p1.proleakproof != p2.proleakproof OR p1.proisstrict != p2.proisstrict OR @@ -182,7 +182,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 - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.prorettype < p2.prorettype) @@ -198,7 +198,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 - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.proargtypes[0] < p2.proargtypes[0]) @@ -216,7 +216,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 - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.proargtypes[1] < p2.proargtypes[1]) @@ -233,7 +233,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 - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[2] < p2.proargtypes[2]) ORDER BY 1, 2; proargtypes | proargtypes @@ -246,7 +246,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 - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[3] < p2.proargtypes[3]) ORDER BY 1, 2; proargtypes | proargtypes @@ -259,7 +259,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 - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[4] < p2.proargtypes[4]) ORDER BY 1, 2; proargtypes | proargtypes @@ -271,7 +271,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 - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[5] < p2.proargtypes[5]) ORDER BY 1, 2; proargtypes | proargtypes @@ -283,7 +283,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 - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[6] < p2.proargtypes[6]) ORDER BY 1, 2; proargtypes | proargtypes @@ -295,7 +295,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 - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[7] < p2.proargtypes[7]) ORDER BY 1, 2; proargtypes | proargtypes @@ -1292,15 +1292,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 - (NOT p.proisagg OR p.proretset OR p.pronargs < a.aggnumdirectargs); + (p.prokind != 'a' OR p.proretset OR p.pronargs < a.aggnumdirectargs); aggfnoid | proname ----------+--------- (0 rows) --- Make sure there are no proisagg pg_proc entries without matches. +-- Make sure there are no prokind = PROKIND_AGGREGATE pg_proc entries without matches. SELECT oid, proname FROM pg_proc as p -WHERE p.proisagg AND +WHERE p.prokind = 'a' AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid); oid | proname -----+--------- @@ -1639,7 +1639,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.proisagg AND p2.proisagg AND + p1.prokind = 'a' AND p2.prokind = 'a' AND array_dims(p1.proargtypes) != array_dims(p2.proargtypes) ORDER BY 1; oid | oid @@ -1650,7 +1650,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 proisagg AND proargdefaults IS NOT NULL; +WHERE prokind = 'a' AND proargdefaults IS NOT NULL; oid | proname -----+--------- (0 rows) @@ -1660,7 +1660,7 @@ WHERE proisagg 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 proisagg AND provariadic != 0 AND a.aggkind = 'n'; +WHERE prokind = 'a' AND provariadic != 0 AND a.aggkind = 'n'; oid | proname -----+--------- (0 rows) diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 5433944c6a..a6e4ca5ce2 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1521,9 +1521,11 @@ UNION ALL SELECT l.objoid, l.classoid, l.objsubid, - CASE - WHEN (pro.proisagg = true) THEN 'aggregate'::text - WHEN (pro.proisagg = false) THEN 'function'::text + 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 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 96be6e752a..b3d76d01fe 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, proisagg, a.rolname +SELECT n.nspname, proname, prorettype::regtype, prokind = 'a' AS 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 fbdf8310e3..8f209d55af 100644 --- a/src/test/regress/sql/create_function_3.sql +++ b/src/test/regress/sql/create_function_3.sql @@ -175,6 +175,14 @@ CREATE FUNCTION functest_B_2(bigint) RETURNS bool LANGUAGE 'sql' DROP FUNCTION functest_b_2; -- error, ambiguous +-- 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'; +CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1'; +DROP FUNCTION functest1(a int); + + -- Cleanups DROP SCHEMA temp_func_test CASCADE; DROP USER regress_unpriv_user; diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index e8fdf8454d..381c14fa86 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -90,10 +90,10 @@ FROM pg_proc as p1 WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-'; --- proiswindow shouldn't be set together with proisagg or proretset +-- proretset should only be set for normal functions SELECT p1.oid, p1.proname FROM pg_proc AS p1 -WHERE proiswindow AND (proisagg OR proretset); +WHERE proretset AND prokind != 'f'; -- currently, no built-in functions should be SECURITY DEFINER; -- this might change in future, but there will probably never be many. @@ -140,9 +140,9 @@ WHERE p1.oid < p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - (p1.proisagg = false OR p2.proisagg = false) AND + (p1.prokind != 'a' OR p2.prokind != 'a') AND (p1.prolang != p2.prolang OR - p1.proisagg != p2.proisagg OR + p1.prokind != p2.prokind OR p1.prosecdef != p2.prosecdef OR p1.proleakproof != p2.proleakproof OR p1.proisstrict != p2.proisstrict OR @@ -166,7 +166,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.prorettype < p2.prorettype) @@ -177,7 +177,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.proargtypes[0] < p2.proargtypes[0]) @@ -188,7 +188,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND p1.prosrc NOT LIKE E'range\\_constructor_' AND p2.prosrc NOT LIKE E'range\\_constructor_' AND (p1.proargtypes[1] < p2.proargtypes[1]) @@ -199,7 +199,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[2] < p2.proargtypes[2]) ORDER BY 1, 2; @@ -208,7 +208,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[3] < p2.proargtypes[3]) ORDER BY 1, 2; @@ -217,7 +217,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[4] < p2.proargtypes[4]) ORDER BY 1, 2; @@ -226,7 +226,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[5] < p2.proargtypes[5]) ORDER BY 1, 2; @@ -235,7 +235,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[6] < p2.proargtypes[6]) ORDER BY 1, 2; @@ -244,7 +244,7 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND - NOT p1.proisagg AND NOT p2.proisagg AND + p1.prokind != 'a' AND p2.prokind != 'a' AND (p1.proargtypes[7] < p2.proargtypes[7]) ORDER BY 1, 2; @@ -804,13 +804,13 @@ SELECT a.aggfnoid::oid, p.proname FROM pg_aggregate as a, pg_proc as p WHERE a.aggfnoid = p.oid AND - (NOT p.proisagg OR p.proretset OR p.pronargs < a.aggnumdirectargs); + (p.prokind != 'a' OR p.proretset OR p.pronargs < a.aggnumdirectargs); --- Make sure there are no proisagg pg_proc entries without matches. +-- Make sure there are no prokind = PROKIND_AGGREGATE pg_proc entries without matches. SELECT oid, proname FROM pg_proc as p -WHERE p.proisagg AND +WHERE p.prokind = 'a' 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. @@ -1089,7 +1089,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.proisagg AND p2.proisagg AND + p1.prokind = 'a' AND p2.prokind = 'a' AND array_dims(p1.proargtypes) != array_dims(p2.proargtypes) ORDER BY 1; @@ -1097,7 +1097,7 @@ SELECT oid, proname FROM pg_proc AS p -WHERE proisagg AND proargdefaults IS NOT NULL; +WHERE prokind = 'a' 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 @@ -1105,7 +1105,7 @@ SELECT p.oid, proname FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid -WHERE proisagg AND provariadic != 0 AND a.aggkind = 'n'; +WHERE prokind = 'a' AND provariadic != 0 AND a.aggkind = 'n'; -- **************** pg_opfamily **************** base-commit: bc1adc651b8e60680aea144d51ae8bc78ea6b2fb -- 2.16.2