Thread: BUG #18647: INSERT statements execute functions twice.

BUG #18647: INSERT statements execute functions twice.

From
PG Bug reporting form
Date:
The following bug has been logged on the website:

Bug reference:      18647
Logged by:          Todd Brandys
Email address:      brandystodd@gmail.com
PostgreSQL version: 16.1
Operating system:   Linux
Description:

I am writing a function uuid.nextval(...) that returns a UUID value from a
preallocated pool of values known to be unique.  I was seeing the pool
decrease by two per INSERT, and I found something interesting when I raised
a NOTICE in the nextval() function.  Here are three INSERTs, and only the
last will result in nextval() being called once.  Is this a known issue?
What would be the reason for calling the functions in the VALUES list twice?
 For the foreseeable future, this means that the most efficient method would
be to place all functions in a FROM list.

dchain=# INSERT INTO public.party
    VALUES ( uuid.nextval('party'), utc.get_timestamp(),
SESSION_USER::regrole, uuid.v4() );
NOTICE:  ***** uuid.nextval
DETAIL:
HINT:
NOTICE:  ***** uuid.nextval
DETAIL:
HINT:
INSERT 0 1

dchain=# INSERT INTO public.party
SELECT      uuid.nextval('party'::regclass) AS party,
            utc.get_timestamp() AS date_upated,
            SESSION_USER::regrole AS user_updated,
            uuid.v4() AS organization;
NOTICE:  ***** uuid.nextval
DETAIL:
HINT:
NOTICE:  ***** uuid.nextval
DETAIL:
HINT:
INSERT 0 1

dchain=# INSERT INTO public.party
SELECT      d_party AS party,
            utc.get_timestamp() AS date_upated,
            SESSION_USER::regrole AS user_updated,
            uuid.v4() AS organization
    FROM    uuid.nextval('party'::regclass) AS d_party;
NOTICE:  ***** uuid.nextval
DETAIL:
HINT:
INSERT 0 1


Re: BUG #18647: INSERT statements execute functions twice.

From
"David G. Johnston"
Date:
On Tue, Oct 8, 2024, 12:31 PG Bug reporting form <noreply@postgresql.org> wrote:
The following bug has been logged on the website:

Bug reference:      18647
Logged by:          Todd Brandys
Email address:      brandystodd@gmail.com
PostgreSQL version: 16.1
Operating system:   Linux
Description:       

I am writing a function uuid.nextval(...)

Show that create function command then.


dchain=# INSERT INTO public.party

The create table for party probably helps too.

IOW, make it possible for someone to reproduce your issue.

You may also wish to be running a supported version before diving down bug hunting.

David J.

Re: BUG #18647: INSERT statements execute functions twice.

From
Tom Lane
Date:
"David G. Johnston" <david.g.johnston@gmail.com> writes:
> The create table for party probably helps too.

I'm wondering about ON INSERT rules for that table ...

> IOW, make it possible for someone to reproduce your issue.

Indeed.  I tried some simple experiments with setting a breakpoint
on the standard nextval() function, and I don't see more than one
call.

            regards, tom lane



Re: BUG #18647: INSERT statements execute functions twice.

From
Todd Brandys
Date:
Here is the CREATE table for party.  It was nothing more than a test table at this time:

CREATE TABLE party (
    uuid uuid NOT NULL,
    date_updated timestamp(0) NOT NULL,
    user_updated     pg_catalog.regrole NOT NULL,
    organization uuid NOT NULL,

    CONSTRAINT pk_party
PRIMARY KEY ( uuid )
);

That’s the extend of it.  The body of the uuid.nextval() function is an SQL function.

CREATE FUNCTION uuid.nextval ( IN i_regclass pg_catalog.regclass ) RETURNS pg_catalog.uuid AS $$
SELECT raise.notice('***** uuid.nextval');
    WITH t_pool AS (
        SELECT      pool.id_entity AS id_entity,
                    pool.uuid AS uuid
            FROM    uuid.pool
            WHERE   pool.id_entity = i_regclass
            ORDER BY pg_catalog.RANDOM() ASC
            LIMIT   1
    ), t_delete AS (
        DELETE FROM uuid.pool
            USING   t_pool
            WHERE   pool.id_entity = t_pool.id_entity
                    AND pool.uuid = t_pool.uuid
        RETURNING   pool.*
    )
    SELECT      t_delete.uuid
        FROM    t_delete
        LIMIT   1;  $$
 LANGUAGE SQL VOLATILE NOT LEAKPROOF STRICT PARALLEL UNSAFE SECURITY DEFINER;

