PostgreSQL 12.1 repairs concurrent index rebuild coordination
The first PostgreSQL 12 maintenance release fixes lock handling and progress reporting during concurrent reindexing. It also repairs stored bit-string padding and recovery settings.
Rebuilding an index while writes continue requires coordination around both the existing index and its replacement. PostgreSQL 12.1 repairs a missing session-level lock on the new index version during REINDEX CONCURRENTLY. Without it, another session could manipulate that index before the rebuild operation was ready.
The November 14 announcement delivers the first maintenance update for PostgreSQL 12 alongside updates to the other supported branches. Its 12.1 release notes describe several concurrent-reindex fixes, including interrupt handling and a race in progress reporting.
I value operations that let PostgreSQL maintenance proceed while applications remain active. Their usefulness depends on the coordination rules being correct, especially when the operation fails or is canceled. This release makes that part of concurrent index rebuilding more reliable.
Replacement indexes need protection too
The missing lock concerns the new index version created by the rebuild. Protecting only the original object is insufficient when another object participates in the operation. The replacement must remain protected for the interval in which the rebuilding session still depends on controlling it.
A separate lock-handling repair addresses query cancellation and session termination. An interrupt arriving at the wrong time could leave session-level locks unreleased. That is an error-path problem, distinct from allowing other sessions to act too early during normal execution.
These fixes show why concurrency support involves more than reducing the duration of a table lock. The operation has several objects and several possible exits. Each exit needs to leave the correct lock state, including when an external request interrupts the work.
The release also repairs a race while reporting progress for concurrent index creation or rebuilding. Reporting is observable administrative behavior, but its implementation must respect the same concurrent state changes as the underlying command. In this case, the race could produce a crash.
Another fix prevents duplicate dependency entries during REINDEX CONCURRENTLY. The notes limit the observed consequence to bloat in pg_depend. That is worth distinguishing from corruption of index contents, since the release identifies excess catalog entries rather than an incorrect query result for this particular bug.
A failed rebuild must leave an object removable
Partition indexes have an additional failure-path repair. A failed concurrent reindex could leave the index's relispartition flag in the wrong state. A subsequent DROP INDEX then failed.
This is an administrative consequence that can outlast the original failed command. The operator needs a way to remove or replace an index after the rebuild stops. Incorrect catalog state obstructs that recovery even if the initial command has already reported its failure.
Partitioning receives other repairs in 12.1, including index creation when the parent contains dropped columns and automatic index removal when indexed columns are dropped. These cases concern how catalog descriptions remain aligned as the schema evolves.
The release also fixes SET CONSTRAINTS ... DEFERRED on partitioned tables. It previously complained incorrectly about missing triggers. The repair matters because declaring a constraint's timing is an SQL operation whose implementation must account for the partition structure.
My preference is for maintenance releases to explain these distinctions. An index-content problem, an unreleased lock and a catalog flag that blocks cleanup need different responses. The notes describe the actual failure modes rather than grouping them under an unexplained recommendation to rebuild everything.
A bit string can have invisible state
The bit-string right-shift fix concerns unused padding in the final byte when the bit length is not a multiple of eight. The operator failed to zero that padding. Most operations did not expose it, but comparison expected those unused bits to be zero.
This means two values that appear to contain the same meaningful bits could compare unexpectedly because their internal padding differed. The problem is in the representation invariant. Comparison code relies on a producer preserving that invariant when it constructs the value.
The release notes give a repair for values already stored in a table. Applying bitwise negation twice restores the logical value while normalizing the padding. For an affected table and bit-string column, the documented form is as follows.
UPDATE mytab
SET bitcol = ~(~bitcol)
WHERE bitcol != ~(~bitcol);
The table and column names are placeholders for the affected objects. This is separate from installing the maintenance binaries, since a corrected operator prevents new malformed results but does not rewrite every stored value produced earlier.
Crash recovery must ignore archive-only settings
Recovery settings receive another targeted repair. PostgreSQL 12 allows settings such as restore_command and recovery_min_apply_delay in postgresql.conf. Their presence there can make them available during ordinary crash recovery, where honoring them is undesirable.
Version 12.1 ignores restore_command, recovery_end_command and recovery_min_apply_delay until crash recovery has completed. The notes also repair archive recovery with an apply delay and remove temporary WAL and history files when archive recovery finishes.
These changes preserve distinctions between recovery modes even though their configuration can now share a file. A setting's availability in the parser does not establish that it should influence every recovery path. The maintenance update requires no dump and restore for existing PostgreSQL 12 installations, while the stored bit-string repair remains a separate operation for data affected by the documented padding bug.