ALTER VLABEL and ALTER ELABEL#
Renames a label, changes its storage, attaches or detaches a parent, turns its indexes off, or adds and removes promoted typed columns.
Synopsis#
ALTER VLABEL [ IF EXISTS ] label_name RENAME TO new_label_name
ALTER ELABEL [ IF EXISTS ] label_name action [, ... ]
ALTER ELABEL [ IF EXISTS ] label_name RENAME TO new_label_name
where action is one of:
ADD [ COLUMN ] promoted_property
DROP [ COLUMN ] column_name [ CASCADE | RESTRICT ]
DISABLE INDEX
SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
SET TABLESPACE tablespace_name
SET { LOGGED | UNLOGGED }
CLUSTER ON index_name
SET WITHOUT CLUSTER
INHERIT parent_label
NO INHERIT parent_label
REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
OWNER TO role_specification
bold keywords · italic placeholders you supply · [ ] optional · ... repeatable. See Syntax conventions.
Description#
ALTER VLABEL acts on a vertex label and ALTER ELABEL on an edge label. Apart from the
keyword, the two statements are the same: every action listed above is accepted on both
kinds. The difference is what each kind of label has for an action to act on.
The indexes a label is created with differ: a vertex label gets a primary key on
id, an edge label gets btree indexes on(start, "end")and("end", start)plus a BRIN index onid.DISABLE INDEXinvalidates all of a label’s indexes either way, so it has one to invalidate on a new vertex label and three on a new edge label.CLUSTER ONalso has different names to choose from.The structural columns that
DROP COLUMNrefuses areidandpropertieson a vertex label, plusstartandendon an edge label.INHERITandNO INHERITrequire a parent of the same kind as the label, and in the same graph.
The label is looked up in the graph named by graph_path; the name cannot be qualified.
RENAME TOis its own form. It cannot be combined with any other action, and a list of several actions cannot contain it.Several actions in one statement are separated by commas and applied in order.
The base labels
ag_vertexandag_edgecannot be altered at all.ALTER VLABELrefuses an edge label andALTER ELABELrefuses a vertex label.
Reshaping a label with ALTER TABLE instead is refused unless enable_graph_ddl is on.
The graph catalog describes a label’s columns, and ALTER TABLE does not update it.
How a graph is stored
covers that gate.
Parameters#
- IF EXISTS
Issue a notice instead of an error when the label does not exist.
- label_name
Label to alter, in the graph named by
graph_path.- RENAME TO new_label_name
Give the label a new name. Vertices and edges keep their ids, so
label()reports the new name for rows created before the rename. The table’s sequence and indexes keep the names they were given, so check those before you writeCLUSTER ON.- ADD [ COLUMN ] promoted_property
Add a promoted typed column and backfill it from the existing rows.
promoted_propertytakes the same three forms as inCREATE VLABEL, under the same restrictions. A property already promoted on the label is refused, as is promoting the same key twice in one statement.- DROP [ COLUMN ] column_name [ CASCADE | RESTRICT ]
Drop a column and, for a promoted property, forget its mapping. A structural column of the label is refused. Indexes built on the dropped column go with it.
- DISABLE INDEX
Mark every index on the label invalid, so that a bulk load does not maintain them. Reads and writes keep working and the planner ignores an invalid index. There is no
ENABLE INDEX; the way back isREINDEX VLABEL.- SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
Set the storage mode of the label’s
propertiescolumn. The mode decides whether a large property map is held inline or in the table’s TOAST relation, and whether it is compressed. A label starts withEXTENDED, which is out of line and compressed. The statement changes the strategy for future writes; it does not rewrite what is already stored.- SET TABLESPACE tablespace_name
Move the label’s table to another tablespace. Its indexes stay where they are.
- SET { LOGGED | UNLOGGED }
Turn write-ahead logging for the label’s table on or off. The label’s id sequence changes persistence with it.
- CLUSTER ON index_name
Record an index as the one a later
CLUSTERshould use. It does not reorder anything now.- SET WITHOUT CLUSTER
Forget that record.
- INHERIT parent_label
Add the label as a child of another label of the same kind in the same graph, so that a pattern on the parent starts matching this label’s rows.
- NO INHERIT parent_label
Remove that relationship.
- REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
Choose which old values a write writes to the WAL to identify a row, for logical replication.
- OWNER TO role_specification
Give the label to another role. Write a role name,
CURRENT_ROLE,CURRENT_USERorSESSION_USER.
Examples#
The examples build their own graph, catalogue, rather than using
the example dataset, and drop it at the end.
CREATE GRAPH catalogue;
SET graph_path = catalogue;
CREATE VLABEL film;
CREATE (:film {title: 'Arrival', year: 2016}), (:film {title: 'Dune', year: 2021});
Rename a label#
ALTER VLABEL film RENAME TO movie;
\dGl catalogue.mov*
List of labels
Graph | Name | Type | Owner
-----------+-------+--------+-------
catalogue | movie | vertex | agens
(1 row)
The rows came with it:
MATCH (m:movie) RETURN count(m) AS movies;
movies
--------
2
(1 row)
The sequence and the primary key still carry the old name:
\d catalogue.movie
Table "catalogue.movie"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+----------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('catalogue.movie'::cstring), nextval('catalogue.film_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
Indexes:
"film_pkey" PRIMARY KEY, btree (id)
Inherits: catalogue.ag_vertex
So ALTER VLABEL movie CLUSTER ON movie_pkey fails with
index "movie_pkey" for table "movie" does not exist, and the name to write is film_pkey.
Turn a label’s indexes off for a bulk load#
ALTER VLABEL movie DISABLE INDEX;
\d catalogue.movie
Table "catalogue.movie"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+----------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('catalogue.movie'::cstring), nextval('catalogue.film_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
Indexes:
"film_pkey" PRIMARY KEY, btree (id) INVALID
Inherits: catalogue.ag_vertex
Load the rows, then build the indexes again:
REINDEX VLABEL movie;
REINDEX
Promote a property on a label that already holds rows#
ALTER VLABEL movie ADD COLUMN year int GENERATED;
\d catalogue.movie
Table "catalogue.movie"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+-----------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('catalogue.movie'::cstring), nextval('catalogue.film_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
year | integer | | | generated always as (ag_property_text(properties, 'year'::text, 'n'::"char")::integer) stored
Indexes:
"film_pkey" PRIMARY KEY, btree (id)
Inherits: catalogue.ag_vertex
The existing rows are backfilled, so the column is complete the moment the statement returns:
SELECT year FROM catalogue.movie ORDER BY year;
year
------
2016
2021
(2 rows)
Look up what a label promotes#
ag_label_property maps a property key to the column that answers for it:
ALTER VLABEL movie ADD COLUMN released text GENERATED (releaseDate);
SELECT p.propname, p.attnum FROM pg_catalog.ag_label_property p
JOIN pg_catalog.ag_label l ON l.oid = p.laboid
JOIN pg_catalog.ag_graph g ON g.oid = l.graphid
WHERE g.graphname = 'catalogue' AND l.labname = 'movie' ORDER BY p.attnum;
propname | attnum
-------------+--------
year | 3
releasedate | 4
(2 rows)
attnum is the column’s position in the table. Join the query to pg_attribute on it when
you want the column name as well. The two differ whenever the explicit-key form was used.
Drop a promoted column#
ALTER VLABEL movie DROP COLUMN released;
The mapping goes with the column:
SELECT p.propname, p.attnum FROM pg_catalog.ag_label_property p
JOIN pg_catalog.ag_label l ON l.oid = p.laboid
JOIN pg_catalog.ag_graph g ON g.oid = l.graphid
WHERE g.graphname = 'catalogue' AND l.labname = 'movie' ORDER BY p.attnum;
propname | attnum
----------+--------
year | 3
(1 row)
Reads of releasedate go back to the property bag; nothing was deleted from it.
Change how the property map is stored#
ALTER VLABEL movie SET STORAGE external;
The mode is set on properties, whichever column you might have expected:
SELECT attname, attstorage FROM pg_attribute
WHERE attrelid = 'catalogue.movie'::regclass AND attnum > 0 AND NOT attisdropped;
attname | attstorage
------------+------------
id | p
properties | e
year | p
(3 rows)
Attach and detach a parent#
CREATE VLABEL work;
ALTER VLABEL movie INHERIT work;
\dGv catalogue.movie
List of labels
Graph | Name | Type | Owner
-----------+-------+--------+-------
catalogue | movie | vertex | agens
(1 row)
Vertex label "catalogue.movie"
--
Inherits: catalogue.ag_vertex,
catalogue.work
movie now has two parents: the base label it started with, and work. Detaching leaves
the base label alone:
ALTER VLABEL movie NO INHERIT work;
ALTER VLABEL
Refusals worth recognizing#
A structural column cannot be dropped:
ALTER VLABEL movie DROP COLUMN properties;
ERROR: cannot drop column "properties" of graph label "movie"
HINT: It is a structural column of the graph label.
An added column has to be generated from the bag:
ALTER VLABEL movie ADD COLUMN rank int;
ERROR: a non-generated promoted column is not supported yet
HINT: Use GENERATED to mirror the property from the jsonb bag.
A property already promoted cannot be promoted a second time:
ALTER VLABEL movie ADD COLUMN yr2 int GENERATED (year);
ERROR: property "year" is already promoted on graph label "movie"
HINT: Drop the existing promoted column first, or promote the property to a different column name.
The base labels are off limits, as parents and as targets:
ALTER VLABEL movie INHERIT ag_vertex;
ERROR: cannot ALTER inheritance with base label
ALTER VLABEL ag_vertex SET STORAGE main;
ERROR: ALTER base vertex label is prohibited
Each statement acts on one kind of label:
CREATE ELABEL directed;
ALTER VLABEL directed RENAME TO helmed;
ERROR: RENAME VLABEL cannot RENAME edge label
And RENAME TO stands alone:
ALTER VLABEL movie RENAME TO film, SET STORAGE main;
ERROR: syntax error at or near ","
LINE 1: ALTER VLABEL movie RENAME TO film, SET STORAGE main;
^
Reshaping the label’s table with SQL is refused while enable_graph_ddl is off:
ALTER TABLE catalogue.movie ADD COLUMN rank int;
ERROR: cannot add a column to graph label "movie" with ALTER TABLE
HINT: Use ALTER VLABEL or ALTER ELABEL instead, which keeps the graph catalog in step.
Finally, drop the graph the examples built:
DROP GRAPH catalogue CASCADE;
Notes#
SET STORAGE takes four keywords, not five. DEFAULT is reserved and is a syntax error
here. To go back to the mode a label starts with, write SET STORAGE extended. An
unrecognized word is reported as invalid storage type "...".
The IF EXISTS notice differs between the two forms: label "nosuch" does not exist, skipping from RENAME TO, and graph label "nosuch" does not exist, skipping from an
action list. Both then report success and do nothing.
Compatibility#
ISO/IEC 39075 (GQL)#
GQL has no statement that alters a label, because it has no labels to alter. An element
type belongs to a graph type, and a graph type is created and dropped whole
(<create graph type statement>, §12.6). Nothing in GQL corresponds to renaming a label,
promoting a property, or turning an index off. Graph types are tracked as planned in the
GQL conformance matrix.
PostgreSQL#
Every action here is an ALTER TABLE action, and each one means what it means there, with
two adjustments. SET STORAGE names no column. The only column whose storage is worth
choosing is properties, and the mode is applied to that one. DISABLE INDEX has no
ALTER TABLE counterpart at all: it marks the label’s indexes invalid, which SQL can
otherwise only do by interrupting CREATE INDEX CONCURRENTLY.
Going the other way, ALTER TABLE on a label’s table is refused for the actions that would
reshape it, unless enable_graph_ddl is on. Adding, dropping or retyping a column is such
an action. The example above shows the refusal. The actions on this page never need that
setting, because they update the graph catalog themselves.