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>
This commit is contained in:
Peter Eisentraut 2018-03-02 08:57:38 -05:00
parent 1733460f02
commit fd1a421fe6
40 changed files with 3246 additions and 3174 deletions

View File

@ -5062,15 +5062,17 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
</indexterm>
<para>
The catalog <structname>pg_proc</structname> stores information about functions (or procedures).
See <xref linkend="sql-createfunction"/>
and <xref linkend="xfunc"/> for more information.
The catalog <structname>pg_proc</structname> stores information about
functions, procedures, aggregate functions, and window functions
(collectively also known as routines). See <xref
linkend="sql-createfunction"/>, <xref linkend="sql-createprocedure"/>, and
<xref linkend="xfunc"/> for more information.
</para>
<para>
The table contains data for aggregate functions as well as plain functions.
If <structfield>proisagg</structfield> is true, there should be a matching
row in <structfield>pg_aggregate</structfield>.
If <structfield>prokind</structfield> indicates that the entry is for an
aggregate function, there should be a matching row in
<structfield>pg_aggregate</structfield>.
</para>
<table>
@ -5157,17 +5159,12 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
</row>
<row>
<entry><structfield>proisagg</structfield></entry>
<entry><type>bool</type></entry>
<entry><structfield>prokind</structfield></entry>
<entry><type>char</type></entry>
<entry></entry>
<entry>Function is an aggregate function</entry>
</row>
<row>
<entry><structfield>proiswindow</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>Function is a window function</entry>
<entry><literal>f</literal> for a normal function, <literal>p</literal>
for a procedure, <literal>a</literal> for an aggregate function, or
<literal>w</literal> for a window function</entry>
</row>
<row>
@ -5264,7 +5261,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
<entry><structfield>prorettype</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>Data type of the return value, or null for a procedure</entry>
<entry>Data type of the return value</entry>
</row>
<row>

View File

@ -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);

View File

@ -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'));

View File

@ -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);

View File

@ -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 */

View File

@ -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))

View File

@ -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)

View File

@ -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",

View File

@ -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)
if (procstruct->prokind != PROKIND_FUNCTION)
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 not be a window function")));
errmsg("transform function must be a normal function")));
if (procstruct->proretset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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))

View File

@ -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)); */

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -5407,11 +5407,15 @@ 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, "
@ -5426,7 +5430,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 "
@ -5435,7 +5439,8 @@ getAggregates(Archive *fout, int *numAggs)
acl_subquery->data,
racl_subquery->data,
initacl_subquery->data,
initracl_subquery->data);
initracl_subquery->data,
agg_check);
if (dopt->binary_upgrade)
appendPQExpBufferStr(query,
" OR EXISTS(SELECT 1 FROM pg_depend WHERE "
@ -5616,11 +5621,15 @@ 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, "
@ -5635,7 +5644,7 @@ getFuncs(Archive *fout, int *numFuncs)
"(p.oid = pip.objoid "
"AND pip.classoid = 'pg_proc'::regclass "
"AND pip.objsubid = 0) "
"WHERE NOT proisagg"
"WHERE %s"
"\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
"WHERE classid = 'pg_proc'::regclass AND "
"objid = p.oid AND deptype = 'i')"
@ -5655,6 +5664,7 @@ 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)
@ -11424,12 +11434,11 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
char *funcargs;
char *funciargs;
char *funcresult;
bool is_procedure;
char *proallargtypes;
char *proargmodes;
char *proargnames;
char *protrftypes;
char *proiswindow;
char *prokind;
char *provolatile;
char *proisstrict;
char *prosecdef;
@ -11459,7 +11468,26 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
asPart = createPQExpBuffer();
/* Fetch function-specific details */
if (fout->remoteVersion >= 90600)
if (fout->remoteVersion >= 110000)
{
/*
* prokind was added in 11
*/
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"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, "
"array_to_string(protrftypes, ' ') AS protrftypes, "
"prokind, 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",
finfo->dobj.catId.oid);
}
else if (fout->remoteVersion >= 90600)
{
/*
* proparallel was added in 9.6
@ -11470,7 +11498,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, "
"proiswindow, provolatile, proisstrict, prosecdef, "
"CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
"provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
"proparallel, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
@ -11489,7 +11518,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, "
"proiswindow, provolatile, proisstrict, prosecdef, "
"CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
"provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
@ -11506,7 +11536,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, "
"proiswindow, provolatile, proisstrict, prosecdef, "
"CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
"provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
@ -11524,7 +11555,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, "
"proiswindow, provolatile, proisstrict, prosecdef, "
"CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
" proconfig, procost, prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
@ -11537,7 +11569,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"proallargtypes, proargmodes, proargnames, "
"false AS proiswindow, "
"'f' AS prokind, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"proconfig, procost, prorows, "
@ -11551,7 +11583,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"proallargtypes, proargmodes, proargnames, "
"false AS proiswindow, "
"'f' AS prokind, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"null AS proconfig, 0 AS procost, 0 AS prorows, "
@ -11567,7 +11599,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
"null AS proallargtypes, "
"null AS proargmodes, "
"proargnames, "
"false AS proiswindow, "
"'f' AS prokind, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"null AS proconfig, 0 AS procost, 0 AS prorows, "
@ -11586,11 +11618,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
{
funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
is_procedure = PQgetisnull(res, 0, PQfnumber(res, "funcresult"));
if (is_procedure)
funcresult = NULL;
else
funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
proallargtypes = proargmodes = proargnames = NULL;
}
else
@ -11599,13 +11627,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
funcargs = funciargs = funcresult = NULL;
is_procedure = false;
}
if (PQfnumber(res, "protrftypes") != -1)
protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
else
protrftypes = NULL;
proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
@ -11731,7 +11758,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
funcsig_tag = format_function_signature(fout, finfo, false);
keyword = is_procedure ? "PROCEDURE" : "FUNCTION";
if (prokind[0] == PROKIND_PROCEDURE)
keyword = "PROCEDURE";
else
keyword = "FUNCTION"; /* works for window functions too */
appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
keyword,
@ -11744,8 +11774,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
funcfullsig ? funcfullsig :
funcsig);
if (is_procedure)
;
if (prokind[0] == PROKIND_PROCEDURE)
/* no result type to output */ ;
else if (funcresult)
appendPQExpBuffer(q, " RETURNS %s", funcresult);
else
@ -11776,7 +11806,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
}
}
if (proiswindow[0] == 't')
if (prokind[0] == PROKIND_WINDOW)
appendPQExpBufferStr(q, " WINDOW");
if (provolatile[0] != PROVOLATILE_VOLATILE)

View File

@ -6257,8 +6257,7 @@ qr/^GRANT SELECT ON TABLE dump_test_second_schema.measurement_y2006m2 TO regress
prorows,
provariadic,
protransform,
proisagg,
proiswindow,
prokind,
prosecdef,
proleakproof,
proisstrict,
@ -6290,8 +6289,7 @@ qr/^GRANT SELECT ON TABLE dump_test_second_schema.measurement_y2006m2 TO regress
\QGRANT SELECT(prorows) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
\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(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(prokind) 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.*

View File

@ -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,15 +354,14 @@ 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\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"
" 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"),
@ -363,6 +370,23 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
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 = 'pg_catalog.trigger'::pg_catalog.regtype 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("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");

View File

@ -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 */

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201802241
#define CATALOG_VERSION_NO 201803021
#endif

View File

@ -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("");

File diff suppressed because it is too large Load Diff

View File

@ -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,

View File

@ -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 bool get_func_isagg(Oid funcid);
extern char get_func_prokind(Oid funcid);
extern bool get_func_leakproof(Oid funcid);
extern float4 get_func_cost(Oid funcid);
extern float4 get_func_rows(Oid funcid);

View File

