diff --git a/contrib/tsearch2/gendict/sql.IN b/contrib/tsearch2/gendict/sql.IN
index ff0d8423999f4810d69816baa9225daee7345fb2..044230b4173f8689953450454512cee85d3a251d 100644
--- a/contrib/tsearch2/gendict/sql.IN
+++ b/contrib/tsearch2/gendict/sql.IN
@@ -1,7 +1,7 @@
 SET search_path = public;
 BEGIN;
 
-HASINIT create function dinit_CFG_MODNAME(text)
+HASINIT create function dinit_CFG_MODNAME(internal)
 HASINIT         returns internal
 HASINIT         as 'MODULE_PATHNAME'
 HASINIT         language 'C';
diff --git a/contrib/tsearch2/tsearch.sql.in b/contrib/tsearch2/tsearch.sql.in
index 35f96cd5cdb625243c3172c018772bf4b3538f3e..b51b049b9a865457311926431f3ff316ceef507f 100644
--- a/contrib/tsearch2/tsearch.sql.in
+++ b/contrib/tsearch2/tsearch.sql.in
@@ -44,7 +44,7 @@ CREATE FUNCTION set_curdict(text)
 	with (isstrict);
 
 --built-in dictionaries
-CREATE FUNCTION dex_init(text)
+CREATE FUNCTION dex_init(internal)
 	returns internal
 	as 'MODULE_PATHNAME' 
 	language 'C';
@@ -57,13 +57,13 @@ CREATE FUNCTION dex_lexize(internal,internal,int4)
 
 insert into pg_ts_dict select 
 	'simple', 
-	'dex_init(text)',
+	'dex_init(internal)',
 	null,
 	'dex_lexize(internal,internal,int4)',
 	'Simple example of dictionary.'
 ;
 	 
-CREATE FUNCTION snb_en_init(text)
+CREATE FUNCTION snb_en_init(internal)
 	returns internal
 	as 'MODULE_PATHNAME' 
 	language 'C';
@@ -76,26 +76,26 @@ CREATE FUNCTION snb_lexize(internal,internal,int4)
 
 insert into pg_ts_dict select 
 	'en_stem', 
-	'snb_en_init(text)',
+	'snb_en_init(internal)',
 	'contrib/english.stop',
 	'snb_lexize(internal,internal,int4)',
 	'English Stemmer. Snowball.'
 ;
 
-CREATE FUNCTION snb_ru_init(text)
+CREATE FUNCTION snb_ru_init(internal)
 	returns internal
 	as 'MODULE_PATHNAME' 
 	language 'C';
 
 insert into pg_ts_dict select 
 	'ru_stem', 
-	'snb_ru_init(text)',
+	'snb_ru_init(internal)',
 	'contrib/russian.stop',
 	'snb_lexize(internal,internal,int4)',
 	'Russian Stemmer. Snowball.'
 ;
 	 
-CREATE FUNCTION spell_init(text)
+CREATE FUNCTION spell_init(internal)
 	returns internal
 	as 'MODULE_PATHNAME' 
 	language 'C';
@@ -108,13 +108,13 @@ CREATE FUNCTION spell_lexize(internal,internal,int4)
 
 insert into pg_ts_dict select 
 	'ispell_template', 
-	'spell_init(text)',
+	'spell_init(internal)',
 	null,
 	'spell_lexize(internal,internal,int4)',
 	'ISpell interface. Must have .dict and .aff files'
 ;
 
-CREATE FUNCTION syn_init(text)
+CREATE FUNCTION syn_init(internal)
 	returns internal
 	as 'MODULE_PATHNAME' 
 	language 'C';
@@ -127,7 +127,7 @@ CREATE FUNCTION syn_lexize(internal,internal,int4)
 
 insert into pg_ts_dict select 
 	'synonym', 
-	'syn_init(text)',
+	'syn_init(internal)',
 	null,
 	'syn_lexize(internal,internal,int4)',
 	'Example of synonym dictionary'
