Re: prokind column (was Re: [HACKERS] SQL procedures)
| От | Tom Lane |
|---|---|
| Тема | Re: prokind column (was Re: [HACKERS] SQL procedures) |
| Дата | |
| Msg-id | 1636.1519850740@sss.pgh.pa.us обсуждение исходный текст |
| Ответ на | Re: prokind column (was Re: [HACKERS] SQL procedures) (Michael Paquier <michael@paquier.xyz>) |
| Ответы |
Re: prokind column (was Re: [HACKERS] SQL procedures)
|
| Список | pgsql-hackers |
Michael Paquier <michael@paquier.xyz> writes:
> Here is some input from me. ...
I have reviewed this patch and attach an updated version below.
I've rebased it up to today, fixed a few minor errors, and adopted
most of Michael's suggestions. Also, since I remain desperately
unhappy with putting zeroes into prorettype, I changed it to not
do that ;-) ... now procedures have VOIDOID as their prorettype,
and it will be substantially less painful to allow them to return
some other scalar result in future, should we wish to. I believe
I've found all the places that were relying on prorettype == 0 as
a substitute for prokind == 'p'.
I have not touched the tab-complete.c changes. It doesn't really make
sense to worry about that until we see what comes out of the other thread
discussing support for server-version-sensitive tab completion. In the
meantime let's just add an open-item entry reminding us to do something
about it before v11 freezes.
Rather than manually audit the 0002 patch, I made a brain-dead little
Perl script to convert the DATA lines automatically, and attach it
below. If pg_proc.h moves further before this gets committed, the
script could be used to generate an updated 0002 patch.
One point worth noting is that in the attached, I made some edits to
pl_gram.y to preserve the existing handling of RETURN-with-a-value
in a plpgsql procedure. However, that existing handling is pretty
stupid. If we simply drop the pl_gram.y diffs below, what happens
is that RETURN-with-a-value is complained of at compile time not
execution time, which seems far superior to me (and more like what
happens in a normal function returning VOID). I think we should
do that and adjust the regression tests accordingly, but I have not
done the latter here.
I also wonder whether we should drop the stanza at the start of
pg_get_function_result() that causes it to return NULL for a procedure.
Without that, it would now return "void" which I think is at least
as defensible, and certainly more upward-compatible with any future
extension in that area. (I did make some changes in the
information_schema that cause it to report "void" not NULL in the
same case.)
Other than those points, I think this is committable, and I think we
should get it in quickly.
regards, tom lane
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 71e20f2..a0e6d70 100644
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
*************** SCRAM-SHA-256$<replaceable><iteration
*** 5062,5076 ****
</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.
</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>.
</para>
<table>
--- 5062,5078 ----
</indexterm>
<para>
! 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>
! 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>
*************** SCRAM-SHA-256$<replaceable><iteration
*** 5157,5173 ****
</row>
<row>
! <entry><structfield>proisagg</structfield></entry>
! <entry><type>bool</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>
</row>
<row>
--- 5159,5170 ----
</row>
<row>
! <entry><structfield>prokind</structfield></entry>
! <entry><type>char</type></entry>
<entry></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>
*************** SCRAM-SHA-256$<replaceable><iteration
*** 5264,5270 ****
<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>
</row>
<row>
--- 5261,5267 ----
<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</entry>
</row>
<row>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 1156627..3f2c629 100644
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
*************** objectsInSchemaToOids(ObjectType objtype
*** 830,850 ****
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)
ScanKeyInit(&key[keycount++],
! Anum_pg_proc_prorettype,
! BTEqualStrategyNumber, F_OIDNE,
! InvalidOid);
else if (objtype == OBJECT_PROCEDURE)
ScanKeyInit(&key[keycount++],
! Anum_pg_proc_prorettype,
! BTEqualStrategyNumber, F_OIDEQ,
! InvalidOid);
rel = heap_open(ProcedureRelationId, AccessShareLock);
scan = heap_beginscan_catalog(rel, keycount, key);
--- 830,846 ----
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(namespaceId));
if (objtype == OBJECT_FUNCTION)
+ /* includes aggregates and window functions */
ScanKeyInit(&key[keycount++],
! Anum_pg_proc_prokind,
! BTEqualStrategyNumber, F_CHARNE,
! CharGetDatum(PROKIND_PROCEDURE));
else if (objtype == OBJECT_PROCEDURE)
ScanKeyInit(&key[keycount++],
! Anum_pg_proc_prokind,
! BTEqualStrategyNumber, F_CHAREQ,
! CharGetDatum(PROKIND_PROCEDURE));
rel = heap_open(ProcedureRelationId, AccessShareLock);
scan = heap_beginscan_catalog(rel, keycount, key);
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index 686528c..9a6bf1b 100644
*** a/src/backend/catalog/information_schema.sql
--- b/src/backend/catalog/information_schema.sql
*************** CREATE VIEW routines AS
*** 1413,1419 ****
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
AS character_data) AS routine_type,
CAST(null AS sql_identifier) AS module_catalog,
CAST(null AS sql_identifier) AS module_schema,
--- 1413,1419 ----
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 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,
*************** CREATE VIEW routines AS
*** 1423,1430 ****
CAST(null AS sql_identifier) AS udt_name,
CAST(
! CASE WHEN p.prorettype = 0 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)
AS data_type,
--- 1423,1429 ----
CAST(null AS sql_identifier) AS udt_name,
CAST(
! CASE 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)
AS data_type,
*************** CREATE VIEW routines AS
*** 1442,1448 ****
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(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,
--- 1441,1447 ----
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(current_database() 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,
*************** CREATE VIEW routines AS
*** 1464,1470 ****
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
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,
--- 1463,1469 ----
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.prokind <> 'p' THEN
CASE WHEN p.proisstrict THEN 'YES' ELSE 'NO' END END AS yes_or_no) AS is_null_call,
CAST(null AS character_data) AS sql_path,
CAST('YES' AS yes_or_no) AS schema_level_routine,
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 80f561d..119297b 100644
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
*************** getProcedureTypeDescription(StringInfo b
*** 4047,4057 ****
elog(ERROR, "cache lookup failed for procedure %u", procid);
procForm = (Form_pg_proc) GETSTRUCT(procTup);
! if (procForm->proisagg)
appendStringInfoString(buffer, "aggregate");
! else if (procForm->prorettype == InvalidOid)
appendStringInfoString(buffer, "procedure");
! else
appendStringInfoString(buffer, "function");
ReleaseSysCache(procTup);
--- 4047,4057 ----
elog(ERROR, "cache lookup failed for procedure %u", procid);
procForm = (Form_pg_proc) GETSTRUCT(procTup);
! if (procForm->prokind == PROKIND_AGGREGATE)
appendStringInfoString(buffer, "aggregate");
! else if (procForm->prokind == PROKIND_PROCEDURE)
appendStringInfoString(buffer, "procedure");
! else /* function or window function */
appendStringInfoString(buffer, "function");
ReleaseSysCache(procTup);
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index f14ea26..50d8d81 100644
*** a/src/backend/catalog/pg_aggregate.c
--- b/src/backend/catalog/pg_aggregate.c
*************** AggregateCreate(const char *aggName,
*** 616,623 ****
InvalidOid, /* no validator */
"aggregate_dummy", /* placeholder proc */
NULL, /* probin */
! true, /* isAgg */
! false, /* isWindowFunc */
false, /* security invoker (currently not
* definable for agg) */
false, /* isLeakProof */
--- 616,622 ----
InvalidOid, /* no validator */
"aggregate_dummy", /* placeholder proc */
NULL, /* probin */
! PROKIND_AGGREGATE,
false, /* security invoker (currently not
* definable for agg) */
false, /* isLeakProof */
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index b59fadb..f7952b9 100644
*** a/src/backend/catalog/pg_proc.c
--- b/src/backend/catalog/pg_proc.c
*************** ProcedureCreate(const char *procedureNam
*** 74,81 ****
Oid languageValidator,
const char *prosrc,
const char *probin,
! bool isAgg,
! bool isWindowFunc,
bool security_definer,
bool isLeakProof,
bool isStrict,
--- 74,80 ----
Oid languageValidator,
const char *prosrc,
const char *probin,
! char prokind,
bool security_definer,
bool isLeakProof,
bool isStrict,
*************** ProcedureCreate(const char *procedureNam
*** 335,342 ****
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_prosecdef - 1] = BoolGetDatum(security_definer);
values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
--- 334,340 ----
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_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);
*************** ProcedureCreate(const char *procedureNam
*** 403,408 ****
--- 401,421 ----
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 type"),
+ (oldproc->prokind == PROKIND_AGGREGATE ?
+ errdetail("\"%s\" is an aggregate function.", procedureName) :
+ oldproc->prokind == PROKIND_FUNCTION ?
+ errdetail("\"%s\" is a function.", procedureName) :
+ oldproc->prokind == PROKIND_PROCEDURE ?
+ errdetail("\"%s\" is a procedure.", procedureName) :
+ oldproc->prokind == PROKIND_WINDOW ?
+ errdetail("\"%s\" is a window function.", procedureName) :
+ 0)));
+
/*
* Not okay to change the return type of the existing proc, since
* existing rules, views, etc may depend on the return type.
*************** ProcedureCreate(const char *procedureNam
*** 535,568 ****
}
}
- /* 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.
--- 548,553 ----
*************** fmgr_sql_validator(PG_FUNCTION_ARGS)
*** 857,864 ****
/* Disallow pseudotype result */
/* except for RECORD, VOID, or polymorphic */
! if (proc->prorettype &&
! get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
!IsPolymorphicType(proc->prorettype))
--- 842,848 ----
/* Disallow pseudotype result */
/* except for RECORD, VOID, or polymorphic */
! if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
!IsPolymorphicType(proc->prorettype))
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5652e9e..5e6e8a6 100644
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
*************** WHERE
*** 332,340 ****
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,
pro.pronamespace AS objnamespace,
CASE WHEN pg_function_is_visible(pro.oid)
THEN quote_ident(pro.proname)
--- 332,342 ----
UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
! CASE pro.prokind
! WHEN 'a' THEN 'aggregate'::text
! WHEN 'f' THEN 'function'::text
! WHEN 'p' THEN 'procedure'::text
! WHEN 'w' THEN 'window'::text END AS objtype,
pro.pronamespace AS objnamespace,
CASE WHEN pg_function_is_visible(pro.oid)
THEN quote_ident(pro.proname)
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index fc4ce8d..4b38ef6 100644
*** a/src/backend/commands/dropcmds.c
--- b/src/backend/commands/dropcmds.c
*************** RemoveObjects(DropStmt *stmt)
*** 92,98 ****
*/
if (stmt->removeType == OBJECT_FUNCTION)
{
! if (get_func_isagg(address.objectId))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function",
--- 92,98 ----
*/
if (stmt->removeType == OBJECT_FUNCTION)
{
! if (get_func_prokind(address.objectId) == PROKIND_AGGREGATE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function",
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index abdfa24..b1f87d0 100644
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
*************** CreateFunction(ParseState *pstate, Creat
*** 1003,1011 ****
if (stmt->is_procedure)
{
Assert(!stmt->returnType);
!
! prorettype = InvalidOid;
returnsSet = false;
}
else if (stmt->returnType)
--- 1003,1014 ----
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 = VOIDOID;
returnsSet = false;
}
else if (stmt->returnType)
*************** CreateFunction(ParseState *pstate, Creat
*** 1097,1104 ****
languageValidator,
prosrc_str, /* converted to text later */
probin_str, /* converted to text later */
! false, /* not an aggregate */
! isWindowFunc,
security,
isLeakProof,
isStrict,
--- 1100,1106 ----
languageValidator,
prosrc_str, /* converted to text later */
probin_str, /* converted to text later */
! stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW :
PROKIND_FUNCTION),
security,
isLeakProof,
isStrict,
*************** RemoveFunctionById(Oid funcOid)
*** 1126,1132 ****
{
Relation relation;
HeapTuple tup;
! bool isagg;
/*
* Delete the pg_proc tuple.
--- 1128,1134 ----
{
Relation relation;
HeapTuple tup;
! char prokind;
/*
* Delete the pg_proc tuple.
*************** RemoveFunctionById(Oid funcOid)
*** 1137,1143 ****
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for function %u", funcOid);
! isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;
CatalogTupleDelete(relation, &tup->t_self);
--- 1139,1145 ----
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for function %u", funcOid);
! prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind;
CatalogTupleDelete(relation, &tup->t_self);
*************** RemoveFunctionById(Oid funcOid)
*** 1148,1154 ****
/*
* If there's a pg_aggregate tuple, delete that too.
*/
! if (isagg)
{
relation = heap_open(AggregateRelationId, RowExclusiveLock);
--- 1150,1156 ----
/*
* If there's a pg_aggregate tuple, delete that too.
*/
! if (prokind == PROKIND_AGGREGATE)
{
relation = heap_open(AggregateRelationId, RowExclusiveLock);
*************** AlterFunction(ParseState *pstate, AlterF
*** 1203,1215 ****
aclcheck_error(ACLCHECK_NOT_OWNER, stmt->objtype,
NameListToString(stmt->func->objname));
! if (procForm->proisagg)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function",
NameListToString(stmt->func->objname))));
! is_procedure = (procForm->prorettype == InvalidOid);
/* Examine requested actions. */
foreach(l, stmt->actions)
--- 1205,1217 ----
aclcheck_error(ACLCHECK_NOT_OWNER, stmt->objtype,
NameListToString(stmt->func->objname));
! 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->prokind == PROKIND_PROCEDURE);
/* Examine requested actions. */
foreach(l, stmt->actions)
*************** CreateCast(CreateCastStmt *stmt)
*** 1525,1538 ****
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cast function must not be volatile")));
#endif
! if (procstruct->proisagg)
! 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")));
if (procstruct->proretset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
--- 1527,1536 ----
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cast function must not be volatile")));
#endif
! if (procstruct->prokind != PROKIND_FUNCTION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("cast function must be a normal function")));
if (procstruct->proretset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
*************** check_transform_function(Form_pg_proc pr
*** 1777,1790 ****
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("transform function must not be volatile")));
! if (procstruct->proisagg)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("transform function must not be an aggregate function")));
! if (procstruct->proiswindow)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("transform function must not be a window function")));
if (procstruct->proretset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
--- 1775,1784 ----
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("transform function must not be volatile")));
! if (procstruct->prokind != PROKIND_FUNCTION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("transform function must be a normal function")));
if (procstruct->proretset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 2ec9624..447bd49 100644
*** a/src/backend/commands/proclang.c
--- b/src/backend/commands/proclang.c
*************** CreateProceduralLanguage(CreatePLangStmt
*** 129,136 ****
F_FMGR_C_VALIDATOR,
pltemplate->tmplhandler,
pltemplate->tmpllibrary,
! false, /* isAgg */
! false, /* isWindowFunc */
false, /* security_definer */
false, /* isLeakProof */
false, /* isStrict */
--- 129,135 ----
F_FMGR_C_VALIDATOR,
pltemplate->tmplhandler,
pltemplate->tmpllibrary,
! PROKIND_FUNCTION,
false, /* security_definer */
false, /* isLeakProof */
false, /* isStrict */
*************** CreateProceduralLanguage(CreatePLangStmt
*** 169,176 ****
F_FMGR_C_VALIDATOR,
pltemplate->tmplinline,
pltemplate->tmpllibrary,
! false, /* isAgg */
! false, /* isWindowFunc */
false, /* security_definer */
false, /* isLeakProof */
true, /* isStrict */
--- 168,174 ----
F_FMGR_C_VALIDATOR,
pltemplate->tmplinline,
pltemplate->tmpllibrary,
! PROKIND_FUNCTION,
false, /* security_definer */
false, /* isLeakProof */
true, /* isStrict */
*************** CreateProceduralLanguage(CreatePLangStmt
*** 212,219 ****
F_FMGR_C_VALIDATOR,
pltemplate->tmplvalidator,
pltemplate->tmpllibrary,
! false, /* isAgg */
! false, /* isWindowFunc */
false, /* security_definer */
false, /* isLeakProof */
true, /* isStrict */
--- 210,216 ----
F_FMGR_C_VALIDATOR,
pltemplate->tmplvalidator,
pltemplate->tmpllibrary,
! PROKIND_FUNCTION,
false, /* security_definer */
false, /* isLeakProof */
true, /* isStrict */
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 899a5c4..bf3cd3a 100644
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
*************** makeRangeConstructors(const char *name,
*** 1672,1679 ****
F_FMGR_INTERNAL_VALIDATOR, /* language validator */
prosrc[i], /* prosrc */
NULL, /* probin */
! false, /* isAgg */
! false, /* isWindowFunc */
false, /* security_definer */
false, /* leakproof */
false, /* isStrict */
--- 1672,1678 ----
F_FMGR_INTERNAL_VALIDATOR, /* language validator */
prosrc[i], /* prosrc */
NULL, /* probin */
! PROKIND_FUNCTION,
false, /* security_definer */
false, /* leakproof */
false, /* isStrict */
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 7e249f5..78bc4ab 100644
*** a/src/backend/executor/functions.c
--- b/src/backend/executor/functions.c
*************** init_execution_state(List *queryTree_lis
*** 573,580 ****
*
* 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.
*/
if (lasttages && fcache->junkFilter)
{
--- 573,579 ----
*
* 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 the last statement in such a function.
*/
if (lasttages && fcache->junkFilter)
{
*************** init_sql_fcache(FmgrInfo *finfo, Oid col
*** 659,666 ****
fcache->rettype = rettype;
/* Fetch the typlen and byval info for the result type */
! if (rettype)
! get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval);
/* Remember whether we're returning setof something */
fcache->returnsSet = procedureStruct->proretset;
--- 658,664 ----
fcache->rettype = rettype;
/* Fetch the typlen and byval info for the result type */
! get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval);
/* Remember whether we're returning setof something */
fcache->returnsSet = procedureStruct->proretset;
*************** fmgr_sql(PG_FUNCTION_ARGS)
*** 1324,1331 ****
}
else
{
! /* Should only get here for procedures and VOID functions */
! Assert(fcache->rettype == InvalidOid || fcache->rettype == VOIDOID);
fcinfo->isnull = true;
result = (Datum) 0;
}
--- 1322,1329 ----
}
else
{
! /* Should only get here for VOID functions and procedures */
! Assert(fcache->rettype == VOIDOID);
fcinfo->isnull = true;
result = (Datum) 0;
}
*************** check_sql_fn_retval(Oid func_id, Oid ret
*** 1549,1557 ****
if (modifyTargetList)
*modifyTargetList = false; /* initialize for no change */
if (junkFilter)
! *junkFilter = NULL; /* initialize in case of procedure/VOID result */
! if (!rettype)
return false;
/*
--- 1547,1559 ----
if (modifyTargetList)
*modifyTargetList = false; /* initialize for no change */
if (junkFilter)
! *junkFilter = NULL; /* initialize in case of VOID result */
! /*
! * 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;
/*
*************** check_sql_fn_retval(Oid func_id, Oid ret
*** 1597,1617 ****
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;
}
/*
* 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.)
*/
/*
--- 1599,1615 ----
else
{
/* Empty function body, or last statement is a utility command */
! 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.
*/
/*
*************** check_sql_fn_retval(Oid func_id, Oid ret
*** 1624,1631 ****
if (fn_typtype == TYPTYPE_BASE ||
fn_typtype == TYPTYPE_DOMAIN ||
fn_typtype == TYPTYPE_ENUM ||
! fn_typtype == TYPTYPE_RANGE ||
! rettype == VOIDOID)
{
/*
* For scalar-type returns, the target list must have exactly one
--- 1622,1628 ----
if (fn_typtype == TYPTYPE_BASE ||
fn_typtype == TYPTYPE_DOMAIN ||
fn_typtype == TYPTYPE_ENUM ||
! fn_typtype == TYPTYPE_RANGE)
{
/*
* For scalar-type returns, the target list must have exactly one
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 89f27ce..a9a09af 100644
*** a/src/backend/optimizer/util/clauses.c
--- b/src/backend/optimizer/util/clauses.c
*************** inline_function(Oid funcid, Oid result_t
*** 4484,4495 ****
/*
* Forget it if the function is not SQL-language or has other showstopper
! * properties. (The nargs check is just paranoia.)
*/
if (funcform->prolang != SQLlanguageId ||
funcform->prosecdef ||
funcform->proretset ||
- funcform->prorettype == InvalidOid ||
funcform->prorettype == RECORDOID ||
!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
funcform->pronargs != list_length(args))
--- 4484,4495 ----
/*
* Forget it if the function is not SQL-language or has other showstopper
! * properties. (The prokind and nargs checks are just paranoia.)
*/
if (funcform->prolang != SQLlanguageId ||
funcform->prosecdef ||
+ funcform->prokind != PROKIND_FUNCTION ||
funcform->proretset ||
funcform->prorettype == RECORDOID ||
!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
funcform->pronargs != list_length(args))
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 085aa87..665d332 100644
*** a/src/backend/parser/parse_coerce.c
--- b/src/backend/parser/parse_coerce.c
*************** build_coercion_expression(Node *node,
*** 834,841 ****
*/
/* Assert(targetTypeId == procstruct->prorettype); */
Assert(!procstruct->proretset);
! Assert(!procstruct->proisagg);
! Assert(!procstruct->proiswindow);
nargs = procstruct->pronargs;
Assert(nargs >= 1 && nargs <= 3);
/* Assert(procstruct->proargtypes.values[0] == exprType(node)); */
--- 834,840 ----
*/
/* Assert(targetTypeId == procstruct->prorettype); */
Assert(!procstruct->proretset);
! Assert(procstruct->prokind == PROKIND_FUNCTION);
nargs = procstruct->pronargs;
Assert(nargs >= 1 && nargs <= 3);
/* Assert(procstruct->proargtypes.values[0] == exprType(node)); */
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 2a4ac09..ea5d521 100644
*** a/src/backend/parser/parse_func.c
--- b/src/backend/parser/parse_func.c
*************** func_get_detail(List *funcname,
*** 1614,1627 ****
*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;
ReleaseSysCache(ftup);
return result;
}
--- 1614,1640 ----
*argdefaults = defaults;
}
}
!
! 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;
}
*************** LookupFuncWithArgs(ObjectType objtype, O
*** 2067,2073 ****
if (objtype == OBJECT_FUNCTION)
{
/* Make sure it's a function, not a procedure */
! if (oid && get_func_rettype(oid) == InvalidOid)
{
if (noError)
return InvalidOid;
--- 2080,2086 ----
if (objtype == OBJECT_FUNCTION)
{
/* Make sure it's a function, not a procedure */
! if (oid && get_func_prokind(oid) == PROKIND_PROCEDURE)
{
if (noError)
return InvalidOid;
*************** LookupFuncWithArgs(ObjectType objtype, O
*** 2098,2104 ****
}
/* Make sure it's a procedure */
! if (get_func_rettype(oid) != InvalidOid)
{
if (noError)
return InvalidOid;
--- 2111,2117 ----
}
/* Make sure it's a procedure */
! if (get_func_prokind(oid) != PROKIND_PROCEDURE)
{
if (noError)
return InvalidOid;
*************** LookupFuncWithArgs(ObjectType objtype, O
*** 2134,2140 ****
}
/* Make sure it's an aggregate */
! if (!get_func_isagg(oid))
{
if (noError)
return InvalidOid;
--- 2147,2153 ----
}
/* Make sure it's an aggregate */
! if (get_func_prokind(oid) != PROKIND_AGGREGATE)
{
if (noError)
return InvalidOid;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 3697466..b58ee3c 100644
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
*************** pg_get_functiondef(PG_FUNCTION_ARGS)
*** 2481,2492 ****
proc = (Form_pg_proc) GETSTRUCT(proctup);
name = NameStr(proc->proname);
! if (proc->proisagg)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function", name)));
! isfunction = (proc->prorettype != InvalidOid);
/*
* We always qualify the function name, to ensure the right function gets
--- 2481,2492 ----
proc = (Form_pg_proc) GETSTRUCT(proctup);
name = NameStr(proc->proname);
! if (proc->prokind == PROKIND_AGGREGATE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function", name)));
! isfunction = (proc->prokind != PROKIND_PROCEDURE);
/*
* We always qualify the function name, to ensure the right function gets
*************** pg_get_functiondef(PG_FUNCTION_ARGS)
*** 2513,2519 ****
/* Emit some miscellaneous options on one line */
oldlen = buf.len;
! if (proc->proiswindow)
appendStringInfoString(&buf, " WINDOW");
switch (proc->provolatile)
{
--- 2513,2519 ----
/* Emit some miscellaneous options on one line */
oldlen = buf.len;
! if (proc->prokind == PROKIND_WINDOW)
appendStringInfoString(&buf, " WINDOW");
switch (proc->provolatile)
{
*************** pg_get_function_result(PG_FUNCTION_ARGS)
*** 2717,2723 ****
if (!HeapTupleIsValid(proctup))
PG_RETURN_NULL();
! if (((Form_pg_proc) GETSTRUCT(proctup))->prorettype == InvalidOid)
{
ReleaseSysCache(proctup);
PG_RETURN_NULL();
--- 2717,2723 ----
if (!HeapTupleIsValid(proctup))
PG_RETURN_NULL();
! if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
{
ReleaseSysCache(proctup);
PG_RETURN_NULL();
*************** print_function_arguments(StringInfo buf,
*** 2817,2823 ****
}
/* Check for special treatment of ordered-set aggregates */
! if (proc->proisagg)
{
HeapTuple aggtup;
Form_pg_aggregate agg;
--- 2817,2823 ----
}
/* Check for special treatment of ordered-set aggregates */
! if (proc->prokind == PROKIND_AGGREGATE)
{
HeapTuple aggtup;
Form_pg_aggregate agg;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 51b6b4f..bba595a 100644
*** a/src/backend/utils/cache/lsyscache.c
--- b/src/backend/utils/cache/lsyscache.c
*************** func_parallel(Oid funcid)
*** 1600,1619 ****
}
/*
! * get_func_isagg
! * Given procedure id, return the function's proisagg field.
*/
! bool
! get_func_isagg(Oid funcid)
{
HeapTuple tp;
! bool result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
! result = ((Form_pg_proc) GETSTRUCT(tp))->proisagg;
ReleaseSysCache(tp);
return result;
}
--- 1600,1619 ----
}
/*
! * get_func_prokind
! * Given procedure id, return the routine kind.
*/
! char
! get_func_prokind(Oid funcid)
{
HeapTuple tp;
! 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))->prokind;
ReleaseSysCache(tp);
return result;
}
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2c934e6..566cbf2 100644
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
*************** getAggregates(Archive *fout, int *numAgg
*** 5407,5417 ****
--- 5407,5421 ----
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, "
*************** getAggregates(Archive *fout, int *numAgg
*** 5426,5432 ****
"(p.oid = pip.objoid "
"AND pip.classoid = 'pg_proc'::regclass "
"AND pip.objsubid = 0) "
! "WHERE p.proisagg AND ("
"p.pronamespace != "
"(SELECT oid FROM pg_namespace "
"WHERE nspname = 'pg_catalog') OR "
--- 5430,5436 ----
"(p.oid = pip.objoid "
"AND pip.classoid = 'pg_proc'::regclass "
"AND pip.objsubid = 0) "
! "WHERE %s AND ("
"p.pronamespace != "
"(SELECT oid FROM pg_namespace "
"WHERE nspname = 'pg_catalog') OR "
*************** getAggregates(Archive *fout, int *numAgg
*** 5435,5441 ****
acl_subquery->data,
racl_subquery->data,
initacl_subquery->data,
! initracl_subquery->data);
if (dopt->binary_upgrade)
appendPQExpBufferStr(query,
" OR EXISTS(SELECT 1 FROM pg_depend WHERE "
--- 5439,5446 ----
acl_subquery->data,
racl_subquery->data,
initacl_subquery->data,
! initracl_subquery->data,
! agg_check);
if (dopt->binary_upgrade)
appendPQExpBufferStr(query,
" OR EXISTS(SELECT 1 FROM pg_depend WHERE "
*************** getFuncs(Archive *fout, int *numFuncs)
*** 5616,5626 ****
--- 5621,5635 ----
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, "
*************** getFuncs(Archive *fout, int *numFuncs)
*** 5635,5641 ****
"(p.oid = pip.objoid "
"AND pip.classoid = 'pg_proc'::regclass "
"AND pip.objsubid = 0) "
! "WHERE NOT proisagg"
"\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
"WHERE classid = 'pg_proc'::regclass AND "
"objid = p.oid AND deptype = 'i')"
--- 5644,5650 ----
"(p.oid = pip.objoid "
"AND pip.classoid = 'pg_proc'::regclass "
"AND pip.objsubid = 0) "
! "WHERE %s"
"\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
"WHERE classid = 'pg_proc'::regclass AND "
"objid = p.oid AND deptype = 'i')"
*************** getFuncs(Archive *fout, int *numFuncs)
*** 5655,5660 ****
--- 5664,5670 ----
initacl_subquery->data,
initracl_subquery->data,
username_subquery,
+ not_agg_check,
g_last_builtin_oid,
g_last_builtin_oid);
if (dopt->binary_upgrade)
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11424,11435 ****
char *funcargs;
char *funciargs;
char *funcresult;
- bool is_procedure;
char *proallargtypes;
char *proargmodes;
char *proargnames;
char *protrftypes;
! char *proiswindow;
char *provolatile;
char *proisstrict;
char *prosecdef;
--- 11434,11444 ----
char *funcargs;
char *funciargs;
char *funcresult;
char *proallargtypes;
char *proargmodes;
char *proargnames;
char *protrftypes;
! char *prokind;
char *provolatile;
char *proisstrict;
char *prosecdef;
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11459,11465 ****
asPart = createPQExpBuffer();
/* Fetch function-specific details */
! if (fout->remoteVersion >= 90600)
{
/*
* proparallel was added in 9.6
--- 11468,11493 ----
asPart = createPQExpBuffer();
/* Fetch function-specific details */
! 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
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11470,11476 ****
"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, "
"proleakproof, proconfig, procost, prorows, "
"proparallel, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
--- 11498,11505 ----
"pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
"pg_catalog.pg_get_function_result(oid) AS funcresult, "
"array_to_string(protrftypes, ' ') AS protrftypes, "
! "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
! "provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
"proparallel, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11489,11495 ****
"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, "
"proleakproof, proconfig, procost, prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
--- 11518,11525 ----
"pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
"pg_catalog.pg_get_function_result(oid) AS funcresult, "
"array_to_string(protrftypes, ' ') AS protrftypes, "
! "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
! "provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11506,11512 ****
"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, "
"proleakproof, proconfig, procost, prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
--- 11536,11543 ----
"pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
"pg_catalog.pg_get_function_result(oid) AS funcresult, "
! "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
! "provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11524,11530 ****
"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, "
"false AS proleakproof, "
" proconfig, procost, prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
--- 11555,11562 ----
"pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
"pg_catalog.pg_get_function_result(oid) AS funcresult, "
! "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
! "provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
" proconfig, procost, prorows, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11537,11543 ****
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"proallargtypes, proargmodes, proargnames, "
! "false AS proiswindow, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"proconfig, procost, prorows, "
--- 11569,11575 ----
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"proallargtypes, proargmodes, proargnames, "
! "'f' AS prokind, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"proconfig, procost, prorows, "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11551,11557 ****
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"proallargtypes, proargmodes, proargnames, "
! "false AS proiswindow, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"null AS proconfig, 0 AS procost, 0 AS prorows, "
--- 11583,11589 ----
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"proallargtypes, proargmodes, proargnames, "
! "'f' AS prokind, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"null AS proconfig, 0 AS procost, 0 AS prorows, "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11567,11573 ****
"null AS proallargtypes, "
"null AS proargmodes, "
"proargnames, "
! "false AS proiswindow, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"null AS proconfig, 0 AS procost, 0 AS prorows, "
--- 11599,11605 ----
"null AS proallargtypes, "
"null AS proargmodes, "
"proargnames, "
! "'f' AS prokind, "
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"null AS proconfig, 0 AS procost, 0 AS prorows, "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11586,11596 ****
{
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"));
proallargtypes = proargmodes = proargnames = NULL;
}
else
--- 11618,11624 ----
{
funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
! funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
proallargtypes = proargmodes = proargnames = NULL;
}
else
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11599,11611 ****
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"));
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
--- 11627,11638 ----
proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
funcargs = funciargs = funcresult = NULL;
}
if (PQfnumber(res, "protrftypes") != -1)
protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
else
protrftypes = NULL;
! 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"));
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11731,11737 ****
funcsig_tag = format_function_signature(fout, finfo, false);
! keyword = is_procedure ? "PROCEDURE" : "FUNCTION";
appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
keyword,
--- 11758,11767 ----
funcsig_tag = format_function_signature(fout, finfo, false);
! if (prokind[0] == PROKIND_PROCEDURE)
! keyword = "PROCEDURE";
! else
! keyword = "FUNCTION"; /* works for window functions too */
appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
keyword,
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11744,11751 ****
funcfullsig ? funcfullsig :
funcsig);
! if (is_procedure)
! ;
else if (funcresult)
appendPQExpBuffer(q, " RETURNS %s", funcresult);
else
--- 11774,11781 ----
funcfullsig ? funcfullsig :
funcsig);
! if (prokind[0] == PROKIND_PROCEDURE)
! /* no result type to output */ ;
else if (funcresult)
appendPQExpBuffer(q, " RETURNS %s", funcresult);
else
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11776,11782 ****
}
}
! if (proiswindow[0] == 't')
appendPQExpBufferStr(q, " WINDOW");
if (provolatile[0] != PROVOLATILE_VOLATILE)
--- 11806,11812 ----
}
}
! if (prokind[0] == PROKIND_WINDOW)
appendPQExpBufferStr(q, " WINDOW");
if (provolatile[0] != PROVOLATILE_VOLATILE)
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 6f74e15..1bea6ae 100644
*** a/src/bin/pg_dump/t/002_pg_dump.pl
--- b/src/bin/pg_dump/t/002_pg_dump.pl
*************** qr/^GRANT SELECT ON TABLE dump_test_seco
*** 6257,6264 ****
prorows,
provariadic,
protransform,
! proisagg,
! proiswindow,
prosecdef,
proleakproof,
proisstrict,
--- 6257,6263 ----
prorows,
provariadic,
protransform,
! prokind,
prosecdef,
proleakproof,
proisstrict,
*************** qr/^GRANT SELECT ON TABLE dump_test_seco
*** 6290,6297 ****
\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(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.*
--- 6289,6295 ----
\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(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.*
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 466a780..0c3be1f 100644
*** a/src/bin/psql/describe.c
--- b/src/bin/psql/describe.c
*************** describeAggregates(const char *pattern,
*** 100,111 ****
" 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 (!showSystem && !pattern)
appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
--- 100,119 ----
" pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
gettext_noop("Argument data types"));
! if (pset.sversion >= 110000)
! appendPQExpBuffer(&buf,
! " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
! "FROM pg_catalog.pg_proc p\n"
! " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
! "WHERE p.prokind = 'a'\n",
! gettext_noop("Description"));
! else
! appendPQExpBuffer(&buf,
! " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
! "FROM pg_catalog.pg_proc p\n"
! " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
! "WHERE p.proisagg\n",
! gettext_noop("Description"));
if (!showSystem && !pattern)
appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
*************** describeFunctions(const char *functypes,
*** 346,359 ****
gettext_noop("Schema"),
gettext_noop("Name"));
! if (pset.sversion >= 80400)
appendPQExpBuffer(&buf,
" pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
" pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
" CASE\n"
" WHEN p.proisagg THEN '%s'\n"
" WHEN p.proiswindow THEN '%s'\n"
- " WHEN p.prorettype = 0 THEN '%s'\n"
" WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
" ELSE '%s'\n"
" END as \"%s\"",
--- 354,384 ----
gettext_noop("Schema"),
gettext_noop("Name"));
! if (pset.sversion >= 110000)
! appendPQExpBuffer(&buf,
! " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
! " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
! " CASE p.prokind\n"
! " WHEN 'a' THEN '%s'\n"
! " WHEN 'w' THEN '%s'\n"
! " WHEN 'p' THEN '%s'\n"
! " ELSE '%s'\n"
! " END as \"%s\"",
! gettext_noop("Result data type"),
! gettext_noop("Argument data types"),
! /* translator: "agg" is short for "aggregate" */
! gettext_noop("agg"),
! gettext_noop("window"),
! gettext_noop("proc"),
! gettext_noop("func"),
! gettext_noop("Type"));
! else if (pset.sversion >= 80400)
appendPQExpBuffer(&buf,
" pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
" pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
" CASE\n"
" WHEN p.proisagg THEN '%s'\n"
" WHEN p.proiswindow THEN '%s'\n"
" WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
" ELSE '%s'\n"
" END as \"%s\"",
*************** describeFunctions(const char *functypes,
*** 362,368 ****
/* translator: "agg" is short for "aggregate" */
gettext_noop("agg"),
gettext_noop("window"),
- gettext_noop("proc"),
gettext_noop("trigger"),
gettext_noop("func"),
gettext_noop("Type"));
--- 387,392 ----
*************** describeFunctions(const char *functypes,
*** 494,500 ****
appendPQExpBufferStr(&buf, "WHERE ");
have_where = true;
}
! appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
}
if (!showTrigger)
{
--- 518,527 ----
appendPQExpBufferStr(&buf, "WHERE ");
have_where = true;
}
! if (pset.sversion >= 110000)
! appendPQExpBufferStr(&buf, "p.prokind <> 'a'\n");
! else
! appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
}
if (!showTrigger)
{
*************** describeFunctions(const char *functypes,
*** 516,522 ****
appendPQExpBufferStr(&buf, "WHERE ");
have_where = true;
}
! appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
}
}
else
--- 543,552 ----
appendPQExpBufferStr(&buf, "WHERE ");
have_where = true;
}
! if (pset.sversion >= 110000)
! appendPQExpBufferStr(&buf, "p.prokind <> 'w'\n");
! else
! appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
}
}
else
*************** describeFunctions(const char *functypes,
*** 528,534 ****
/* Note: at least one of these must be true ... */
if (showAggregate)
{
! appendPQExpBufferStr(&buf, "p.proisagg\n");
needs_or = true;
}
if (showTrigger)
--- 558,567 ----
/* Note: at least one of these must be true ... */
if (showAggregate)
{
! if (pset.sversion >= 110000)
! appendPQExpBufferStr(&buf, "p.prokind = 'a'\n");
! else
! appendPQExpBufferStr(&buf, "p.proisagg\n");
needs_or = true;
}
if (showTrigger)
*************** describeFunctions(const char *functypes,
*** 543,549 ****
{
if (needs_or)
appendPQExpBufferStr(&buf, " OR ");
! appendPQExpBufferStr(&buf, "p.proiswindow\n");
needs_or = true;
}
appendPQExpBufferStr(&buf, " )\n");
--- 576,585 ----
{
if (needs_or)
appendPQExpBufferStr(&buf, " OR ");
! if (pset.sversion >= 110000)
! appendPQExpBufferStr(&buf, "p.prokind = 'w'\n");
! else
! appendPQExpBufferStr(&buf, "p.proiswindow\n");
needs_or = true;
}
appendPQExpBufferStr(&buf, " )\n");
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 8bc4a19..cf23d13 100644
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
*************** static const SchemaQuery Query_for_list_
*** 349,355 ****
/* catname */
"pg_catalog.pg_proc p",
/* selcondition */
! "p.proisagg",
/* viscondition */
"pg_catalog.pg_function_is_visible(p.oid)",
/* namespace */
--- 349,355 ----
/* catname */
"pg_catalog.pg_proc p",
/* selcondition */
! "p.prokind = 'a'",
/* viscondition */
"pg_catalog.pg_function_is_visible(p.oid)",
/* namespace */
*************** static const SchemaQuery Query_for_list_
*** 397,403 ****
/* catname */
"pg_catalog.pg_proc p",
/* selcondition */
! "p.prorettype <> 0",
/* viscondition */
"pg_catalog.pg_function_is_visible(p.oid)",
/* namespace */
--- 397,403 ----
/* catname */
"pg_catalog.pg_proc p",
/* selcondition */
! "p.prokind IN ('f', 'w')",
/* viscondition */
"pg_catalog.pg_function_is_visible(p.oid)",
/* namespace */
*************** static const SchemaQuery Query_for_list_
*** 428,434 ****
/* catname */
"pg_catalog.pg_proc p",
/* selcondition */
! "p.prorettype = 0",
/* viscondition */
"pg_catalog.pg_function_is_visible(p.oid)",
/* namespace */
--- 428,434 ----
/* catname */
"pg_catalog.pg_proc p",
/* selcondition */
! "p.prokind = 'p'",
/* viscondition */
"pg_catalog.pg_function_is_visible(p.oid)",
/* namespace */
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 26b1866..01cf59e 100644
*** a/src/include/catalog/pg_class.h
--- b/src/include/catalog/pg_class.h
*************** DATA(insert OID = 1247 ( pg_type PGNSP
*** 151,157 ****
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_));
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("");
--- 151,157 ----
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 28 0 t f f f f f f t n f 3 1 _null_
_null__null_));
DESCR("");
DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 33 0 t f f f f f f t n f 3 1 _null_
_null__null_));
DESCR("");
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c00d055..b25c918 100644
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** CATALOG(pg_proc,1255) BKI_BOOTSTRAP BKI_
*** 43,50 ****
float4 prorows; /* estimated # of rows out (if proretset) */
Oid provariadic; /* element type of variadic array, or 0 */
regproc protransform; /* transforms calls to it during planning */
! bool proisagg; /* is it an aggregate? */
! bool proiswindow; /* is it a window function? */
bool prosecdef; /* security definer */
bool proleakproof; /* is it a leak-proof function? */
bool proisstrict; /* strict with respect to NULLs? */
--- 43,49 ----
float4 prorows; /* estimated # of rows out (if proretset) */
Oid provariadic; /* element type of variadic array, or 0 */
regproc protransform; /* transforms calls to it during planning */
! char prokind; /* see PROKIND_ categories below */
bool prosecdef; /* security definer */
bool proleakproof; /* is it a leak-proof function? */
bool proisstrict; /* strict with respect to NULLs? */
*************** typedef FormData_pg_proc *Form_pg_proc;
*** 86,92 ****
* compiler constants for pg_proc
* ----------------
*/
! #define Natts_pg_proc 29
#define Anum_pg_proc_proname 1
#define Anum_pg_proc_pronamespace 2
#define Anum_pg_proc_proowner 3
--- 85,91 ----
* compiler constants for pg_proc
* ----------------
*/
! #define Natts_pg_proc 28
#define Anum_pg_proc_proname 1
#define Anum_pg_proc_pronamespace 2
#define Anum_pg_proc_proowner 3
*************** typedef FormData_pg_proc *Form_pg_proc;
*** 95,121 ****
#define Anum_pg_proc_prorows 6
#define Anum_pg_proc_provariadic 7
#define Anum_pg_proc_protransform 8
! #define Anum_pg_proc_proisagg 9
! #define Anum_pg_proc_proiswindow 10
! #define Anum_pg_proc_prosecdef 11
! #define Anum_pg_proc_proleakproof 12
! #define Anum_pg_proc_proisstrict 13
! #define Anum_pg_proc_proretset 14
! #define Anum_pg_proc_provolatile 15
! #define Anum_pg_proc_proparallel 16
! #define Anum_pg_proc_pronargs 17
! #define Anum_pg_proc_pronargdefaults 18
! #define Anum_pg_proc_prorettype 19
! #define Anum_pg_proc_proargtypes 20
! #define Anum_pg_proc_proallargtypes 21
! #define Anum_pg_proc_proargmodes 22
! #define Anum_pg_proc_proargnames 23
! #define Anum_pg_proc_proargdefaults 24
! #define Anum_pg_proc_protrftypes 25
! #define Anum_pg_proc_prosrc 26
! #define Anum_pg_proc_probin 27
! #define Anum_pg_proc_proconfig 28
! #define Anum_pg_proc_proacl 29
/* ----------------
* initial contents of pg_proc
--- 94,119 ----
#define Anum_pg_proc_prorows 6
#define Anum_pg_proc_provariadic 7
#define Anum_pg_proc_protransform 8
! #define Anum_pg_proc_prokind 9
! #define Anum_pg_proc_prosecdef 10
! #define Anum_pg_proc_proleakproof 11
! #define Anum_pg_proc_proisstrict 12
! #define Anum_pg_proc_proretset 13
! #define Anum_pg_proc_provolatile 14
! #define Anum_pg_proc_proparallel 15
! #define Anum_pg_proc_pronargs 16
! #define Anum_pg_proc_pronargdefaults 17
! #define Anum_pg_proc_prorettype 18
! #define Anum_pg_proc_proargtypes 19
! #define Anum_pg_proc_proallargtypes 20
! #define Anum_pg_proc_proargmodes 21
! #define Anum_pg_proc_proargnames 22
! #define Anum_pg_proc_proargdefaults 23
! #define Anum_pg_proc_protrftypes 24
! #define Anum_pg_proc_prosrc 25
! #define Anum_pg_proc_probin 26
! #define Anum_pg_proc_proconfig 27
! #define Anum_pg_proc_proacl 28
/* ----------------
* initial contents of pg_proc
*************** DATA(insert OID = 5028 ( satisfies_hash_
*** 5576,5581 ****
--- 5574,5587 ----
DESCR("hash partition CHECK constraint");
/*
+ * Symbolic values for prokind column
+ */
+ #define PROKIND_FUNCTION 'f'
+ #define PROKIND_AGGREGATE 'a'
+ #define PROKIND_WINDOW 'w'
+ #define PROKIND_PROCEDURE 'p'
+
+ /*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
* or can change due to outside factors (such as parameter variables or
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 098e2e6..b66871b 100644
*** a/src/include/catalog/pg_proc_fn.h
--- b/src/include/catalog/pg_proc_fn.h
*************** extern ObjectAddress ProcedureCreate(con
*** 27,34 ****
Oid languageValidator,
const char *prosrc,
const char *probin,
! bool isAgg,
! bool isWindowFunc,
bool security_definer,
bool isLeakProof,
bool isStrict,
--- 27,33 ----
Oid languageValidator,
const char *prosrc,
const char *probin,
! char prokind,
bool security_definer,
bool isLeakProof,
bool isStrict,
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 1f6c04a..e55ea40 100644
*** a/src/include/utils/lsyscache.h
--- b/src/include/utils/lsyscache.h
*************** extern bool get_func_retset(Oid funcid);
*** 117,123 ****
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 bool get_func_leakproof(Oid funcid);
extern float4 get_func_cost(Oid funcid);
extern float4 get_func_rows(Oid funcid);
--- 117,123 ----
extern bool func_strict(Oid funcid);
extern char func_volatile(Oid funcid);
extern char func_parallel(Oid funcid);
! extern char get_func_prokind(Oid funcid);
extern bool get_func_leakproof(Oid funcid);
extern float4 get_func_cost(Oid funcid);
extern float4 get_func_rows(Oid funcid);
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 77c41b2..fa8e2fd 100644
*** a/src/pl/plperl/plperl.c
--- b/src/pl/plperl/plperl.c
*************** compile_plperl_function(Oid fn_oid, bool
*** 2832,2838 ****
* Get the required information for input conversion of the
* return value.
************************************************************/
! if (!is_trigger && !is_event_trigger && procStruct->prorettype)
{
Oid rettype = procStruct->prorettype;
--- 2832,2839 ----
* Get the required information for input conversion of the
* return value.
************************************************************/
! if (!is_trigger && !is_event_trigger &&
! procStruct->prokind != PROKIND_PROCEDURE)
{
Oid rettype = procStruct->prorettype;
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index d07a16a..6fbbc4a 100644
*** a/src/pl/plpgsql/src/pl_comp.c
--- b/src/pl/plpgsql/src/pl_comp.c
*************** do_compile(FunctionCallInfo fcinfo,
*** 275,280 ****
--- 275,281 ----
bool isnull;
char *proc_source;
HeapTuple typeTup;
+ Form_pg_type typeStruct;
PLpgSQL_variable *var;
PLpgSQL_rec *rec;
int i;
*************** do_compile(FunctionCallInfo fcinfo,
*** 365,370 ****
--- 366,373 ----
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
*************** do_compile(FunctionCallInfo fcinfo,
*** 529,538 ****
/*
* Lookup the function's return type
*/
- if (rettypeid)
- {
- Form_pg_type typeStruct;
-
typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettypeid));
if (!HeapTupleIsValid(typeTup))
elog(ERROR, "cache lookup failed for type %u", rettypeid);
--- 532,537 ----
*************** do_compile(FunctionCallInfo fcinfo,
*** 577,583 ****
}
ReleaseSysCache(typeTup);
- }
break;
case PLPGSQL_DML_TRIGGER:
--- 576,581 ----
*************** plpgsql_compile_inline(char *proc_source
*** 890,895 ****
--- 888,894 ----
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);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 4ff87e0..297aa3e 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** plpgsql_exec_function(PLpgSQL_function *
*** 573,579 ****
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)
{
estate.err_stmt = NULL;
estate.err_text = NULL;
--- 573,579 ----
estate.err_text = NULL;
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
rc = exec_stmt_block(&estate, func->action);
! if (rc != PLPGSQL_RC_RETURN)
{
estate.err_stmt = NULL;
estate.err_text = NULL;
*************** plpgsql_exec_function(PLpgSQL_function *
*** 617,625 ****
}
else if (!estate.retisnull)
{
! if (!func->fn_rettype)
ereport(ERROR,
! (errmsg("cannot return a value from a procedure")));
/*
* Cast result value to function's declared result type, and copy it
--- 617,626 ----
}
else if (!estate.retisnull)
{
! if (func->fn_prokind == PROKIND_PROCEDURE)
ereport(ERROR,
! (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
*************** exec_stmt_return(PLpgSQL_execstate *esta
*** 2956,2964 ****
/*
* 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.
*/
! if (estate->fn_rettype == VOIDOID)
{
estate->retval = (Datum) 0;
estate->retisnull = false;
--- 2957,2966 ----
/*
* 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. We don't do it for procedures, though.
*/
! if (estate->fn_rettype == VOIDOID &&
! estate->func->fn_prokind != PROKIND_PROCEDURE)
{
estate->retval = (Datum) 0;
estate->retisnull = false;
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 688fbd6..697ead0 100644
*** a/src/pl/plpgsql/src/pl_gram.y
--- b/src/pl/plpgsql/src/pl_gram.y
***************
*** 16,21 ****
--- 16,22 ----
#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"
*************** make_return_stmt(int location)
*** 3137,3143 ****
parser_errposition(yylloc)));
new->retvarno = plpgsql_curr_compile->out_param_varno;
}
! else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
{
if (yylex() != ';')
ereport(ERROR,
--- 3138,3145 ----
parser_errposition(yylloc)));
new->retvarno = plpgsql_curr_compile->out_param_varno;
}
! else if (plpgsql_curr_compile->fn_rettype == VOIDOID &&
! plpgsql_curr_compile->fn_prokind != PROKIND_PROCEDURE)
{
if (yylex() != ';')
ereport(ERROR,
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 26a7344..dd59036 100644
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
*************** typedef struct PLpgSQL_function
*** 918,923 ****
--- 918,924 ----
bool fn_retisdomain;
bool fn_retset;
bool fn_readonly;
+ char fn_prokind;
int fn_nargs;
int fn_argvarnos[FUNC_MAX_ARGS];
diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c
index 4e06413..82cc3f2 100644
*** a/src/pl/plpython/plpy_procedure.c
--- b/src/pl/plpython/plpy_procedure.c
*************** PLy_procedure_create(HeapTuple procTup,
*** 188,194 ****
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->src = NULL;
proc->argnames = NULL;
proc->args = NULL;
--- 188,194 ----
proc->fn_tid = procTup->t_self;
proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
proc->is_setof = procStruct->proretset;
! proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
proc->src = NULL;
proc->argnames = NULL;
proc->args = NULL;
*************** PLy_procedure_create(HeapTuple procTup,
*** 208,214 ****
* 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)
{
Oid rettype = procStruct->prorettype;
HeapTuple rvTypeTup;
--- 208,214 ----
* get information required for output conversion of the return value,
* but only if this isn't a trigger or procedure.
*/
! if (!is_trigger && procStruct->prokind != PROKIND_PROCEDURE)
{
Oid rettype = procStruct->prorettype;
HeapTuple rvTypeTup;
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 5df4dfd..2eb6c33 100644
*** a/src/pl/tcl/pltcl.c
--- b/src/pl/tcl/pltcl.c
*************** compile_pltcl_function(Oid fn_oid, Oid t
*** 1523,1531 ****
* Get the required information for input conversion of the
* return value.
************************************************************/
! prodesc->fn_is_procedure = (procStruct->prorettype == InvalidOid);
! if (!is_trigger && !is_event_trigger && procStruct->prorettype)
{
Oid rettype = procStruct->prorettype;
--- 1523,1531 ----
* Get the required information for input conversion of the
* return value.
************************************************************/
! prodesc->fn_is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
! if (!is_trigger && !is_event_trigger && !prodesc->fn_is_procedure)
{
Oid rettype = procStruct->prorettype;
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 44356de..3e40df1 100644
*** a/src/test/regress/expected/alter_generic.out
--- b/src/test/regress/expected/alter_generic.out
*************** ERROR: must be owner of function alt_ag
*** 83,103 ****
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
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
(8 rows)
--
--- 83,103 ----
ALTER AGGREGATE alt_agg2(int) SET SCHEMA alt_nsp2; -- failed (name conflict)
ERROR: function alt_agg2(integer) already exists in schema "alt_nsp2"
RESET SESSION AUTHORIZATION;
! SELECT n.nspname, proname, prorettype::regtype, prokind, a.rolname
FROM pg_proc p, pg_namespace n, pg_authid a
WHERE p.pronamespace = n.oid AND p.proowner = a.oid
AND n.nspname IN ('alt_nsp1', 'alt_nsp2')
ORDER BY nspname, proname;
! nspname | proname | prorettype | prokind | rolname
! ----------+-----------+------------+---------+---------------------
! alt_nsp1 | alt_agg2 | integer | a | regress_alter_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)
--
diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out
index 5ff1e0d..3cdd92c 100644
*** a/src/test/regress/expected/create_function_3.out
--- b/src/test/regress/expected/create_function_3.out
*************** ERROR: could not find a function named
*** 271,276 ****
--- 271,285 ----
DROP FUNCTION functest_b_2; -- error, ambiguous
ERROR: function name "functest_b_2" is not unique
HINT: Specify the argument list to select the function unambiguously.
+ -- CREATE OR REPLACE tests
+ CREATE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1';
+ CREATE OR REPLACE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1';
+ ERROR: cannot change routine type
+ DETAIL: "functest1" is a function.
+ CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1';
+ ERROR: cannot change routine type
+ DETAIL: "functest1" is a function.
+ DROP FUNCTION functest1(a int);
-- Cleanups
DROP SCHEMA temp_func_test CASCADE;
NOTICE: drop cascades to 16 other objects
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 6616cc1..01608d2 100644
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.prolang = 0 OR p1.prorettype =
*** 74,79 ****
--- 74,80 ----
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
*************** WHERE prosrc IS NULL OR prosrc = '' OR p
*** 88,97 ****
-----+---------
(0 rows)
! -- proiswindow shouldn't be set together with proisagg or proretset
SELECT p1.oid, p1.proname
FROM pg_proc AS p1
! WHERE proiswindow AND (proisagg OR proretset);
oid | proname
-----+---------
(0 rows)
--- 89,98 ----
-----+---------
(0 rows)
! -- proretset should only be set for normal functions
SELECT p1.oid, p1.proname
FROM pg_proc AS p1
! WHERE proretset AND prokind != 'f';
oid | proname
-----+---------
(0 rows)
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 154,162 ****
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.prolang != p2.prolang OR
! p1.proisagg != p2.proisagg OR
p1.prosecdef != p2.prosecdef OR
p1.proleakproof != p2.proleakproof OR
p1.proisstrict != p2.proisstrict OR
--- 155,163 ----
WHERE p1.oid < p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! (p1.prokind != 'a' OR p2.prokind != 'a') AND
(p1.prolang != p2.prolang OR
! p1.prokind != p2.prokind OR
p1.prosecdef != p2.prosecdef OR
p1.proleakproof != p2.proleakproof OR
p1.proisstrict != p2.proisstrict OR
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 182,188 ****
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.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.prorettype < p2.prorettype)
--- 183,189 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
p1.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.prorettype < p2.prorettype)
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 198,204 ****
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.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.proargtypes[0] < p2.proargtypes[0])
--- 199,205 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
p1.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.proargtypes[0] < p2.proargtypes[0])
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 216,222 ****
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.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.proargtypes[1] < p2.proargtypes[1])
--- 217,223 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
p1.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.proargtypes[1] < p2.proargtypes[1])
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 233,239 ****
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.proargtypes[2] < p2.proargtypes[2])
ORDER BY 1, 2;
proargtypes | proargtypes
--- 234,240 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[2] < p2.proargtypes[2])
ORDER BY 1, 2;
proargtypes | proargtypes
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 246,252 ****
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.proargtypes[3] < p2.proargtypes[3])
ORDER BY 1, 2;
proargtypes | proargtypes
--- 247,253 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[3] < p2.proargtypes[3])
ORDER BY 1, 2;
proargtypes | proargtypes
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 259,265 ****
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.proargtypes[4] < p2.proargtypes[4])
ORDER BY 1, 2;
proargtypes | proargtypes
--- 260,266 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[4] < p2.proargtypes[4])
ORDER BY 1, 2;
proargtypes | proargtypes
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 271,277 ****
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.proargtypes[5] < p2.proargtypes[5])
ORDER BY 1, 2;
proargtypes | proargtypes
--- 272,278 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[5] < p2.proargtypes[5])
ORDER BY 1, 2;
proargtypes | proargtypes
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 283,289 ****
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.proargtypes[6] < p2.proargtypes[6])
ORDER BY 1, 2;
proargtypes | proargtypes
--- 284,290 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[6] < p2.proargtypes[6])
ORDER BY 1, 2;
proargtypes | proargtypes
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 295,301 ****
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.proargtypes[7] < p2.proargtypes[7])
ORDER BY 1, 2;
proargtypes | proargtypes
--- 296,302 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[7] < p2.proargtypes[7])
ORDER BY 1, 2;
proargtypes | proargtypes
*************** WHERE aggfnoid = 0 OR aggtransfn = 0 OR
*** 1292,1306 ****
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);
aggfnoid | proname
----------+---------
(0 rows)
! -- Make sure there are no proisagg pg_proc entries without matches.
SELECT oid, proname
FROM pg_proc as p
! WHERE p.proisagg AND
NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
oid | proname
-----+---------
--- 1293,1307 ----
SELECT a.aggfnoid::oid, p.proname
FROM pg_aggregate as a, pg_proc as p
WHERE a.aggfnoid = p.oid AND
! (p.prokind != 'a' OR p.proretset OR p.pronargs < a.aggnumdirectargs);
aggfnoid | proname
----------+---------
(0 rows)
! -- Make sure there are no prokind = PROKIND_AGGREGATE pg_proc entries without matches.
SELECT oid, proname
FROM pg_proc as p
! WHERE p.prokind = 'a' AND
NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
oid | proname
-----+---------
*************** ORDER BY 1, 2;
*** 1639,1645 ****
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
array_dims(p1.proargtypes) != array_dims(p2.proargtypes)
ORDER BY 1;
oid | oid
--- 1640,1646 ----
SELECT p1.oid::regprocedure, p2.oid::regprocedure
FROM pg_proc AS p1, pg_proc AS p2
WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND
! p1.prokind = 'a' AND p2.prokind = 'a' AND
array_dims(p1.proargtypes) != array_dims(p2.proargtypes)
ORDER BY 1;
oid | oid
*************** ORDER BY 1;
*** 1650,1656 ****
-- 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;
oid | proname
-----+---------
(0 rows)
--- 1651,1657 ----
-- For the same reason, built-in aggregates with default arguments are no good.
SELECT oid, proname
FROM pg_proc AS p
! WHERE prokind = 'a' AND proargdefaults IS NOT NULL;
oid | proname
-----+---------
(0 rows)
*************** WHERE proisagg AND proargdefaults IS NOT
*** 1660,1666 ****
-- 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';
oid | proname
-----+---------
(0 rows)
--- 1661,1667 ----
-- that is not subject to the misplaced ORDER BY issue).
SELECT p.oid, proname
FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid
! WHERE prokind = 'a' AND provariadic != 0 AND a.aggkind = 'n';
oid | proname
-----+---------
(0 rows)
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 5acb92f..d7eff6c 100644
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
*************** UNION ALL
*** 1521,1529 ****
SELECT l.objoid,
l.classoid,
l.objsubid,
! CASE
! WHEN (pro.proisagg = true) THEN 'aggregate'::text
! WHEN (pro.proisagg = false) THEN 'function'::text
ELSE NULL::text
END AS objtype,
pro.pronamespace AS objnamespace,
--- 1521,1531 ----
SELECT l.objoid,
l.classoid,
l.objsubid,
! CASE pro.prokind
! WHEN 'a'::"char" THEN 'aggregate'::text
! WHEN 'f'::"char" THEN 'function'::text
! WHEN 'p'::"char" THEN 'procedure'::text
! WHEN 'w'::"char" THEN 'window'::text
ELSE NULL::text
END AS objtype,
pro.pronamespace AS objnamespace,
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index 96be6e7..fd43f23 100644
*** a/src/test/regress/sql/alter_generic.sql
--- b/src/test/regress/sql/alter_generic.sql
*************** ALTER AGGREGATE alt_agg2(int) SET SCHEMA
*** 81,87 ****
RESET SESSION AUTHORIZATION;
! SELECT n.nspname, proname, prorettype::regtype, proisagg, a.rolname
FROM pg_proc p, pg_namespace n, pg_authid a
WHERE p.pronamespace = n.oid AND p.proowner = a.oid
AND n.nspname IN ('alt_nsp1', 'alt_nsp2')
--- 81,87 ----
RESET SESSION AUTHORIZATION;
! 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')
diff --git a/src/test/regress/sql/create_function_3.sql b/src/test/regress/sql/create_function_3.sql
index fbdf831..8f209d5 100644
*** a/src/test/regress/sql/create_function_3.sql
--- b/src/test/regress/sql/create_function_3.sql
*************** DROP FUNCTION functest_b_1; -- error, n
*** 175,180 ****
--- 175,188 ----
DROP FUNCTION functest_b_2; -- error, ambiguous
+ -- CREATE OR REPLACE tests
+
+ CREATE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1';
+ CREATE OR REPLACE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1';
+ CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1';
+ DROP FUNCTION functest1(a int);
+
+
-- Cleanups
DROP SCHEMA temp_func_test CASCADE;
DROP USER regress_unpriv_user;
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index e8fdf84..a593d37 100644
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.prolang = 0 OR p1.prorettype =
*** 82,87 ****
--- 82,88 ----
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');
*************** SELECT p1.oid, p1.proname
*** 90,99 ****
FROM pg_proc as p1
WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
! -- proiswindow shouldn't be set together with proisagg or proretset
SELECT p1.oid, p1.proname
FROM pg_proc AS p1
! WHERE proiswindow AND (proisagg OR proretset);
-- currently, no built-in functions should be SECURITY DEFINER;
-- this might change in future, but there will probably never be many.
--- 91,100 ----
FROM pg_proc as p1
WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
! -- proretset should only be set for normal functions
SELECT p1.oid, p1.proname
FROM pg_proc AS p1
! 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.
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 140,148 ****
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.prolang != p2.prolang OR
! p1.proisagg != p2.proisagg OR
p1.prosecdef != p2.prosecdef OR
p1.proleakproof != p2.proleakproof OR
p1.proisstrict != p2.proisstrict OR
--- 141,149 ----
WHERE p1.oid < p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! (p1.prokind != 'a' OR p2.prokind != 'a') AND
(p1.prolang != p2.prolang OR
! p1.prokind != p2.prokind OR
p1.prosecdef != p2.prosecdef OR
p1.proleakproof != p2.proleakproof OR
p1.proisstrict != p2.proisstrict OR
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 166,172 ****
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.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.prorettype < p2.prorettype)
--- 167,173 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
p1.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.prorettype < p2.prorettype)
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 177,183 ****
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.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.proargtypes[0] < p2.proargtypes[0])
--- 178,184 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
p1.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.proargtypes[0] < p2.proargtypes[0])
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 188,194 ****
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.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.proargtypes[1] < p2.proargtypes[1])
--- 189,195 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
p1.prosrc NOT LIKE E'range\\_constructor_' AND
p2.prosrc NOT LIKE E'range\\_constructor_' AND
(p1.proargtypes[1] < p2.proargtypes[1])
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 199,205 ****
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.proargtypes[2] < p2.proargtypes[2])
ORDER BY 1, 2;
--- 200,206 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[2] < p2.proargtypes[2])
ORDER BY 1, 2;
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 208,214 ****
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.proargtypes[3] < p2.proargtypes[3])
ORDER BY 1, 2;
--- 209,215 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[3] < p2.proargtypes[3])
ORDER BY 1, 2;
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 217,223 ****
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.proargtypes[4] < p2.proargtypes[4])
ORDER BY 1, 2;
--- 218,224 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[4] < p2.proargtypes[4])
ORDER BY 1, 2;
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 226,232 ****
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.proargtypes[5] < p2.proargtypes[5])
ORDER BY 1, 2;
--- 227,233 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[5] < p2.proargtypes[5])
ORDER BY 1, 2;
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 235,241 ****
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.proargtypes[6] < p2.proargtypes[6])
ORDER BY 1, 2;
--- 236,242 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[6] < p2.proargtypes[6])
ORDER BY 1, 2;
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 244,250 ****
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.proargtypes[7] < p2.proargtypes[7])
ORDER BY 1, 2;
--- 245,251 ----
WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
! p1.prokind != 'a' AND p2.prokind != 'a' AND
(p1.proargtypes[7] < p2.proargtypes[7])
ORDER BY 1, 2;
*************** WHERE aggfnoid = 0 OR aggtransfn = 0 OR
*** 804,816 ****
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);
! -- Make sure there are no proisagg pg_proc entries without matches.
SELECT oid, proname
FROM pg_proc as p
! WHERE p.proisagg AND
NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
-- If there is no finalfn then the output type must be the transtype.
--- 805,817 ----
SELECT a.aggfnoid::oid, p.proname
FROM pg_aggregate as a, pg_proc as p
WHERE a.aggfnoid = p.oid AND
! (p.prokind != 'a' OR p.proretset OR p.pronargs < a.aggnumdirectargs);
! -- Make sure there are no prokind = PROKIND_AGGREGATE pg_proc entries without matches.
SELECT oid, proname
FROM pg_proc as p
! 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.
*************** ORDER BY 1, 2;
*** 1089,1095 ****
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
array_dims(p1.proargtypes) != array_dims(p2.proargtypes)
ORDER BY 1;
--- 1090,1096 ----
SELECT p1.oid::regprocedure, p2.oid::regprocedure
FROM pg_proc AS p1, pg_proc AS p2
WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND
! p1.prokind = 'a' AND p2.prokind = 'a' AND
array_dims(p1.proargtypes) != array_dims(p2.proargtypes)
ORDER BY 1;
*************** ORDER BY 1;
*** 1097,1103 ****
SELECT oid, proname
FROM pg_proc AS p
! WHERE proisagg AND proargdefaults IS NOT NULL;
-- For the same reason, we avoid creating built-in variadic aggregates, except
-- that variadic ordered-set aggregates are OK (since they have special syntax
--- 1098,1104 ----
SELECT oid, proname
FROM pg_proc AS p
! 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
*************** WHERE proisagg AND proargdefaults IS NOT
*** 1105,1111 ****
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';
-- **************** pg_opfamily ****************
--- 1106,1112 ----
SELECT p.oid, proname
FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid
! WHERE prokind = 'a' AND provariadic != 0 AND a.aggkind = 'n';
-- **************** pg_opfamily ****************
#! /usr/bin/perl
# Usage: fix_proc_data.pl <pg_proc.h >new_pg_proc.h
use strict;
use warnings;
while (<>)
{
if (m/^DATA/) {
my @fields = split;
my $proisagg = $fields[13];
my $proiswindow = $fields[14];
my $prokind;
if ($proisagg eq 'f' && $proiswindow eq 'f') {
$prokind = 'f';
} elsif ($proisagg eq 't' && $proiswindow eq 'f') {
$prokind = 'a';
} elsif ($proisagg eq 'f' && $proiswindow eq 't') {
$prokind = 'w';
} else {
die "bad proisagg/proiswindow";
}
s/ $proisagg $proiswindow / $prokind / || die "substitution failed";
}
print;
}
Вложения
В списке pgsql-hackers по дате отправления: