pggen icon indicating copy to clipboard operation
pggen copied to clipboard

Interval processing causes panics

Open flamedmg opened this issue 3 years ago • 4 comments
trafficstars

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

flamedmg avatar Dec 20 '21 18:12 flamedmg

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.

jschaf avatar Dec 20 '21 19:12 jschaf

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.

flamedmg avatar Dec 21 '21 09:12 flamedmg

I can reproduce and looking for a fix.

jschaf avatar May 22 '22 23:05 jschaf

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
}

jschaf avatar May 23 '22 02:05 jschaf