diff --git a/contrib/tsearch2/untsearch.sql.in b/contrib/tsearch2/untsearch.sql.in
index b1883d5fbdf083ced54b93bab60659d7c0b95890..2a658dfd933caac5e5d74f0329918c9db8d7fea1 100644
--- a/contrib/tsearch2/untsearch.sql.in
+++ b/contrib/tsearch2/untsearch.sql.in
@@ -34,14 +34,14 @@ DROP FUNCTION lexize(text, text);
 DROP FUNCTION lexize(text);
 DROP FUNCTION set_curdict(int);
 DROP FUNCTION set_curdict(text);
-DROP FUNCTION dex_init(text);
+DROP FUNCTION dex_init(internal);
 DROP FUNCTION dex_lexize(internal,internal,int4);
-DROP FUNCTION snb_en_init(text);
+DROP FUNCTION snb_en_init(internal);
 DROP FUNCTION snb_lexize(internal,internal,int4);
-DROP FUNCTION snb_ru_init(text);
-DROP FUNCTION spell_init(text);
+DROP FUNCTION snb_ru_init(internal);
+DROP FUNCTION spell_init(internal);
 DROP FUNCTION spell_lexize(internal,internal,int4);
-DROP FUNCTION syn_init(text);
+DROP FUNCTION syn_init(internal);
 DROP FUNCTION syn_lexize(internal,internal,int4);
 DROP FUNCTION set_curprs(int);
 DROP FUNCTION set_curprs(text);
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 1f8b3388db21f8f3fdf47a7aeccd08d0bcb41f69..12f6c64634f0e874a00e3d17f34939c99e146a6e 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.128 2005/04/14 20:03:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.129 2005/05/03 16:51:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -81,6 +81,9 @@ ProcedureCreate(const char *procedureName,
 	int			allParamCount;
 	Oid		   *allParams;
 	bool		genericInParam = false;
+	bool		genericOutParam = false;
+	bool		internalInParam = false;
+	bool		internalOutParam = false;
 	Relation	rel;
 	HeapTuple	tup;
 	HeapTuple	oldtup;
@@ -133,43 +136,59 @@ ProcedureCreate(const char *procedureName,
 
 	/*
 	 * Do not allow return type ANYARRAY or ANYELEMENT unless at least one
-	 * input argument is also ANYARRAY or ANYELEMENT
+	 * input argument is ANYARRAY or ANYELEMENT.  Also, do not allow
+	 * return type INTERNAL unless at least one input argument is INTERNAL.
 	 */
 	for (i = 0; i < parameterCount; i++)
 	{
-		if (parameterTypes->values[i] == ANYARRAYOID ||
-			parameterTypes->values[i] == ANYELEMENTOID)
+		switch (parameterTypes->values[i])
 		{
-			genericInParam = true;
-			break;
+			case ANYARRAYOID:
+			case ANYELEMENTOID:
+				genericInParam = true;
+				break;
+			case INTERNALOID:
+				internalInParam = true;
+				break;
 		}
 	}
 
-	if (!genericInParam)
+	if (allParameterTypes != PointerGetDatum(NULL))
 	{
-		bool	genericOutParam = false;
-
-		if (allParameterTypes != PointerGetDatum(NULL))
+		for (i = 0; i < allParamCount; i++)
 		{
-			for (i = 0; i < allParamCount; i++)
+			/*
+			 * We don't bother to distinguish input and output params here,
+			 * so if there is, say, just an input INTERNAL param then we will
+			 * still set internalOutParam.  This is OK since we don't really
+			 * care.
+			 */
+			switch (allParams[i])
 			{
-				if (allParams[i] == ANYARRAYOID ||
-					allParams[i] == ANYELEMENTOID)
-				{
+				case ANYARRAYOID:
+				case ANYELEMENTOID:
 					genericOutParam = true;
 					break;
-				}
+				case INTERNALOID:
+					internalOutParam = true;
+					break;
 			}
 		}
-
-		if (returnType == ANYARRAYOID || returnType == ANYELEMENTOID ||
-			genericOutParam)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-					 errmsg("cannot determine result data type"),
-					 errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
 	}
 
+	if ((returnType == ANYARRAYOID || returnType == ANYELEMENTOID ||
+		 genericOutParam) && !genericInParam)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+				 errmsg("cannot determine result data type"),
+				 errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
+
+	if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+				 errmsg("unsafe use of INTERNAL pseudo-type"),
+				 errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
+
 	/*
 	 * don't allow functions of complex types that have the same name as
 	 * existing attributes of the type