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

Reply via email to