Re: Add CREATE support to event triggers - Mailing list pgsql-hackers

From Alvaro Herrera
Subject Re: Add CREATE support to event triggers
Date
Msg-id 20140313210640.GJ4744@eldon.alvh.no-ip.org
Whole thread Raw
In response to Re: Add CREATE support to event triggers  (Alvaro Herrera <alvherre@2ndquadrant.com>)
Responses Re: Add CREATE support to event triggers  (Robert Haas <robertmhaas@gmail.com>)
List pgsql-hackers
Alvaro Herrera escribió:

> I also fixed the sequence OWNED BY problem simply by adding support for
> ALTER SEQUENCE.  Of course, the intention is that all forms of CREATE
> and ALTER are supported, but this one seems reasonable standalone
> because CREATE TABLE uses it internally.

I have been hacking on this on and off.  This afternoon I discovered
that interval typmod output can also be pretty unusual.  Example:

create table a (a interval year to month);

For the column, we get this type spec (note the typmod):
           "coltype": {               "is_array": false,                "schemaname": "pg_catalog",
"typename":"interval",                "typmod": " year to month"           }, 
 

so the whole command output ends up being this:

NOTICE:  expanded: CREATE  TABLE  public.a (a pg_catalog."interval" year to month   )    WITH (oids=OFF)

However, this is not accepted on input:

alvherre=# CREATE  TABLE  public.a (a pg_catalog."interval" year to month   )    WITH (oids=OFF);
ERROR:  syntax error at or near "year"
LÍNEA 1: CREATE  TABLE  public.a (a pg_catalog."interval" year to mon...
        ^
 

I'm not too sure what to do about this yet.  I checked the catalogs and
gram.y, and it seems that interval is the only type that allows such
strange games to be played.  I would hate to be forced to add a kludge
specific to type interval, but that seems to be the only option.  (This
would involve checking the OID of the type in deparse_utility.c, and if
it's INTERVALOID, then omit the schema qualification and quoting on the
type name).

I have also been working on adding ALTER TABLE support.  So far it's
pretty simple; here is an example.  Note I run a single command which
includes a SERIAL column, and on output I get three commands (just like
a serial column on create table).

alvherre=# alter table tt add column b numeric, add column c serial, alter column a set default extract(epoch from
now());
NOTICE:  JSON blob: {   "definition": [       {           "clause": "cache",            "fmt": "CACHE %{value}s",
    "value": "1"       },        {           "clause": "cycle",            "fmt": "%{no}s CYCLE",            "no": "NO"
     },        {           "clause": "increment_by",            "fmt": "INCREMENT BY %{value}s",            "value":
"1"      },        {           "clause": "minvalue",            "fmt": "MINVALUE %{value}s",            "value": "1"
  },        {           "clause": "maxvalue",            "fmt": "MAXVALUE %{value}s",            "value":
"9223372036854775807"      },        {           "clause": "start",            "fmt": "START WITH %{value}s",
"value": "1"       },        {           "clause": "restart",            "fmt": "RESTART %{value}s",
"value":"1"       }   ],    "fmt": "CREATE %{persistence}s SEQUENCE %{identity}D %{definition: }s",    "identity": {
  "objname": "tt_c_seq",        "schemaname": "public"   },    "persistence": ""
 
}
NOTICE:  expanded: CREATE  SEQUENCE public.tt_c_seq CACHE 1 NO CYCLE INCREMENT BY 1 MINVALUE 1 MAXVALUE
9223372036854775807START WITH 1 RESTART 1
 
NOTICE:  JSON blob: {   "fmt": "ALTER TABLE %{identity}D %{subcmds:, }s",    "identity": {       "objname": "tt",
"schemaname": "public"   },    "subcmds": [       {           "definition": {               "collation": {
    "fmt": "COLLATE %{name}D",                    "present": false               },                "coltype": {
         "is_array": false,                    "schemaname": "pg_catalog",                    "typename": "numeric",
               "typmod": ""               },                "default": {                   "fmt": "DEFAULT
%{default}s",                   "present": false               },                "fmt": "%{name}I %{coltype}T
%{default}s%{not_null}s %{collation}s",                "name": "b",                "not_null": "",
"type":"column"           },            "fmt": "ADD COLUMN %{definition}s",            "type": "add column"       },
   {           "definition": {               "collation": {                   "fmt": "COLLATE %{name}D",
   "present": false               },                "coltype": {                   "is_array": false,
"schemaname": "pg_catalog",                    "typename": "int4",                    "typmod": ""               },
          "default": {                   "default": "pg_catalog.nextval('public.tt_c_seq'::pg_catalog.regclass)",
            "fmt": "DEFAULT %{default}s"               },                "fmt": "%{name}I %{coltype}T %{default}s
%{not_null}s%{collation}s",                "name": "c",                "not_null": "",                "type": "column"
        },            "fmt": "ADD COLUMN %{definition}s",            "type": "add column"       },        {
"column":"a",            "definition": "pg_catalog.date_part('epoch'::pg_catalog.text, pg_catalog.now())",
"fmt":"ALTER COLUMN %{column}I SET DEFAULT %{definition}s",            "type": "set default"       }   ]
 
}
NOTICE:  expanded: ALTER TABLE public.tt ADD COLUMN b pg_catalog."numeric"   , ADD COLUMN c pg_catalog.int4 DEFAULT
pg_catalog.nextval('public.tt_c_seq'::pg_catalog.regclass) , ALTER COLUMN a SET DEFAULT
pg_catalog.date_part('epoch'::pg_catalog.text,pg_catalog.now())
 
NOTICE:  JSON blob: {   "definition": [       {           "clause": "owned",            "fmt": "OWNED BY %{owner}D",
       "owner": {               "attrname": "c",                "objname": "tt",                "schemaname": "public"
        }       }   ],    "fmt": "ALTER SEQUENCE %{identity}D %{definition: }s",    "identity": {       "objname":
"tt_c_seq",       "schemaname": "public"   }
 
}
NOTICE:  expanded: ALTER SEQUENCE public.tt_c_seq OWNED BY public.tt.c
ALTER TABLE


Each subcommand is represented separately in a JSON array.  Each element
in the array has a "type" element indicating (broadly) what it's doing;
the "fmt" element has all the details.  So things like replication
systems might decide to replicate some part of the ALTER or not,
depending on the specific type.  (And, of course, they can easily decide
that replica XYZ must not replay the command because the table is not
supposed to exist there; or perhaps it belongs to a replication set that
is not the one the current node is origin for.)


-- 
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services



pgsql-hackers by date:

Previous
From: Andrew Dunstan
Date:
Subject: jsonb status
Next
From: Peter Geoghegan
Date:
Subject: Re: jsonb and nested hstore