On Oct 8, 2024, at 1:04 PM, David G. Johnston <david.g.johnston@gmail.com> wrote:

On Tue, Oct 8, 2024, 12:31 PG Bug reporting form <noreply@postgresql.org> wrote:
The following bug has been logged on the website:

Bug reference:      18647
Logged by:          Todd Brandys
Email address:      brandystodd@gmail.com
PostgreSQL version: 16.1
Operating system:   Linux
Description:       

I am writing a function uuid.nextval(...)

Show that create function command then.


dchain=# INSERT INTO public.party

The create table for party probably helps too.

IOW, make it possible for someone to reproduce your issue.

You may also wish to be running a supported version before diving down bug hunting.

David J.

Re: BUG #18647: INSERT statements execute functions twice.

From
"David G. Johnston"
Date:
On Wednesday, October 9, 2024, Todd Brandys <brandystodd@gmail.com> wrote:
Here is the CREATE table for party.  It was nothing more than a test table at this time:

CREATE TABLE party (
    uuid uuid NOT NULL,
    date_updated timestamp(0) NOT NULL,
    user_updated     pg_catalog.regrole NOT NULL,
    organization uuid NOT NULL,

    CONSTRAINT pk_party
PRIMARY KEY ( uuid )
);

As an aside, using regrole is not a good idea.  The meaning of the integer that gets saved will change if you perform an upgrade or otherwise have to rebuild the global role catalog table.  User-space should not be storing OID values.

David J. 

Re: BUG #18647: INSERT statements execute functions twice.

From
Greg Sabino Mullane
Date:
More detail is still needed. We don't have access to your schemas and functions. But at first glance, there is something else going on, not explained by the given code. Try to remove the unimportant parts and get it down to a reproducible test case. For example, here is a test case showing the expected behavior on Postgres 16:

create function mynextval(text) returns text language plpgsql as $$ BEGIN RAISE NOTICE 'Inside mynextval!'; RETURN 'x'; END; $$;
create table foo(a text, b text);

greg=# insert into foo values (mynextval('abc'));
NOTICE:  Inside mynextval!
INSERT 0 1

greg=# insert into foo values (mynextval('abc'), mynextval('def'));
NOTICE:  Inside mynextval!
NOTICE:  Inside mynextval!
INSERT 0 1

greg=# insert into foo select mynextval('abc'), mynextval('def');
NOTICE:  Inside mynextval!
NOTICE:  Inside mynextval!
INSERT 0 1

greg=# insert into foo select x from mynextval('abc') x;
NOTICE:  Inside mynextval!
INSERT 0 1

greg=#  insert into foo select mynextval('def') from mynextval('abc') x;
NOTICE:  Inside mynextval!
NOTICE:  Inside mynextval!
INSERT 0 1

Cheers,
Greg

Re: BUG #18647: INSERT statements execute functions twice.

From
Tom Lane
Date:
Greg Sabino Mullane <htamfids@gmail.com> writes:
> More detail is still needed. We don't have access to your schemas and
> functions. But at first glance, there is something else going on, not
> explained by the given code. Try to remove the unimportant parts and get it
> down to a reproducible test case.

Yes, we really need a self-contained test case.

Also, is this stock community Postgres, or some derivative
(RDS, EDB, etc)?  Do you have any extensions installed?

            regards, tom lane



Re: BUG #18647: INSERT statements execute functions twice.

From
Alvaro Herrera
Date:
On 2024-Oct-09, Todd Brandys wrote:

> CREATE FUNCTION uuid.nextval ( IN i_regclass pg_catalog.regclass ) RETURNS pg_catalog.uuid AS $$
> SELECT raise.notice('***** uuid.nextval');
>     WITH t_pool AS (
>         SELECT      pool.id_entity AS id_entity,
>                     pool.uuid AS uuid
>             FROM    uuid.pool
>             WHERE   pool.id_entity = i_regclass
>             ORDER BY pg_catalog.RANDOM() ASC
>             LIMIT   1

Not related to your reported problem, but note that the "order by
random()" pattern might be slow as uuid.pool becomes large.  Andrew
Gierth wrote a blog post on this topic awhile ago which may be helpful:
https://blog.rhodiumtoad.org.uk/2009/03/08/selecting-random-rows-from-a-table/

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/
"Before you were born your parents weren't as boring as they are now. They
got that way paying your bills, cleaning up your room and listening to you
tell them how idealistic you are."  -- Charles J. Sykes' advice to teenagers