Thread: In processing DDL, when does pg_catalog get updated?

In processing DDL, when does pg_catalog get updated?

From
"Ken Winter"
Date:
I'm running a DDL script that does the following (in this order):

1. Creates a table containing a BIGSERIAL primary key column declaration,
which apparently automatically creates a sequence to populate this column.

2. Runs a "gen_sequences" function that I wrote, which executes CREATE
SEQUENCE statements for all columns in the table that have defaults like
'nextval%' but that don't already have sequences.  The part of the function
that checks that the sequence doesn't already exist consults the pg_catalog,
as follows:
            IF NOT EXISTS (SELECT 1
                FROM pg_catalog.pg_class AS t,
                    pg_catalog.pg_namespace AS s
                WHERE t.relname = sequence_name
                    AND s.nspname = schema_name
                    AND t.relnamespace = s.oid
                    AND t.relkind = 'S')
            THEN
                <execute the CREATE SEQUENCE statement>
            END IF;

This script aborts with a message like this:

ERROR:  relation "my_table_id_seq" already exists

...which implies that the code above is not finding "my_table_id_seq" in the
catalog.  I know that the code works OK in detecting sequences that
pre-existed the execution of this script.  So the only explanation that I
can come up with is that, at step 2, the pg_catalog has not yet been updated
to reflect the results of step 1 - namely, that the new sequence has been
created.

Is it possible that the pg_catalog is not updated with the results of a DDL
script until the whole script has executed?

If this is so, is there any way to force the pg_catalog to be updated along
the way?

~ TIA
~ Ken




Re: In processing DDL, when does pg_catalog get updated?

From
Tom Lane
Date:
"Ken Winter" <ken@sunward.org> writes:
> Is it possible that the pg_catalog is not updated with the results of a DDL
> script until the whole script has executed?

No, the serial sequence should exist as soon as the CREATE TABLE is done
... unless you are doing something weird like wrapping the whole thing
in a transaction and expecting uncommitted transaction results to be
visible from another session.  Could you show us a complete test case
instead of an extract?

            regards, tom lane

Re: In processing DDL, when does pg_catalog get updated?

From
"Ken Winter"
Date:
Tom ~

Good idea.  The grisly details are as follows.

****************************

Here is the DDL script (generated from PowerDesigner 10.1.0.1134):

/*==============================================================*/
/* DBMS name:      PostgreSQL 7.3                               */
/* Created on:     12/30/2005 11:08:02 AM                       */
/*==============================================================*/

SET search_path TO public;

/*==============================================================*/
/* Table: e_mail_address                                        */
/*==============================================================*/
create table e_mail_address (
pop_id               INT8                 not null default
nextval('pop_seq'),
effective_date_and_time TIMESTAMP WITH TIME ZONE not null default
CURRENT_TIMESTAMP,
invisible_id         BIGSERIAL            not null,
e_mail_type          VARCHAR(255)         null,
expiration_date_and_time TIMESTAMP WITH TIME ZONE null default 'infinity',
user_name            VARCHAR(255)         not null,
domain_name          VARCHAR(255)         not null,
use_this_e_mail_for_administrative_matters BOOL                 null,
use_this_e_mail_for_teaching_and_practice BOOL                 null,
use_this_e_mail_for_personal_messages BOOL                 null,
omit_this_e_mail_from_school_directory BOOL                 null,
comments             VARCHAR(4000)        null,
constraint PK_e_mail_address_priority_pk primary key (pop_id,
effective_date_and_time, invisible_id),
constraint fk_contact___e_mail_address foreign key (pop_id)
   references pop (pop_id)
on delete cascade on update cascade,
constraint fk_e_mail_type___e_mail_address foreign key (e_mail_type)
   references e_mail_type (e_mail_type)
on delete cascade on update cascade
)
INHERITS (when_and_who)
WITH OIDS;

SELECT gen_sequences('e_mail_address', 'public');

****************************

Here is the function "gen_sequences" that is evoking the error:

CREATE OR REPLACE FUNCTION gen_sequences ( VARCHAR, VARCHAR ) RETURNS
VARCHAR AS
    '
    DECLARE
        table_name ALIAS FOR $1;
        schema_name ALIAS FOR $2;
        this_table RECORD;
        dummy RECORD;
        sequence_name VARCHAR;
        cre_seq_arr VARCHAR [] := ''{}'';
        cre_seq_code VARCHAR := '''';
    BEGIN
        EXECUTE ''SET search_path TO '' || schema_name;

        /* Create a CREATE SEQUENCE statement for the sequence
        of each sequence-assigned column,
        if the sequence doesnt exist already. */
        FOR this_table IN
            SELECT c.column_name AS sub_idcol,
                c.column_default AS default_expr
            FROM information_schema.columns c
            WHERE c.table_name = table_name
                AND c.table_schema = schema_name
                AND c.column_default LIKE ''nextval%''
            LOOP
            sequence_name := split_part(this_table.default_expr, '''''''',
2);
            IF NOT EXISTS (SELECT 1
                FROM pg_catalog.pg_class AS t,
                    pg_catalog.pg_namespace AS s
                WHERE t.relname = sequence_name
                    AND s.nspname = schema_name
                    AND t.relnamespace = s.oid
                    AND t.relkind = ''S'')
            THEN
                IF array_upper(cre_seq_arr, 1) IS NULL THEN
                    cre_seq_arr[1] := ''CREATE SEQUENCE '' || sequence_name
|| '';'' ;
                ELSE
                    cre_seq_arr[array_upper(cre_seq_arr, 1) + 1] := ''CREATE
SEQUENCE '' || sequence_name || '';'' ;
                END IF;
                cre_seq_code := cre_seq_code ||
cre_seq_arr[array_upper(cre_seq_arr, 1)] || ''
                    '';
            END IF;
        END LOOP;

        /* Execute the CREATE SEQUENCE statements, if any. */
        IF array_upper(cre_seq_arr, 1) IS NOT NULL THEN
            FOR n IN 1..array_upper(cre_seq_arr, 1) LOOP
                EXECUTE cre_seq_arr[n];
            END LOOP;
        END IF;
        RETURN  cre_seq_code;
    END;
    '
    LANGUAGE plpgsql
;

****************************

And here is the error message from phpPgAdmin:

SQL error:

ERROR:  relation "e_mail_address_invisible_id_seq" already exists
CONTEXT:  PL/pgSQL function "gen_sequences" line 45 at execute statement

****************************

Line 45 is the line that contains the execute statement.

Those are the raw facts.

My question is: Why didn't the chunk of "gen_sequences" code that consults
pg_catalog find a record of "e_mail_address_invisible_id_seq", and thereby
refrain from trying to create it again?

~ Thanks again
~ Ken



Re: In processing DDL, when does pg_catalog get updated?

From
Tom Lane
Date:
"Ken Winter" <ken@sunward.org> writes:
> My question is: Why didn't the chunk of "gen_sequences" code that consults
> pg_catalog find a record of "e_mail_address_invisible_id_seq", and thereby
> refrain from trying to create it again?

I added a few "raise notice" commands to your function, and got this:

NOTICE:  sub_idcol = invisible_id
NOTICE:  default_exp = nextval('public.e_mail_address_invisible_id_seq'::text)
NOTICE:  sequence_name = public.e_mail_address_invisible_id_seq
NOTICE:  not found
NOTICE:  sub_idcol = pop_id
NOTICE:  default_exp = nextval('pop_seq'::text)
NOTICE:  sequence_name = pop_seq
NOTICE:  found
ERROR:  relation "e_mail_address_invisible_id_seq" already exists
CONTEXT:  SQL statement "CREATE SEQUENCE public.e_mail_address_invisible_id_seq;"
PL/pgSQL function "gen_sequences" line 51 at execute statement

The problem seems to be that you're not accounting for a schema name
possibly appearing in nextval's argument.

            regards, tom lane

Re: In processing DDL, when does pg_catalog get updated?

From
"Ken Winter"
Date:
Tom ~

Right you are!  I added some code to trim off the schema name, and it works
fine.

You also alerted me to the NOTICE facility.  (I'm new to PostgreSQL, and
have been learning it in "wade right in" mode rather than properly studying
the whole environment.)  I have a "PostgreSQL for Dummies" question about
RAISE NOTICE:  Where do I find its output?  According to the documentation
(http://www.postgresql.org/docs/7.4/static/plpgsql-errors-and-messages.htmlh
ttp://www.postgresql.org/docs/7.4/static/plpgsql-errors-and-messages.html),
the messages are either "reported to the client, written to the server log,
or both".  My database is on a web host (zettai.net), and I'm working on it
via phpPgAdmin.  I don't know where to find messages "reported to the
client", and I don't know how to access the system log.  Can anyone help?

~ Thanks!
~ Ken


> -----Original Message-----
> From: Tom Lane [mailto:tgl@sss.pgh.pa.us]
> Sent: Friday, December 30, 2005 12:10 PM
> To: Ken Winter
> Cc: 'PostgreSQL pg-general List'
> Subject: Re: [GENERAL] In processing DDL, when does pg_catalog get
> updated?
>
> "Ken Winter" <ken@sunward.org> writes:
> > My question is: Why didn't the chunk of "gen_sequences" code that
> consults
> > pg_catalog find a record of "e_mail_address_invisible_id_seq", and
> thereby
> > refrain from trying to create it again?
>
> I added a few "raise notice" commands to your function, and got this:
>
> NOTICE:  sub_idcol = invisible_id
> NOTICE:  default_exp =
> nextval('public.e_mail_address_invisible_id_seq'::text)
> NOTICE:  sequence_name = public.e_mail_address_invisible_id_seq
> NOTICE:  not found
> NOTICE:  sub_idcol = pop_id
> NOTICE:  default_exp = nextval('pop_seq'::text)
> NOTICE:  sequence_name = pop_seq
> NOTICE:  found
> ERROR:  relation "e_mail_address_invisible_id_seq" already exists
> CONTEXT:  SQL statement "CREATE SEQUENCE
> public.e_mail_address_invisible_id_seq;"
> PL/pgSQL function "gen_sequences" line 51 at execute statement
>
> The problem seems to be that you're not accounting for a schema name
> possibly appearing in nextval's argument.
>
>             regards, tom lane