--- plperl.c.orig	Fri Apr 27 18:22:56 2007
+++ plperl.c	Fri Apr 27 18:23:12 2007
@@ -52,6 +52,7 @@
 	Oid			result_typioparam;
 	int			nargs;
 	FmgrInfo	arg_out_func[FUNC_MAX_ARGS];
+	Oid		arg_out_oid[FUNC_MAX_ARGS];
 	bool		arg_is_rowtype[FUNC_MAX_ARGS];
 	SV		   *reference;
 } plperl_proc_desc;
@@ -141,6 +142,7 @@
 
 static Datum plperl_trigger_handler(PG_FUNCTION_ARGS);
 static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger);
+static Datum plperl_convert_sv_to_datum(Oid rtypeid, FmgrInfo *in_func, Oid typioparam, SV *sv);
 
 static SV  *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc);
 static void plperl_init_shared_libs(pTHX);
@@ -524,7 +526,31 @@
 	return res;
 }
 
+/* Build a Datum form an SV handling the case of bytea */
 
+static Datum
+plperl_convert_sv_to_datum(Oid rtypeid, FmgrInfo *in_func, Oid typioparam, SV *sv)
+{
+	char *val;
+	STRLEN len;
+	Datum retval;
+
+	val = SvPV(sv, len);
+	if(rtypeid == BYTEAOID)
+	{
+		StringInfoData buf;
+		initStringInfo(&buf);
+		appendBinaryStringInfo(&buf, val, len);
+		retval = ReceiveFunctionCall(in_func, &buf,
+							   typioparam, -1);
+	}
+	else {
+		retval = InputFunctionCall(in_func, val,
+							   typioparam, -1);
+	}
+	return retval;
+}
+
 /* Build a tuple from a hash. */
 
 static HeapTuple
@@ -730,7 +756,6 @@
 	while ((val = hv_iternextsv(hvNew, &key, &klen)))
 	{
 		int			attn = SPI_fnumber(tupdesc, key);
-		Oid			typinput;
 		Oid			typioparam;
 		int32		atttypmod;
 		FmgrInfo	finfo;
@@ -741,16 +766,43 @@
 					 errmsg("Perl hash contains nonexistent column \"%s\"",
 							key)));
 		/* XXX would be better to cache these lookups */
-		getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid,
-						 &typinput, &typioparam);
-		fmgr_info(typinput, &finfo);
+		if(tupdesc->attrs[attn - 1]->atttypid == BYTEAOID)
+		{
+			Oid	typreceive;
+			getTypeBinaryInputInfo(tupdesc->attrs[attn - 1]->atttypid,
+							 &typreceive, &typioparam);
+			fmgr_info(typreceive, &finfo);
+		}
+		else
+		{
+			Oid	typinput;
+			getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid,
+							 &typinput, &typioparam);
+			fmgr_info(typinput, &finfo);
+		}
 		atttypmod = tupdesc->attrs[attn - 1]->atttypmod;
 		if (SvOK(val) && SvTYPE(val) != SVt_NULL)
 		{
-			modvalues[slotsused] = InputFunctionCall(&finfo,
-													 SvPV(val, PL_na),
+			STRLEN len;
+			char *str;
+			str = SvPV(val, len);
+			if(tupdesc->attrs[attn - 1]->atttypid == BYTEAOID)
+			{
+				StringInfoData buf;
+				initStringInfo(&buf);
+				appendBinaryStringInfo(&buf, str, len);
+				modvalues[slotsused] = ReceiveFunctionCall(&finfo,
+													 &buf,
 													 typioparam,
 													 atttypmod);
+			}
+			else
+			{
+				modvalues[slotsused] = InputFunctionCall(&finfo,
+													 str,
+													 typioparam,
+													 atttypmod);
+			}
 			modnulls[slotsused] = ' ';
 		}
 		else
@@ -1040,13 +1092,24 @@
 		}
 		else
 		{
-			char	   *tmp;
-
-			tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
-									 fcinfo->arg[i]);
-			sv = newSVstring(tmp);
-			XPUSHs(sv_2mortal(sv));
-			pfree(tmp);
+			if(desc->arg_out_oid[i] == BYTEAOID)
+			{
+				bytea	*tmpbytes;
+				tmpbytes = SendFunctionCall(&(desc->arg_out_func[i]),
+									 	fcinfo->arg[i]);
+				sv = newSVpvn(VARDATA(tmpbytes), VARSIZE(tmpbytes) - VARHDRSZ);
+				XPUSHs(sv_2mortal(sv));
+				pfree(tmpbytes);
+			}
+			else
+			{
+				char	   *tmp;
+				tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
+									 	fcinfo->arg[i]);
+				sv = newSVstring(tmp);
+				XPUSHs(sv_2mortal(sv));
+				pfree(tmp);
+			}
 		}
 	}
 	PUTBACK;
@@ -1271,7 +1334,7 @@
 	else
 	{
 		/* Return a perl string converted to a Datum */
-		char	   *val;
+		char		*val;
 
 		if (prodesc->fn_retisarray && SvROK(perlret) &&
 			SvTYPE(SvRV(perlret)) == SVt_PVAV)
@@ -1281,10 +1344,8 @@
 			perlret = array_ret;
 		}
 
-		val = SvPV(perlret, PL_na);
-
-		retval = InputFunctionCall(&prodesc->result_in_func, val,
-								   prodesc->result_typioparam, -1);
+		retval = plperl_convert_sv_to_datum(prodesc->result_oid, &prodesc->result_in_func,
+							prodesc->result_typioparam, perlret);
 	}
 
 	if (array_ret == NULL)
@@ -1560,7 +1621,14 @@
 			prodesc->fn_retisarray =
 				(typeStruct->typlen == -1 && typeStruct->typelem);
 
-			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
+			if(procStruct->prorettype == BYTEAOID)
+			{
+				perm_fmgr_info(typeStruct->typreceive, &(prodesc->result_in_func));
+			}
+			else
+			{
+				perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
+			}
 			prodesc->result_typioparam = getTypeIOParam(typeTup);
 
 			ReleaseSysCache(typeTup);
@@ -1598,13 +1666,24 @@
 						format_type_be(procStruct->proargtypes.values[i]))));
 				}
 
+				/* Learn the types for later (needed for binary vs. string) */
+				prodesc->arg_out_oid[i] = procStruct->proargtypes.values[i];
+
 				if (typeStruct->typtype == 'c')
 					prodesc->arg_is_rowtype[i] = true;
 				else
 				{
 					prodesc->arg_is_rowtype[i] = false;
-					perm_fmgr_info(typeStruct->typoutput,
-								   &(prodesc->arg_out_func[i]));
+					if(prodesc->arg_out_oid[i] == BYTEAOID)
+					{
+						perm_fmgr_info(typeStruct->typsend,
+								   	&(prodesc->arg_out_func[i]));
+					}
+					else
+					{
+						perm_fmgr_info(typeStruct->typoutput,
+								   	&(prodesc->arg_out_func[i]));
+					}
 				}
 
 				ReleaseSysCache(typeTup);
@@ -1668,8 +1747,6 @@
 		Datum		attr;
 		bool		isnull;
 		char	   *attname;
-		char	   *outputstr;
-		Oid			typoutput;
 		bool		typisvarlena;
 
 		if (tupdesc->attrs[i]->attisdropped)
@@ -1685,15 +1762,30 @@
 			continue;
 		}
 
-		/* XXX should have a way to cache these lookups */
-		getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
-						  &typoutput, &typisvarlena);
+		if(tupdesc->attrs[i]->atttypid == BYTEAOID)
+		{
+			bytea		*outputbytes;
+			Oid		typsend;
+			getTypeBinaryOutputInfo(tupdesc->attrs[i]->atttypid,
+							  &typsend, &typisvarlena);
+			outputbytes = OidSendFunctionCall(typsend, attr);
+			hv_store_string(hv, attname, newSVpvn(VARDATA(outputbytes), VARSIZE(outputbytes) - VARHDRSZ));
+			pfree(outputbytes);
+		}
+		else
+		{
+			char		*outputstr;
+			Oid		typoutput;
+			/* XXX should have a way to cache these lookups */
+			getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
+							  &typoutput, &typisvarlena);
 
-		outputstr = OidOutputFunctionCall(typoutput, attr);
+			outputstr = OidOutputFunctionCall(typoutput, attr);
 
-		hv_store_string(hv, attname, newSVstring(outputstr));
+			hv_store_string(hv, attname, newSVstring(outputstr));
 
-		pfree(outputstr);
+			pfree(outputstr);
+		}
 	}
 
 	return newRV_noinc((SV *) hv);
@@ -1904,10 +1996,8 @@
 
 		if (SvOK(sv) && SvTYPE(sv) != SVt_NULL)
 		{
-			char	   *val = SvPV(sv, PL_na);
-
-			ret = InputFunctionCall(&prodesc->result_in_func, val,
-									prodesc->result_typioparam, -1);
+			ret = plperl_convert_sv_to_datum(prodesc->result_oid, &prodesc->result_in_func,
+								prodesc->result_typioparam, sv);
 			isNull = false;
 		}
 		else
@@ -2141,8 +2231,16 @@
 											  "plperl_spi_prepare");
 			typeTup = typenameType(NULL, makeTypeNameFromNameList(names));
 			qdesc->argtypes[i] = HeapTupleGetOid(typeTup);
-			perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
-						   &(qdesc->arginfuncs[i]));
+			if(qdesc->argtypes[i] == BYTEAOID)
+			{
+				perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typreceive,
+						   	&(qdesc->arginfuncs[i]));
+			}
+			else
+			{
+				perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
+						   	&(qdesc->arginfuncs[i]));
+			}
 			qdesc->argtypioparams[i] = getTypeIOParam(typeTup);
 			ReleaseSysCache(typeTup);
 		}
@@ -2297,10 +2395,10 @@
 		{
 			if (SvTYPE(argv[i]) != SVt_NULL)
 			{
-				argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
-												 SvPV(argv[i], PL_na),
-												 qdesc->argtypioparams[i],
-												 -1);
+				argvalues[i] = plperl_convert_sv_to_datum(qdesc->argtypes[i],
+												&qdesc->arginfuncs[i],
+												qdesc->argtypioparams[i],
+												argv[i]);
 				nulls[i] = ' ';
 			}
 			else
@@ -2428,10 +2526,10 @@
 		{
 			if (SvTYPE(argv[i]) != SVt_NULL)
 			{
-				argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
-												 SvPV(argv[i], PL_na),
-												 qdesc->argtypioparams[i],
-												 -1);
+				argvalues[i] = plperl_convert_sv_to_datum(qdesc->argtypes[i],
+												&qdesc->arginfuncs[i],
+												qdesc->argtypioparams[i],
+												argv[i]);
 				nulls[i] = ' ';
 			}
 			else
