4

I have some tables in PostgreSQL 12.9 that were declared as something like

-- This table is written in old style
create table old_style_table_1 (
    id bigserial not null primary key,
    ...
);

-- This table uses new feature
create table new_style_table_2 (
    id bigint generated by default as identity,
    ...
);

Second table seems to be declared using the identity flag introduced in 10th version.

Time went by, and we have partitioned the old tables, while keeping the original sequences:

CREATE TABLE partitioned_old_style_table_1 (LIKE old_style_table_1 INCLUDING DEFAULTS) PARTITION BY HASH (user_id);
CREATE TABLE partitioned_new_style_table_2 (LIKE new_style_table_2 INCLUDING DEFAULTS) PARTITION BY HASH (user_id);

DDL for their id columns seems to be id bigint default nextval('old_style_table_1_id_seq') not null and id bigint default nextval('new_style_table_2_id_seq') not null.

Everything has worked fine so far. Partitioned tables proved to be a great boon and we decided to retire the old tables by dropping them.

DROP TABLE old_style_table_1, new_style_table_2;
-- [2BP01] ERROR: cannot drop desired object(s) because other objects depend on them 
-- Detail: default value for column id of table old_style_table_1 depends on sequence old_style_table_1_id_seq
-- default value for column id of table new_style_table_2 depends on sequence new_style_table_2_id_seq

After some pondering I've found out that sequences may have owners in postgres, so I opted to change them:

ALTER SEQUENCE old_style_table_1_id_seq OWNED BY partitioned_old_style_table_1.id;
DROP TABLE old_style_table_1;
-- Worked out flawlessly

ALTER SEQUENCE new_style_table_2_id_seq OWNED BY partitioned_new_style_table_2.id;
ALTER SEQUENCE new_style_table_2_id_seq OWNED BY NONE;
-- Here's the culprit of the question:
-- [0A000] ERROR: cannot change ownership of identity sequence

So, apparently the fact that this column has pg_attribute.attidentity set to 'd' forbids me from:

• changing the default value of the column:

ALTER TABLE new_style_table_2 ALTER COLUMN id SET DEFAULT 0;
-- [42601] ERROR: column "id" of relation "new_style_table_2" is an identity column

• dropping the default value:

ALTER TABLE new_style_table_2 ALTER COLUMN id DROP DEFAULT;
-- [42601] ERROR: column "id" of relation "new_style_table_2" is an identity column
-- Hint: Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.

• dropping the identity, column or the table altogether (new tables already depend on the sequence):

ALTER TABLE new_style_table_2 ALTER COLUMN id DROP IDENTITY IF EXISTS;
-- or
ALTER TABLE new_style_table_2 DROP COLUMN id;
-- or
DROP TABLE new_style_table_2;
-- result in
-- [2BP01] ERROR: cannot drop desired object(s) because other objects depend on them 
-- default value for column id of table partitioned_new_style_table_2 depends on sequence new_style_table_2_id_seq

I've looked up the documentation, it provides the way to SET IDENTITY or ADD IDENTITY, but no way to remove it or to change to a throwaway sequence without attempting to drop the existing one.

➥ So, how am I able to remove an identity flag from the column-sequence pair so it won't affect other tables that use this sequence?

UPD: Tried running UPDATE pg_attribute SET attidentity='' WHERE attrelid=16816; on localhost, still receive [2BP01] and [0A000]. :/

Though I managed to execute the DROP DEFAULT value bit, but it seems like a dead end.

Xobotun
  • 1,121
  • 1
  • 18
  • 29

1 Answers1

4

I don't think there is a safe and supported way to do that (without catalog modifications). Fortunately, there is nothing special about sequences that would make dropping them a problem. So take a short down time and:

  • remove the default value that uses the identity sequence

  • record the current value of the sequence

  • drop the table

  • create a new sequence with an appropriate START value

  • use the new sequence to set new default values

If you want an identity column, you should define it on the partitioned table, not on one of the partitions.

Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263
  • Sigh, I think that's the only easy way, right. I tried to avoid downtime, and maybe create a sequence in the migration, but `START` seems to take only literals, no `SELECT nextval('old_sequence')` things. I don't like the idea of manually manipulating production database, but I don't have access to `pg_catalog` either, so... Alright, thanks. :D – Xobotun Jan 21 '22 at 16:51
  • 1
    With some small effort, the down time could be seconds. Create a new sequence with a start value of 100000 or so above the value of the current sequence, change the column defaults one by one, then drop the old sequence. – Laurenz Albe Jan 24 '22 at 06:44
  • Given we use 64-bit`BIGINT` 10^5 increment is nothing compared to its 10^19 range, yes. Still, our deployment practices are pretty rigid, meaning new releases need kind of one or two day "sleep-in" on the test contour as we collect performance data and record new bugs. Risking inconsistent ids due to the time span between now and the migration getting applied to the production seems worse than having a five minute downtime. At least that's what I think, and also on this project. :D Thanks, I'll discuss it with the team today. Maybe we'll leave these unused tables truncated untilsomedowntime... – Xobotun Jan 24 '22 at 07:06
  • 1
    What you say makes a lot of sense. I just wanted to point out that the down time can be avoided if it is really important. – Laurenz Albe Jan 24 '22 at 07:17