jonwagner / Insight.Database

Fast, lightweight .NET micro-ORM

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

PostgreSQL CommandType.StoredProcedure 42809: procname() is not a procedure exception

SCVNG3R opened this issue · comments

As it's mentioned on Npgsql documentation website, starting with Npgsql 7.0, CommandType.StoredProcedure now invokes stored procedures, and not function as before. Attempting to call a database function (such as GetBeerByType()) will result in the following exception: Npgsql.PostgresException: '42809: procname() is not a procedure

This renders Insight.Database unusable with PostgreSQL
More info can be found here: Npgsql Basic Usage

Steps to reproduce

Attempt to run the HelloWorld code under Npgsql

Expected behavior

Return value from calling a database function

  • Dotnet version: [netcore7]
  • Npgsql: [7.0.1]
  • Database: [PostgreSQL 15]
  • Library version: [6.3.11]

I see that this is a transition because PG < v11 only had functions and now it supports stored procedures. NpgSQL previously mapped CommandType.StoredProcedure to functions and now is correcting the behaviour.

Their release notes mark this as a breaking change.

I believe the correct stance to take is:

  • CommandType.StoredProcedure should invoke stored procedures
  • If you coded your database with FUNCTIONs then you should follow the npgsql guidance of calling AppContext.SetSwitch("Npgsql.EnableStoredProcedureCompatMode", true);

As for Insight.Database, I will update the test cases to use stored procedures and ensure it works with PG11 and NPGSQL7.

sigh...this is going to be a lot harder than i expected.

  • postgres and npgsql use entirely different methods for returning recordsets and output parameters between functions and procedures
  • there is no CommandType.Function that allows us to distinguish between functions and procedures and get the desired functionality.

I'll try to find time to do a full pass through the PG provider but it's non-trivial.

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

sigh...this is going to be a lot harder than i expected.

  • postgres and npgsql use entirely different methods for returning recordsets and output parameters between functions and procedures
  • there is no CommandType.Function that allows us to distinguish between functions and procedures and get the desired functionality.

We could add our own. Make a NpgsqlCommandType enum and add the missing value as NpgsqlCommandType.Function=100.

For the property...

public NpgsqlCommandType NpgsqlCommandType {
    { get => (CommandType)NpgsqlCommandType; }
    { set => NpgsqlCommandType = (CommandType)value; }
}

This works because enums don't have range checks.

Good news?

For v8.0, I updated the Postgres provider. Now if you use CommandType.StoredProcedure, we do a mixup on the command:

  • Convert it back to CommandType.Text
  • Convert to SELECT * FROM function_name (params)

And surprisingly, this works!

@Grauenwolf give it a shot after the next build.

(Note that there is no longer support for calling stored procedures, but this feels like it's better compatibility.)