We are migrating from on-prem SQL Server to cloud-hosted PostgreSQL. Our databases are being translated automatically and this has resulted in a lot of procedures where the data is being returned as refcursor parameters rather than an ordinary recordset e.g.
CREATE OR REPLACE PROCEDURE myschema_dbo.usp_getcustomers(
IN par_includeinactive numeric,
INOUT p_refcur refcursor)
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
OPEN p_refcur FOR
SELECT customer.name AS customername, customer.isactive, customer.emailaddress
FROM myschema_dbo.customer
WHERE customer.isactive = 1 OR par_IncludeInactive = 0
END;
$BODY$;
The calling applications are predominantly C# and we are attempting to call these procedures using the Npgsql data provider:
using (var dataSource = NpgsqlDataSource.Create(this.connectionString))
{
using (var command = dataSource.CreateCommand("myschema_dbo.usp_getcustomers"))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new NpgsqlParameter()
{
ParameterName = "par_includeinactive",
NpgsqlDbType = NpgsqlDbType.Numeric,
Direction = ParameterDirection.Input,
Value = 1
});
command.Parameters.Add(new NpgsqlParameter()
{
ParameterName = "p_refcur",
NpgsqlDbType = NpgsqlDbType.Refcursor,
Direction = ParameterDirection.InputOutput,
Value = "p_refcur"
});
command.ExecuteNonQuery();
command.CommandText = "fetch all in \"p_refcur\"";
command.CommandType = CommandType.Text;
var reader = command.ExecuteReader();
while (reader.Read())
{
// Process the record
}
}
}
This results in a Npgsql.PostgresException with error message 34000: cursor "p_refcur" does not exist. Because of the automated translation process and volume of procedures across our databases, modifying the stored procedures would be a very expensive exercise that we would prefer to avoid.
I have tried fetching the ref cursor parameter using its value, or passing a different value in. I have also searched through stack overflow but the only similar questions refer to functions where a ref cursor is returned rather than used as a parameter for a procedure.
I'd highly recommend modifying those stored procedures to return a table directly rather than a refcursor - the automatic translation from SQL Server stored procedures doesn't seem to be doing a great job there.
For example, your function above could be simplified to the following:
This is more efficient since you get back the results in one roundtrip; if your function returns a refcursor, you then need to execute an additional roundtrip to get the results from that refcursor; it's also needlessly complicated and not natural to PostgreSQL.
Note also that for such simple functions you can simply use SQL rather than pl/pgsql. In addition, PostgreSQL has a 1st-class boolean data type which you should use e.g. for
include_activerather than numeric.