tcdi / plrust

A Rust procedural language handler for PostgreSQL
PostgreSQL License
1.1k stars 32 forks source link

enumerated type as function arg? #407

Closed ncharlot closed 6 months ago

ncharlot commented 6 months ago

Hi,

I'm trying to pass a Postgres enum as an argument:

create type mood as enum ('sad', 'ok', 'happy');
create function test_enum(m mood)
returns text
language plrust parallel safe
as $$
    Ok(Some("test ok".to_string()))
$$;

But i got the error:

ERROR:
   0: Oid `oid=#16409` was not mappable to a Rust type

I saw that pgrx was able to create a Rust enum and to map it to Postgres enum but did not find any doc nor example about the reciprocity.

Thanks for your help!

eeeebbbbrrrr commented 6 months ago

Yeah, pl/rust doesn't support mapping Postgres enums inside a LANGUAGE plrust function. It's not clear how we'd do that. Doing it via some codegen to make a corresponding Rust enum type would be a compile-time thing and then we'd have problems keeping the function's understanding of the enum synchronized with the Postgres version.

On the flip side, we could probably invent and expose some kind of dynamic interface in Rust, but then we'd lose all the type safety and performance benefits enums can bring.

I don't have a great answer for you. I suppose, and this is gross, but I suppose you could make the argument an integer and then have postgres do the casting for you at the planner level. It would be on you to then map integer values to the enum variant, but as the owner of the enum schema, you're probably better equipped to do that than we are.

ncharlot commented 6 months ago

Thank for you speed answer @eeeebbbbrrrr

Since you didn't suggest that, I guess creating the enum in Rust with #[derive(PostgresEnum)] would not work either.

eeeebbbbrrrr commented 6 months ago

Oh no. That stuff isn’t even available to plrust functions

ncharlot commented 6 months ago

Ok! Or we can write extensions directly rather than function/procedure in PlRust.

eeeebbbbrrrr commented 6 months ago

Yeah, you could. That depends on what it is you're building and how you want to manage it. PL/Rust is most useful for standalone UDFs that don't need any information that can't be written directly into the function's source code.

Full pgrx extensions let you do anything, and comes with all the upsides and downsides of "anything".

ncharlot commented 6 months ago

Can we expect better raw performance btw a function written in extension and a UDF in PL/Rust?

eeeebbbbrrrr commented 6 months ago

given any standalone function, the performance should be identical between a LANGUAGE plrust UDF and its equivalent #[pg_extern] version written using pgrx.

I suppose you could eek a little more perf out of a pgrx extension because you can target-cpu=native, but otherwise they'd be the same with essentially the same overhead.

<short pause>

I suppose PL/Rust functions have a HashMap lookup or two plus some additional branching per function call that a raw pgrx extension function wouldn't. I'd expect that to be lost in the noise, however.