Hi
I miss a reglanguage type from our set of reg* types.
It reduce a mental overhead for queries over pg_proc table
With this type I can easy filter only plpgsql functions
select *
from pg_proc
where prolang = 'plpgsql'::reglanguage
and pronamespace <> 'pg_catalog'::regnamespace;
Regards
Pavel
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index d1d033178f..85bcd43d3d 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -4525,8 +4525,8 @@ INSERT INTO mytable VALUES(-1); -- fails
several alias types for <type>oid</type>: <type>regproc</type>,
<type>regprocedure</type>, <type>regoper</type>, <type>regoperator</type>,
<type>regclass</type>, <type>regtype</type>, <type>regrole</type>,
- <type>regnamespace</type>, <type>regconfig</type>, and
- <type>regdictionary</type>. <xref linkend="datatype-oid-table"/> shows an
+ <type>regnamespace</type>, <type>regconfig</type>, <type>reglanguage</type>
+ and <type>regdictionary</type>. <xref linkend="datatype-oid-table"/> shows an
overview.
</para>
@@ -4660,6 +4660,14 @@ SELECT * FROM pg_attribute
<entry>text search dictionary</entry>
<entry><literal>simple</literal></entry>
</row>
+
+ <row>
+ <entry><type>reglanguage</type></entry>
+ <entry><structname>pg_language</structname></entry>
+ <entry>language name</entry>
+ <entry><literal>plpgsql</literal></entry>
+ </row>
+
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 28035f1635..2bb1b2fd8e 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -18413,6 +18413,11 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<entry><type>regrole</type></entry>
<entry>get the OID of the named role</entry>
</row>
+ <row>
+ <entry><literal><function>to_reglanguage(<parameter>language_name</parameter>)</function></literal></entry>
+ <entry><type>regrole</type></entry>
+ <entry>get the OID of the named language</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -18717,7 +18722,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
names (given as <type>text</type>) to objects of
type <type>regclass</type>, <type>regproc</type>, <type>regprocedure</type>,
<type>regoper</type>, <type>regoperator</type>, <type>regtype</type>,
- <type>regnamespace</type>, and <type>regrole</type>
+ <type>regnamespace</type>, <type>regrole</type> and <type>reglanguage</type>
respectively. These functions differ from a cast from
text in that they don't accept a numeric OID, and that they return null
rather than throwing an error if the name is not found (or, for
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index f0fa52bc27..da412ef01b 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -29,6 +29,7 @@
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_dict.h"
#include "catalog/pg_type.h"
+#include "commands/proclang.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "parser/parse_type.h"
@@ -1717,6 +1718,118 @@ stringToQualifiedNameList(const char *string)
return result;
}
+/*
+ * reglanguagein - converts "language" to type OID
+ *
+ * We also accept a numeric OID, for symmetry with the output routine,
+ * and for possible use in bootstrap mode.
+ *
+ * '-' signifies unknown (OID 0). In all other cases, the input must
+ * match an existing pg_type entry.
+ */
+Datum
+reglanguagein(PG_FUNCTION_ARGS)
+{
+ char *language_name_or_oid = PG_GETARG_CSTRING(0);
+ Oid result = InvalidOid;
+
+ /* '-' ? */
+ if (strcmp(language_name_or_oid, "-") == 0)
+ PG_RETURN_OID(InvalidOid);
+
+ /* Numeric OID? */
+ if (language_name_or_oid[0] >= '0' &&
+ language_name_or_oid[0] <= '9' &&
+ strspn(language_name_or_oid, "0123456789") == strlen(language_name_or_oid))
+ {
+ result = DatumGetObjectId(DirectFunctionCall1(oidin,
+ CStringGetDatum(language_name_or_oid)));
+ PG_RETURN_OID(result);
+ }
+
+ /* Else it's a type name, possibly schema-qualified or decorated */
+
+ /* The rest of this wouldn't work in bootstrap mode */
+ if (IsBootstrapProcessingMode())
+ elog(ERROR, "reglanguage values must be OIDs in bootstrap mode");
+
+ result = get_language_oid(language_name_or_oid, false);
+
+ PG_RETURN_OID(result);
+}
+
+/*
+ * to_reglanguage - converts "language nane" to type OID
+ *
+ * If the name is not found, we return NULL.
+ */
+Datum
+to_reglanguage(PG_FUNCTION_ARGS)
+{
+ char *language_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
+ Oid result;
+
+ result = get_language_oid(language_name, true);
+
+ if (OidIsValid(result))
+ PG_RETURN_OID(result);
+ else
+ PG_RETURN_NULL();
+}
+
+/*
+ * reglanguageout - converts language OID to "language_name"
+ */
+Datum
+reglanguageout(PG_FUNCTION_ARGS)
+{
+ Oid langid = PG_GETARG_OID(0);
+ char *result;
+
+ if (langid == InvalidOid)
+ {
+ result = pstrdup("-");
+ PG_RETURN_CSTRING(result);
+ }
+
+ result = get_language_name(langid, true);
+
+ if (result)
+ {
+ /* pstrdup is not really necessary, but it avoids a compiler warning */
+ result = pstrdup(quote_identifier(result));
+ }
+ else
+ {
+ /* If OID doesn't match any namespace, return it numerically */
+ result = (char *) palloc(NAMEDATALEN);
+ snprintf(result, NAMEDATALEN, "%u", langid);
+ }
+
+ PG_RETURN_CSTRING(result);
+}
+
+/*
+ * reglanguagerecv - converts external binary format to reglanguage
+ */
+Datum
+reglanguagerecv(PG_FUNCTION_ARGS)
+{
+ /* Exactly the same as oidrecv, so share code */
+ return oidrecv(fcinfo);
+}
+
+/*
+ * reglanguagesend - converts reglanguage to binary format
+ */
+Datum
+reglanguagesend(PG_FUNCTION_ARGS)
+{
+ /* Exactly the same as oidsend, so share code */
+ return oidsend(fcinfo);
+}
+
+
/*****************************************************************************
* SUPPORT ROUTINES *
*****************************************************************************/
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 0be26fe037..934bc5215a 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3760,6 +3760,7 @@ convert_to_scalar(Datum value, Oid valuetypid, Oid collid, double *scaledvalue,
case REGDICTIONARYOID:
case REGROLEOID:
case REGNAMESPACEOID:
+ case REGLANGUAGEOID:
*scaledvalue = convert_numeric_to_scalar(value, valuetypid,
&failure);
*scaledlobound = convert_numeric_to_scalar(lobound, boundstypid,
@@ -3891,6 +3892,7 @@ convert_numeric_to_scalar(Datum value, Oid typid, bool *failure)
case REGDICTIONARYOID:
case REGROLEOID:
case REGNAMESPACEOID:
+ case REGLANGUAGEOID:
/* we can treat OIDs as integers... */
return (double) DatumGetObjectId(value);
}
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 5f9a102a74..0fa52b33a7 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -1034,9 +1034,11 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
" 'regoper', "
" 'regoperator', "
" 'regproc', "
- " 'regprocedure' "
+ " 'regprocedure', "
+ " 'reglanguage' "
/* regrole.oid is preserved, so 'regrole' is OK */
/* regtype.oid is preserved, so 'regtype' is OK */
+ /* reglanguage.oid is preserved, so 'reglanguage' is OK */
" ) AND "
" c.relnamespace = n.oid AND "
" n.nspname NOT IN ('pg_catalog', 'information_schema')");
diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat
index 6ef8b8a4e7..ef75611587 100644
--- a/src/include/catalog/pg_cast.dat
+++ b/src/include/catalog/pg_cast.dat
@@ -263,6 +263,20 @@
castcontext => 'a', castmethod => 'f' },
{ castsource => 'regnamespace', casttarget => 'int4', castfunc => '0',
castcontext => 'a', castmethod => 'b' },
+{ castsource => 'oid', casttarget => 'reglanguage', castfunc => '0',
+ castcontext => 'i', castmethod => 'b' },
+{ castsource => 'reglanguage', casttarget => 'oid', castfunc => '0',
+ castcontext => 'i', castmethod => 'b' },
+{ castsource => 'int8', casttarget => 'reglanguage', castfunc => 'oid',
+ castcontext => 'i', castmethod => 'f' },
+{ castsource => 'int2', casttarget => 'reglanguage', castfunc => 'int4(int2)',
+ castcontext => 'i', castmethod => 'f' },
+{ castsource => 'int4', casttarget => 'reglanguage', castfunc => '0',
+ castcontext => 'i', castmethod => 'b' },
+{ castsource => 'reglanguage', casttarget => 'int8', castfunc => 'int8(oid)',
+ castcontext => 'a', castmethod => 'f' },
+{ castsource => 'reglanguage', casttarget => 'int4', castfunc => '0',
+ castcontext => 'a', castmethod => 'b' },
# String category
{ castsource => 'text', casttarget => 'bpchar', castfunc => '0',
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 07a86c7b7b..1cba01c3c9 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6700,6 +6700,17 @@
prorettype => 'regnamespace', proargtypes => 'text',
prosrc => 'to_regnamespace' },
+{ oid => '4191', descr => 'I/O',
+ proname => 'reglanguagein', provolatile => 's', prorettype => 'reglanguage',
+ proargtypes => 'cstring', prosrc => 'reglanguagein' },
+{ oid => '4192', descr => 'I/O',
+ proname => 'reglanguageout', provolatile => 's', prorettype => 'cstring',
+ proargtypes => 'reglanguage', prosrc => 'reglanguageout' },
+{ oid => '4193', descr => 'convert language name to reglanguage',
+ proname => 'to_reglanguage', provolatile => 's',
+ prorettype => 'reglanguage', proargtypes => 'text',
+ prosrc => 'to_reglanguage' },
+
{ oid => '1268',
descr => 'parse qualified identifier to array of identifiers',
proname => 'parse_ident', prorettype => '_text', proargtypes => 'text bool',
@@ -7471,6 +7482,12 @@
{ oid => '4088', descr => 'I/O',
proname => 'regnamespacesend', prorettype => 'bytea',
proargtypes => 'regnamespace', prosrc => 'regnamespacesend' },
+{ oid => '4194', descr => 'I/O',
+ proname => 'reglanguagerecv', prorettype => 'reglanguage',
+ proargtypes => 'internal', prosrc => 'reglanguagerecv' },
+{ oid => '4195', descr => 'I/O',
+ proname => 'reglanguagesend', prorettype => 'bytea',
+ proargtypes => 'reglanguage', prosrc => 'reglanguagesend' },
{ oid => '2456', descr => 'I/O',
proname => 'bit_recv', prorettype => 'bit',
proargtypes => 'internal oid int4', prosrc => 'bit_recv' },
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index 4cf2b9df7b..5502c7a622 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -392,6 +392,11 @@
typinput => 'regnamespacein', typoutput => 'regnamespaceout',
typreceive => 'regnamespacerecv', typsend => 'regnamespacesend',
typalign => 'i' },
+{ oid => '4179', array_type_oid => '4180', descr => 'registered language',
+ typname => 'reglanguage', typlen => '4', typbyval => 't', typcategory => 'N',
+ typinput => 'reglanguagein', typoutput => 'reglanguageout',
+ typreceive => 'reglanguagerecv', typsend => 'reglanguagesend',
+ typalign => 'i' },
# uuid
{ oid => '2950', array_type_oid => '2951', descr => 'UUID datatype',
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index ee4fcda866..198716bc8e 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -40,6 +40,12 @@ SELECT regtype('int4');
integer
(1 row)
+SELECT reglanguage('plpgsql');
+ reglanguage
+-------------
+ plpgsql
+(1 row)
+
SELECT to_regoper('||/');
to_regoper
------------
@@ -76,6 +82,12 @@ SELECT to_regtype('int4');
integer
(1 row)
+SELECT to_reglanguage('plpgsql');
+ to_reglanguage
+----------------
+ plpgsql
+(1 row)
+
-- with schemaname
SELECT regoper('pg_catalog.||/');
regoper
@@ -219,6 +231,10 @@ SELECT regtype('int3');
ERROR: type "int3" does not exist
LINE 1: SELECT regtype('int3');
^
+SELECT reglanguage('plpgsq');
+ERROR: language "plpgsq" does not exist
+LINE 1: SELECT reglanguage('plpgsq');
+ ^
-- with schemaname
SELECT regoper('ng_catalog.||/');
ERROR: schema "ng_catalog" does not exist
@@ -277,6 +293,10 @@ SELECT regnamespace('foo.bar');
ERROR: invalid name syntax
LINE 1: SELECT regnamespace('foo.bar');
^
+SELECT reglanguage('xxx.plpgsq');
+ERROR: language "xxx.plpgsq" does not exist
+LINE 1: SELECT reglanguage('xxx.plpgsq');
+ ^
/* If objects don't exist, return NULL with no error. */
-- without schemaname
SELECT to_regoper('||//');
@@ -315,6 +335,12 @@ SELECT to_regtype('int3');
(1 row)
+SELECT to_reglanguage('plpgsq');
+ to_reglanguage
+----------------
+
+(1 row)
+
-- with schemaname
SELECT to_regoper('ng_catalog.||/');
to_regoper
@@ -395,3 +421,9 @@ SELECT to_regnamespace('"Nonexistent"');
SELECT to_regnamespace('foo.bar');
ERROR: invalid name syntax
+SELECT to_reglanguage('xxx.plpgsq');
+ to_reglanguage
+----------------
+
+(1 row)
+
diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql
index a60bc28901..13daaa5fc1 100644
--- a/src/test/regress/sql/regproc.sql
+++ b/src/test/regress/sql/regproc.sql
@@ -14,6 +14,7 @@ SELECT regproc('now');
SELECT regprocedure('abs(numeric)');
SELECT regclass('pg_class');
SELECT regtype('int4');
+SELECT reglanguage('plpgsql');
SELECT to_regoper('||/');
SELECT to_regoperator('+(int4,int4)');
@@ -21,6 +22,7 @@ SELECT to_regproc('now');
SELECT to_regprocedure('abs(numeric)');
SELECT to_regclass('pg_class');
SELECT to_regtype('int4');
+SELECT to_reglanguage('plpgsql');
-- with schemaname
@@ -61,6 +63,7 @@ SELECT regproc('know');
SELECT regprocedure('absinthe(numeric)');
SELECT regclass('pg_classes');
SELECT regtype('int3');
+SELECT reglanguage('plpgsq');
-- with schemaname
@@ -81,6 +84,7 @@ SELECT regrole('foo.bar');
SELECT regnamespace('Nonexistent');
SELECT regnamespace('"Nonexistent"');
SELECT regnamespace('foo.bar');
+SELECT reglanguage('xxx.plpgsq');
/* If objects don't exist, return NULL with no error. */
@@ -92,6 +96,7 @@ SELECT to_regproc('know');
SELECT to_regprocedure('absinthe(numeric)');
SELECT to_regclass('pg_classes');
SELECT to_regtype('int3');
+SELECT to_reglanguage('plpgsq');
-- with schemaname
@@ -113,3 +118,4 @@ SELECT to_regrole('foo.bar');
SELECT to_regnamespace('Nonexistent');
SELECT to_regnamespace('"Nonexistent"');
SELECT to_regnamespace('foo.bar');
+SELECT to_reglanguage('xxx.plpgsq');