@ -2832,7 +2832,8 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger)
* Get the required information for input conversion of the
* return value.
************************************************************/
if (!is_trigger && !is_event_trigger && procStruct->prorettype)
if (!is_trigger && !is_event_trigger &&
procStruct->prokind != PROKIND_PROCEDURE)
{
Oid rettype = procStruct->prorettype;

View File

@ -275,6 +275,7 @@ do_compile(FunctionCallInfo fcinfo,
bool isnull;
char *proc_source;
HeapTuple typeTup;
Form_pg_type typeStruct;
PLpgSQL_variable *var;
PLpgSQL_rec *rec;
int i;
@ -365,6 +366,8 @@ do_compile(FunctionCallInfo fcinfo,
else
function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
function->fn_prokind = procStruct->prokind;
/*
* Initialize the compiler, particularly the namespace stack. The
* outermost namespace contains function parameters and other special
@ -529,55 +532,50 @@ do_compile(FunctionCallInfo fcinfo,
/*
* Lookup the function's return type
*/
if (rettypeid)
typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettypeid));
if (!HeapTupleIsValid(typeTup))
elog(ERROR, "cache lookup failed for type %u", rettypeid);
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype result, except VOID or RECORD */
/* (note we already replaced polymorphic types) */
if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
Form_pg_type typeStruct;
typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettypeid));
if (!HeapTupleIsValid(typeTup))
elog(ERROR, "cache lookup failed for type %u", rettypeid);
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype result, except VOID or RECORD */
/* (note we already replaced polymorphic types) */
if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
if (rettypeid == VOIDOID ||
rettypeid == RECORDOID)
/* okay */ ;
else if (rettypeid == TRIGGEROID || rettypeid == EVTTRIGGEROID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("trigger functions can only be called as triggers")));
else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("PL/pgSQL functions cannot return type %s",
format_type_be(rettypeid))));
}
function->fn_retistuple = type_is_rowtype(rettypeid);
function->fn_retisdomain = (typeStruct->typtype == TYPTYPE_DOMAIN);
function->fn_retbyval = typeStruct->typbyval;
function->fn_rettyplen = typeStruct->typlen;
/*
* install $0 reference, but only for polymorphic return
* types, and not when the return is specified through an
* output parameter.
*/
if (IsPolymorphicType(procStruct->prorettype) &&
num_out_args == 0)
{
(void) plpgsql_build_variable("$0", 0,
build_datatype(typeTup,
-1,
function->fn_input_collation),
true);
}
ReleaseSysCache(typeTup);
if (rettypeid == VOIDOID ||
rettypeid == RECORDOID)
/* okay */ ;
else if (rettypeid == TRIGGEROID || rettypeid == EVTTRIGGEROID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("trigger functions can only be called as triggers")));
else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("PL/pgSQL functions cannot return type %s",
format_type_be(rettypeid))));
}
function->fn_retistuple = type_is_rowtype(rettypeid);
function->fn_retisdomain = (typeStruct->typtype == TYPTYPE_DOMAIN);
function->fn_retbyval = typeStruct->typbyval;
function->fn_rettyplen = typeStruct->typlen;
/*
* install $0 reference, but only for polymorphic return
* types, and not when the return is specified through an
* output parameter.
*/
if (IsPolymorphicType(procStruct->prorettype) &&
num_out_args == 0)
{
(void) plpgsql_build_variable("$0", 0,
build_datatype(typeTup,
-1,
function->fn_input_collation),
true);
}
ReleaseSysCache(typeTup);
break;
case PLPGSQL_DML_TRIGGER:
@ -890,6 +888,7 @@ plpgsql_compile_inline(char *proc_source)
function->fn_retset = false;
function->fn_retistuple = false;
function->fn_retisdomain = false;
function->fn_prokind = PROKIND_FUNCTION;
/* a bit of hardwired knowledge about type VOID here */
function->fn_retbyval = true;
function->fn_rettyplen = sizeof(int32);

View File

