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:
parent
1733460f02
commit
fd1a421fe6
|
@ -5062,15 +5062,17 @@ SCRAM-SHA-256$<replaceable><iteration count></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><iteration count></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><iteration count></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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)); */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.*
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -53,6 +53,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 201802241
|
||||
#define CATALOG_VERSION_NO 201803021
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
--
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ****************
|
||||
|
|
Loading…
Reference in New Issue