diff --git a/src/pl/plpython/expected/plpython_function.out b/src/pl/plpython/expected/plpython_function.out
index e1ffa7302dbd3f5abc7efd66800a8a1d6d2f34b9..4ace0445d9abacc91d4b61b607cc045c696afb26 100644
--- a/src/pl/plpython/expected/plpython_function.out
+++ b/src/pl/plpython/expected/plpython_function.out
@@ -436,3 +436,14 @@ elif typ == 'obj':
 	type_record.second = second
 	return type_record
 $$ LANGUAGE plpythonu;
+CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
+return first + '_in_to_out';
+$$ LANGUAGE plpythonu;
+-- this doesn't work yet :-(
+CREATE FUNCTION test_in_out_params_multi(first in text,
+                                         second out text, third out text) AS $$
+return first + '_record_in_to_out';
+$$ LANGUAGE plpythonu;
+CREATE FUNCTION test_inout_params(first inout text) AS $$
+return first + '_inout';
+$$ LANGUAGE plpythonu;
diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
index 170abe7ab6e68250df134238e1a61ea85af5752b..ddd565bbff5fda0d56a630d0a26d3a4e47d317b1 100644
--- a/src/pl/plpython/expected/plpython_test.out
+++ b/src/pl/plpython/expected/plpython_test.out
@@ -539,3 +539,18 @@ SELECT * FROM test_type_record_as('obj', null, null, true);
        |       
 (1 row)
 
+SELECT * FROM test_in_out_params('test_in');
+      second       
+-------------------
+ test_in_in_to_out
+(1 row)
+
+-- this doesn't work yet :-(
+SELECT * FROM test_in_out_params_multi('test_in');
+ERROR:  plpython functions cannot return type record
+SELECT * FROM test_inout_params('test_in');
+     first     
+---------------
+ test_in_inout
+(1 row)
+
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index 130eca4f71de0e4e1af1244f5c2e4dac256a464a..9fbfe563ee91b4119565abe7a3e7a253a6a422a7 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plpython.c - python as a procedural language for PostgreSQL
  *
- *	$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.108 2008/03/28 00:21:56 tgl Exp $
+ *	$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.109 2008/05/03 02:47:47 tgl Exp $
  *
  *********************************************************************
  */
@@ -1161,9 +1161,6 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
 	bool		isnull;
 	int			i,
 				rv;
-	Datum		argnames;
-	Datum	   *elems;
-	int			nelems;
 
 	procStruct = (Form_pg_proc) GETSTRUCT(procTup);
 
@@ -1249,58 +1246,83 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
 		}
 
 		/*
-		 * now get information required for input conversion of the
-		 * procedure's arguments.
+		 * Now get information required for input conversion of the
+		 * procedure's arguments.  Note that we ignore output arguments
+		 * here --- since we don't support returning record, and that was
+		 * already checked above, there's no need to worry about multiple
+		 * output arguments.
 		 */
-		proc->nargs = procStruct->pronargs;
-		if (proc->nargs)
+		if (procStruct->pronargs)
 		{
-			argnames = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_proargnames, &isnull);
-			if (!isnull)
+			Oid		*types;
+			char   **names,
+					*modes;
+			int		 i,
+					 pos,
+					 total;
+
+			/* extract argument type info from the pg_proc tuple */
+			total = get_func_arg_info(procTup, &types, &names, &modes);
+
+			/* count number of in+inout args into proc->nargs */
+			if (modes == NULL)
+				proc->nargs = total;
+			else
 			{
-				/* XXX this code is WRONG if there are any output arguments */
-				deconstruct_array(DatumGetArrayTypeP(argnames), TEXTOID, -1, false, 'i',
-								  &elems, NULL, &nelems);
-				if (nelems != proc->nargs)
-					elog(ERROR,
-						 "proargnames must have the same number of elements "
-						 "as the function has arguments");
-				proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs);
-				memset(proc->argnames, 0, sizeof(char *) * proc->nargs);
+				/* proc->nargs was initialized to 0 above */
+				for (i = 0; i < total; i++)
+				{
+					if (modes[i] != 'o')
+						(proc->nargs)++;
+				}
 			}
