pggen
pggen copied to clipboard
Interval processing causes panics
Hello, i'm getting the following when trying to pass interval to postgresql stored function:
panic: encode []ProductIn: cannot convert {31207680000000 0 0 2} to Interval
I tried to debug and found that error happens here: https://github.com/jackc/pgtype/blob/master/interval.go#L45 Object that is passed there is of type pgtype.Interval, which can't be processed properly as you can see. Could you please suggest how i can fix the issue and i will be happy to issue PR
Can you post a minimal schema, query, and pggen invocation to reproduce?
Inferring from the error message, it looks like you have a custom type ProductIn used as input to pggen. It looks like you're passing an array, so []ProductIn, and you want to cast to the postgres type Interval[] but pggen is trying to cast to a single interval.
Could be a type mismatch in your pggen query or it could be a bug in pggen (handling input array elements wasn't the simplest code I've ever written).
I have a branch open that touches some of this. My plan was to tackle a bunch of open bugs over the break.
Here is the schema: schema.sql
CREATE TYPE public.test_in as
(
sku text,
trial_interval interval
);
create function public.test_in_fn(f_products public.test_in) returns void as
$$
begin
select f_products;
end ;
$$ language plpgsql strict
volatile
security definer
set search_path to pg_catalog, public, pg_temp;
query.sql
--name: IntervalTest :exec
select public.test_in_fn(pggen.arg('test_in_arg'));
code that calls IntervalTest function
a := ""
NewQuerier(p.db).IntervalTest(ctx, TestIn{
Sku: &a,
TrialInterval: pgtype.Interval{Status: pgtype.Present, Microseconds: microsecondsPerHour * 1},
})
In real code i'm passing an array of products, but this code fails as well.
I can reproduce and looking for a fix.
The panic occurs because we're setting a pgtype.Interval to another Interval which should be supported by pgtype. The relevant code is https://github.com/jackc/pgtype/blob/d846dbcb75b2ac38a1c6fd0390cd18472fe72dee/interval.go#L35:
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
I don't understand why pgtype only returns if value2 != value. Seems like we can return nil if value2 == value.
Edit: oh, it's a check to see if the Get value is different than the ValueEncoder.
Here's a test case showing the problem:
func TestPgtype_Interval(t *testing.T) {
v1 := pgtype.Interval{Days: 2, Status: pgtype.Present}
v2 := pgtype.Interval{Days: 2, Status: pgtype.Present}
err := v1.Set(v2)
require.NoError(t, err) // Errors
}