@ -573,7 +573,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
estate.err_text = NULL;
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
rc = exec_stmt_block(&estate, func->action);
if (rc != PLPGSQL_RC_RETURN && func->fn_rettype)
if (rc != PLPGSQL_RC_RETURN)
{
estate.err_stmt = NULL;
estate.err_text = NULL;
@ -617,9 +617,10 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
}
else if (!estate.retisnull)
{
if (!func->fn_rettype)
if (func->fn_prokind == PROKIND_PROCEDURE)
ereport(ERROR,
(errmsg("cannot return a value from a procedure")));
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot return a value from a procedure")));
/*
* Cast result value to function's declared result type, and copy it
@ -2956,9 +2957,10 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
/*
* Special hack for function returning VOID: instead of NULL, return a
* non-null VOID value. This is of dubious importance but is kept for
* backwards compatibility.
* backwards compatibility. We don't do it for procedures, though.
*/
if (estate->fn_rettype == VOIDOID)
if (estate->fn_rettype == VOIDOID &&
estate->func->fn_prokind != PROKIND_PROCEDURE)
{
estate->retval = (Datum) 0;
estate->retisnull = false;

View File

@ -16,6 +16,7 @@
#include "postgres.h"
#include "catalog/namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "parser/parser.h"
#include "parser/parse_type.h"
@ -3137,7 +3138,8 @@ make_return_stmt(int location)
parser_errposition(yylloc)));
new->retvarno = plpgsql_curr_compile->out_param_varno;
}
else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
else if (plpgsql_curr_compile->fn_rettype == VOIDOID &&
plpgsql_curr_compile->fn_prokind != PROKIND_PROCEDURE)
{
if (yylex() != ';')
ereport(ERROR,

View File

@ -918,6 +918,7 @@ typedef struct PLpgSQL_function
bool fn_retisdomain;
bool fn_retset;
bool fn_readonly;
char fn_prokind;
int fn_nargs;
int fn_argvarnos[FUNC_MAX_ARGS];

View File

@ -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;
@ -208,7 +208,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
* get information required for output conversion of the return value,
* but only if this isn't a trigger or procedure.
*/
if (!is_trigger && procStruct->prorettype)
if (!is_trigger && procStruct->prokind != PROKIND_PROCEDURE)
{
Oid rettype = procStruct->prorettype;
HeapTuple rvTypeTup;

View File

@ -1523,9 +1523,9 @@ 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)
if (!is_trigger && !is_event_trigger && !prodesc->fn_is_procedure)
{
Oid rettype = procStruct->prorettype;

View File

@ -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, proisagg, a.rolname
SELECT n.nspname, proname, prorettype::regtype, prokind, 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 | proisagg | rolname
----------+-----------+------------+----------+---------------------
alt_nsp1 | alt_agg2 | integer | t | regress_alter_user2
alt_nsp1 | alt_agg3 | integer | t | regress_alter_user1
alt_nsp1 | alt_agg4 | integer | t | regress_alter_user2
alt_nsp1 | alt_func2 | integer | f | regress_alter_user2
alt_nsp1 | alt_func3 | integer | f | regress_alter_user1
alt_nsp1 | alt_func4 | integer | f | regress_alter_user2
alt_nsp2 | alt_agg2 | integer | t | regress_alter_user3
alt_nsp2 | alt_func2 | integer | f | regress_alter_user3
nspname | proname | prorettype | prokind | rolname
----------+-----------+------------+---------+---------------------
alt_nsp1 | alt_agg2 | integer | a | regress_alter_user2
alt_nsp1 | alt_agg3 | integer | a | regress_alter_user1
alt_nsp1 | alt_agg4 | integer | a | regress_alter_user2
alt_nsp1 | alt_func2 | integer | f | regress_alter_user2
alt_nsp1 | alt_func3 | integer | f | regress_alter_user1
alt_nsp1 | alt_func4 | integer | f | regress_alter_user2
alt_nsp2 | alt_agg2 | integer | a | regress_alter_user3
alt_nsp2 | alt_func2 | integer | f | regress_alter_user3
(8 rows)
--

View File

@ -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 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.
DROP FUNCTION functest1(a int);
-- Cleanups
DROP SCHEMA temp_func_test CASCADE;
NOTICE: drop cascades to 16 other objects

View File

@ -74,6 +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
provolatile NOT IN ('i', 's', 'v') OR
proparallel NOT IN ('s', 'r', 'u');
oid | proname
@ -88,10 +89,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 +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.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 +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
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 +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
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 +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
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 +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
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 +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
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 +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
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 +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
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 +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
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 +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
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 +1293,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 +1640,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 +1651,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 +1661,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)

View File

@ -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,

View File

@ -81,7 +81,7 @@ ALTER AGGREGATE alt_agg2(int) SET SCHEMA alt_nsp2; -- failed (name conflict)
RESET SESSION AUTHORIZATION;
SELECT n.nspname, proname, prorettype::regtype, proisagg, a.rolname
SELECT n.nspname, proname, prorettype::regtype, prokind, 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')

View File

@ -175,6 +175,14 @@ DROP FUNCTION functest_b_1; -- error, not found
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;

View File

@ -82,6 +82,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
provolatile NOT IN ('i', 's', 'v') OR
proparallel NOT IN ('s', 'r', 'u');
@ -90,10 +91,10 @@ SELECT p1.oid, p1.proname
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 +141,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
@ -166,7 +167,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)
@ -177,7 +178,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])
@ -188,7 +189,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])
@ -199,7 +200,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;
@ -208,7 +209,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;
@ -217,7 +218,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;
@ -226,7 +227,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;
@ -235,7 +236,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;
@ -244,7 +245,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;
@ -804,13 +805,13 @@ 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);
-- 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 +1090,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;
@ -1097,7 +1098,7 @@ ORDER BY 1;
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 +1106,7 @@ WHERE proisagg AND proargdefaults IS NOT NULL;
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 ****************