-		}
-		for (i = 0; i < proc->nargs; i++)
-		{
-			HeapTuple	argTypeTup;
-			Form_pg_type argTypeStruct;
 
-			argTypeTup = SearchSysCache(TYPEOID,
-						 ObjectIdGetDatum(procStruct->proargtypes.values[i]),
-										0, 0, 0);
-			if (!HeapTupleIsValid(argTypeTup))
-				elog(ERROR, "cache lookup failed for type %u",
-					 procStruct->proargtypes.values[i]);
-			argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
+			proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs);
+			for (i = pos = 0; i < total; i++)
+			{
+				HeapTuple	argTypeTup;
+				Form_pg_type argTypeStruct;
 
-			/* Disallow pseudotype argument */
-			if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("plpython functions cannot take type %s",
-						format_type_be(procStruct->proargtypes.values[i]))));
-
-			if (argTypeStruct->typtype != TYPTYPE_COMPOSITE)
-				PLy_input_datum_func(&(proc->args[i]),
-									 procStruct->proargtypes.values[i],
-									 argTypeTup);
-			else
-				proc->args[i].is_rowtype = 2;	/* still need to set I/O funcs */
+				if (modes && modes[i] == 'o')	/* skip OUT arguments */
+					continue;
+
+				Assert(types[i] == procStruct->proargtypes.values[pos]);
+
+				argTypeTup = SearchSysCache(TYPEOID,
+											ObjectIdGetDatum(types[i]),
+											0, 0, 0);
+				if (!HeapTupleIsValid(argTypeTup))
+					elog(ERROR, "cache lookup failed for type %u", types[i]);
+				argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
+
+				/* check argument type is OK, set up I/O function info */
+				switch (argTypeStruct->typtype)
+				{
+					case TYPTYPE_PSEUDO:
+						/* Disallow pseudotype argument */
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("plpython functions cannot take type %s",
+								 format_type_be(types[i]))));
+						break;
+					case TYPTYPE_COMPOSITE:
+						/* we'll set IO funcs at first call */
+						proc->args[pos].is_rowtype = 2;
+						break;
+					default:
+						PLy_input_datum_func(&(proc->args[pos]),
+											 types[i],
+											 argTypeTup);
+						break;
+				}
 
-			ReleaseSysCache(argTypeTup);
+				/* get argument name */
+				proc->argnames[pos] = names ? PLy_strdup(names[i]) : NULL;
 
-			/* Fetch argument name */
-			if (proc->argnames)
-				proc->argnames[i] = PLy_strdup(TextDatumGetCString(elems[i]));
+				ReleaseSysCache(argTypeTup);
+
+				pos++;
+			}
 		}
 
 		/*
diff --git a/src/pl/plpython/sql/plpython_function.sql b/src/pl/plpython/sql/plpython_function.sql
index 224d5196a3c236782f695d6bc061c503516da511..cf01e8e0cdc81b2f991614f2dbb50b3c1127a572 100644
--- a/src/pl/plpython/sql/plpython_function.sql
+++ b/src/pl/plpython/sql/plpython_function.sql
@@ -480,3 +480,16 @@ elif typ == 'obj':
 	return type_record
 $$ LANGUAGE plpythonu;
 
+CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
+return first + '_in_to_out';
+$$ LANGUAGE plpythonu;
+
+-- this doesn't work yet :-(
+CREATE FUNCTION test_in_out_params_multi(first in text,
+                                         second out text, third out text) AS $$
+return first + '_record_in_to_out';
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION test_inout_params(first inout text) AS $$
+return first + '_inout';
+$$ LANGUAGE plpythonu;
diff --git a/src/pl/plpython/sql/plpython_test.sql b/src/pl/plpython/sql/plpython_test.sql
index dafcae089e92c5b36eb5aaba15e9dd25b45fc422..f7321ab9e006cb7ea31395bd636d175fe3e8d987 100644
--- a/src/pl/plpython/sql/plpython_test.sql
+++ b/src/pl/plpython/sql/plpython_test.sql
@@ -143,3 +143,8 @@ SELECT * FROM test_type_record_as('obj', 'one', null, false);
 SELECT * FROM test_type_record_as('obj', null, 2, false);
 SELECT * FROM test_type_record_as('obj', 'three', 3, false);
 SELECT * FROM test_type_record_as('obj', null, null, true);
+
+SELECT * FROM test_in_out_params('test_in');
+-- this doesn't work yet :-(
+SELECT * FROM test_in_out_params_multi('test_in');
+SELECT * FROM test_inout_params('test_in');