When ALTER TABLE rewrites a table, it reindexes, but the reindex does not
revalidate UNIQUE/EXCLUDE constraints.  This behaves badly in cases like this,
neglecting to throw an error on the new UNIQUE violation:

CREATE TABLE t (c numeric UNIQUE);
INSERT INTO t VALUES (1.1),(1.2);
ALTER TABLE t ALTER c TYPE int;

The comment gave a reason for skipping the checks: it would cause deadlocks when
we rewrite a system catalog.  So, this patch changes things to only skip the
check for system catalogs.
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 2544,2552 **** reindex_index(Oid indexId, bool skip_constraint_checks)
   * catalog indexes while collecting the list.)
   *
   * We also skip rechecking uniqueness/exclusion constraint properties if
!  * heap_rebuilt is true.  This avoids likely deadlock conditions when doing
!  * VACUUM FULL or CLUSTER on system catalogs.  REINDEX should be used to
!  * rebuild an index if constraint inconsistency is suspected.
   *
   * Returns true if any indexes were rebuilt.  Note that a
   * CommandCounterIncrement will occur after each index rebuild.
--- 2544,2554 ----
   * catalog indexes while collecting the list.)
   *
   * We also skip rechecking uniqueness/exclusion constraint properties if
!  * heap_rebuilt is true and the relation is a system catalog.  This avoids
!  * likely deadlock conditions when doing VACUUM FULL or CLUSTER.  We trust 
that
!  * constraints will remain consistent across a user-issued ALTER TABLE 
against a
!  * system catalog.  REINDEX should be used to rebuild an index if constraint
!  * inconsistency is suspected.
   *
   * Returns true if any indexes were rebuilt.  Note that a
   * CommandCounterIncrement will occur after each index rebuild.
***************
*** 2629,2635 **** reindex_relation(Oid relid, bool toast_too, bool 
heap_rebuilt)
                        if (is_pg_class)
                                RelationSetIndexList(rel, doneIndexes, 
InvalidOid);
  
!                       reindex_index(indexOid, heap_rebuilt);
  
                        CommandCounterIncrement();
  
--- 2631,2637 ----
                        if (is_pg_class)
                                RelationSetIndexList(rel, doneIndexes, 
InvalidOid);
  
!                       reindex_index(indexOid, heap_rebuilt && 
IsSystemRelation(rel));
  
                        CommandCounterIncrement();
  
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
***************
*** 1774,1779 **** DEBUG:  Rebuilding index "t_strarr_idx"
--- 1774,1781 ----
  DEBUG:  Rebuilding index "t_square_idx"
  DEBUG:  Rebuilding index "t_expr_idx"
  DEBUG:  Rebuilding index "t_touchy_f_idx"
+ ERROR:  could not create unique index "t_touchy_f_idx"
+ DETAIL:  Key (touchy_f(constraint1))=(100) is duplicated.
  ALTER TABLE t ALTER constraint2 TYPE trickint;                                
                -- noop-e
  DEBUG:  Rewriting table "t"
  DEBUG:  Rebuilding index "t_constraint4_key"
***************
*** 1792,1816 **** DEBUG:  Rebuilding index "t_strarr_idx"
  DEBUG:  Rebuilding index "t_square_idx"
  DEBUG:  Rebuilding index "t_touchy_f_idx"
  DEBUG:  Rebuilding index "t_expr_idx"
! -- Temporary fixup until behavior of the previous two improves.
! ALTER TABLE t ALTER constraint1 TYPE int, ALTER constraint2 TYPE int;
! DEBUG:  Rewriting table "t"
! DEBUG:  Rebuilding index "t_constraint4_key"
! DEBUG:  Rebuilding index "t_integral_key"
! DEBUG:  Rebuilding index "t_rational_key"
! DEBUG:  Rebuilding index "t_daytimetz_key"
! DEBUG:  Rebuilding index "t_daytime_key"
! DEBUG:  Rebuilding index "t_stamptz_key"
! DEBUG:  Rebuilding index "t_stamp_key"
! DEBUG:  Rebuilding index "t_timegap_key"
! DEBUG:  Rebuilding index "t_bits_key"
! DEBUG:  Rebuilding index "t_network_key"
! DEBUG:  Rebuilding index "t_string_idx"
! DEBUG:  Rebuilding index "t_string_idx1"
! DEBUG:  Rebuilding index "t_strarr_idx"
! DEBUG:  Rebuilding index "t_square_idx"
! DEBUG:  Rebuilding index "t_touchy_f_idx"
! DEBUG:  Rebuilding index "t_expr_idx"
  -- Change a column with an outgoing foreign key constraint.
  ALTER TABLE t ALTER constraint3 TYPE numeric(8,1); -- rewrite, FK error
  DEBUG:  Rewriting table "t"
--- 1794,1801 ----
  DEBUG:  Rebuilding index "t_square_idx"
  DEBUG:  Rebuilding index "t_touchy_f_idx"
  DEBUG:  Rebuilding index "t_expr_idx"
! ERROR:  could not create unique index "t_expr_idx"
! DETAIL:  Key ((1))=(1) is duplicated.
  -- Change a column with an outgoing foreign key constraint.
  ALTER TABLE t ALTER constraint3 TYPE numeric(8,1); -- rewrite, FK error
  DEBUG:  Rewriting table "t"
*** a/src/test/regress/sql/alter_table.sql
--- b/src/test/regress/sql/alter_table.sql
***************
*** 1246,1253 **** FROM pg_trigger WHERE tgrelid = 't'::regclass ORDER BY 
tgname;
  ALTER TABLE t ALTER constraint0 TYPE trickint;                                
                -- verify-e
  ALTER TABLE t ALTER constraint1 TYPE trickint;                                
                -- noop-e
  ALTER TABLE t ALTER constraint2 TYPE trickint;                                
                -- noop-e
- -- Temporary fixup until behavior of the previous two improves.
- ALTER TABLE t ALTER constraint1 TYPE int, ALTER constraint2 TYPE int;
  
  -- Change a column with an outgoing foreign key constraint.
  ALTER TABLE t ALTER constraint3 TYPE numeric(8,1); -- rewrite, FK error
--- 1246,1251 ----
-- 
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to