aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2018-03-02 08:57:38 -0500
committerPeter Eisentraut <peter_e@gmx.net>2018-03-02 13:48:33 -0500
commitfd1a421fe66173fb9b85d3fe150afde8e812cbe4 (patch)
tree24c80c87337ec2d1bb46ee8463207d0cfff5ffc3 /src/backend
parent1733460f0205fc6d6bbe4c14911049a918c6e073 (diff)
downloadpostgresql-fd1a421fe66173fb9b85d3fe150afde8e812cbe4.tar.gz
postgresql-fd1a421fe66173fb9b85d3fe150afde8e812cbe4.zip
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. Also change prorettype to be VOIDOID for procedures. Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Michael Paquier <michael@paquier.xyz>
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/aclchk.c18
-rw-r--r--src/backend/catalog/information_schema.sql12
-rw-r--r--src/backend/catalog/objectaddress.c6
-rw-r--r--src/backend/catalog/pg_aggregate.c3
-rw-r--r--src/backend/catalog/pg_proc.c52
-rw-r--r--src/backend/catalog/system_views.sql8
-rw-r--r--src/backend/commands/dropcmds.c2
-rw-r--r--src/backend/commands/functioncmds.c36
-rw-r--r--src/backend/commands/proclang.c9
-rw-r--r--src/backend/commands/typecmds.c3
-rw-r--r--src/backend/executor/functions.c39
-rw-r--r--src/backend/optimizer/util/clauses.c4
-rw-r--r--src/backend/parser/parse_coerce.c3
-rw-r--r--src/backend/parser/parse_func.c35
-rw-r--r--src/backend/utils/adt/ruleutils.c10
-rw-r--r--src/backend/utils/cache/lsyscache.c12
16 files changed, 116 insertions, 136 deletions
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 1156627b9ec..3f2c629c472 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 686528c354d..f4e69f4a264 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,
@@ -1423,7 +1423,7 @@ CREATE VIEW routines AS
CAST(null AS sql_identifier) AS udt_name,
CAST(
- CASE WHEN p.prorettype = 0 THEN NULL
+ CASE WHEN p.prokind = 'p' THEN NULL
WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY'
WHEN nt.nspname = 'pg_catalog' THEN format_type(t.oid, null)
ELSE 'USER-DEFINED' END AS character_data)
@@ -1442,14 +1442,14 @@ CREATE VIEW routines AS
CAST(null AS cardinal_number) AS datetime_precision,
CAST(null AS character_data) AS interval_type,
CAST(null AS cardinal_number) AS interval_precision,
- CAST(CASE WHEN p.prorettype <> 0 THEN current_database() END AS sql_identifier) AS type_udt_catalog,
+ CAST(CASE WHEN nt.nspname IS NOT NULL THEN current_database() END AS sql_identifier) AS type_udt_catalog,
CAST(nt.nspname AS sql_identifier) AS type_udt_schema,
CAST(t.typname AS sql_identifier) AS type_udt_name,
CAST(null AS sql_identifier) AS scope_catalog,
CAST(null AS sql_identifier) AS scope_schema,
CAST(null AS sql_identifier) AS scope_name,
CAST(null AS cardinal_number) AS maximum_cardinality,
- CAST(0 AS sql_identifier) AS dtd_identifier,
+ CAST(CASE WHEN p.prokind <> 'p' THEN 0 END AS sql_identifier) AS dtd_identifier,
CAST(CASE WHEN l.lanname = 'sql' THEN 'SQL' ELSE 'EXTERNAL' END AS character_data)
AS routine_body,
@@ -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,
@@ -1511,7 +1511,7 @@ CREATE VIEW routines AS
JOIN pg_language l ON p.prolang = l.oid)
LEFT JOIN
(pg_type t JOIN pg_namespace nt ON t.typnamespace = nt.oid)
- ON p.prorettype = t.oid
+ ON p.prorettype = t.oid AND p.prokind <> 'p'
WHERE (pg_has_role(p.proowner, 'USAGE')
OR has_function_privilege(p.oid, 'EXECUTE'));
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 80f561df1c1..119297b33a0 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 f14ea26fcbf..50d8d81f2cc 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 b59fadbf769..40e579f95dc 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);
+ /* 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.
@@ -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.
@@ -857,8 +842,7 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
/* Disallow pseudotype result */
/* except for RECORD, VOID, or polymorphic */
- if (proc->prorettype &&
- get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
+ if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
!IsPolymorphicType(proc->prorettype))
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5652e9ee6d0..5e6e8a64f63 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -332,9 +332,11 @@ WHERE
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/dropcmds.c b/src/backend/commands/dropcmds.c
index fc4ce8d22ac..4b38ef68d98 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_isagg(address.objectId))
+ if (get_func_prokind(address.objectId) == PROKIND_AGGREGATE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function",
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index abdfa249c01..b1f87d056e5 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1003,9 +1003,12 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
if (stmt->is_procedure)
{
+ /*
+ * Sometime in the future, procedures might be allowed to return
+ * results; for now, they all return VOID.
+ */
Assert(!stmt->returnType);
-
- prorettype = InvalidOid;
+ prorettype = VOIDOID;
returnsSet = false;
}
else if (stmt->returnType)
@@ -1097,8 +1100,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 +1128,7 @@ RemoveFunctionById(Oid funcOid)
{
Relation relation;
HeapTuple tup;
- bool isagg;
+ char prokind;
/*
* Delete the pg_proc tuple.
@@ -1137,7 +1139,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 +1150,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 +1205,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 +1527,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 +1775,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 2ec96242ae4..447bd49f894 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 899a5c4cd4c..bf3cd3a4546 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/executor/functions.c b/src/backend/executor/functions.c
index 7e249f575f3..78bc4ab34bd 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -573,8 +573,7 @@ init_execution_state(List *queryTree_list,
*
* Note: don't set setsResult if the function returns VOID, as evidenced
* by not having made a junkfilter. This ensures we'll throw away any
- * output from a utility statement that check_sql_fn_retval deemed to not
- * have output.
+ * output from the last statement in such a function.
*/
if (lasttages && fcache->junkFilter)
{
@@ -659,8 +658,7 @@ init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK)
fcache->rettype = rettype;
/* Fetch the typlen and byval info for the result type */
- if (rettype)
- get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval);
+ get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval);
/* Remember whether we're returning setof something */
fcache->returnsSet = procedureStruct->proretset;
@@ -1324,8 +1322,8 @@ fmgr_sql(PG_FUNCTION_ARGS)
}
else
{
- /* Should only get here for procedures and VOID functions */
- Assert(fcache->rettype == InvalidOid || fcache->rettype == VOIDOID);
+ /* Should only get here for VOID functions and procedures */
+ Assert(fcache->rettype == VOIDOID);
fcinfo->isnull = true;
result = (Datum) 0;
}
@@ -1549,9 +1547,13 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
if (modifyTargetList)
*modifyTargetList = false; /* initialize for no change */
if (junkFilter)
- *junkFilter = NULL; /* initialize in case of procedure/VOID result */
+ *junkFilter = NULL; /* initialize in case of VOID result */
- if (!rettype)
+ /*
+ * If it's declared to return VOID, we don't care what's in the function.
+ * (This takes care of the procedure case, as well.)
+ */
+ if (rettype == VOIDOID)
return false;
/*
@@ -1597,21 +1599,17 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
else
{
/* Empty function body, or last statement is a utility command */
- if (rettype && rettype != VOIDOID)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
- errmsg("return type mismatch in function declared to return %s",
- format_type_be(rettype)),
- errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING.")));
- return false;
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("return type mismatch in function declared to return %s",
+ format_type_be(rettype)),
+ errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING.")));
+ return false; /* keep compiler quiet */
}
/*
* OK, check that the targetlist returns something matching the declared
- * type. (We used to insist that the declared type not be VOID in this
- * case, but that makes it hard to write a void function that exits after
- * calling another void function. Instead, we insist that the tlist
- * return void ... so void is treated as if it were a scalar type below.)
+ * type.
*/
/*
@@ -1624,8 +1622,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
if (fn_typtype == TYPTYPE_BASE ||
fn_typtype == TYPTYPE_DOMAIN ||
fn_typtype == TYPTYPE_ENUM ||
- fn_typtype == TYPTYPE_RANGE ||
- rettype == VOIDOID)
+ fn_typtype == TYPTYPE_RANGE)
{
/*
* For scalar-type returns, the target list must have exactly one
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 89f27ce0eb0..a9a09afd2b5 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -4484,12 +4484,12 @@ 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 nargs check is just paranoia.)
+ * properties. (The prokind and nargs checks are just paranoia.)
*/
if (funcform->prolang != SQLlanguageId ||
funcform->prosecdef ||
+ funcform->prokind != PROKIND_FUNCTION ||
funcform->proretset ||
- funcform->prorettype == InvalidOid ||
funcform->prorettype == RECORDOID ||
!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
funcform->pronargs != list_length(args))
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 085aa8766c9..665d3327a02 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 2a4ac09d5c9..ea5d5212b4c 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1614,14 +1614,27 @@ 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);
+ result = FUNCDETAIL_NORMAL; /* keep compiler quiet */
+ break;
+ }
+
ReleaseSysCache(ftup);
return result;
}
@@ -2067,7 +2080,7 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError)
if (objtype == OBJECT_FUNCTION)
{
/* Make sure it's a function, not a procedure */
- if (oid && get_func_rettype(oid) == InvalidOid)
+ if (oid && get_func_prokind(oid) == PROKIND_PROCEDURE)
{
if (noError)
return InvalidOid;
@@ -2098,7 +2111,7 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError)
}
/* Make sure it's a procedure */
- if (get_func_rettype(oid) != InvalidOid)
+ if (get_func_prokind(oid) != PROKIND_PROCEDURE)
{
if (noError)
return InvalidOid;
@@ -2134,7 +2147,7 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError)
}
/* Make sure it's an aggregate */
- if (!get_func_isagg(oid))
+ if (get_func_prokind(oid) != PROKIND_AGGREGATE)
{
if (noError)
return InvalidOid;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 36974667892..b58ee3c3876 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2481,12 +2481,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_PROCEDURE);
/*
* We always qualify the function name, to ensure the right function gets
@@ -2513,7 +2513,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)
{
@@ -2717,7 +2717,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();
@@ -2817,7 +2817,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 51b6b4f7bbe..bba595ad1da 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_isagg
- * Given procedure id, return the function's proisagg field.
+ * get_func_prokind
+ * Given procedure id, return the routine kind.
*/
-bool
-get_func_isagg(Oid funcid)
+char
+get_func_prokind(Oid funcid)
{
HeapTuple tp;
- bool result;
+ char result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(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;
ReleaseSysCache(tp);
return result;
}