PostgreSQL 12.3 fixes installer lookup and generated values
The May update fixes a Windows installer privilege problem and repairs generated-column value handling. Its maintenance changes also preserve dependencies during failed index rebuilds and database dumps.
An installer can cross a privilege boundary before the database starts. PostgreSQL's Windows installer invoked system programs without fully qualified executable paths. A file in the installer's loading directory or current working directory could take precedence over the intended program. The CVE-2020-10733 advisory explains that someone able to place a file in those directories could execute code with the installer's administrative rights.
That is a packaging vulnerability with a specific prerequisite. The attacker needs write access to a directory involved in executable lookup. It does not describe a SQL command that a remote database user can submit to obtain those rights. The advisory identifies fixes in 12.3 and the corresponding supported maintenance branches, published on May 14. Keeping the affected component explicit helps explain which administrative activity creates the exposure.
I default to PostgreSQL for relational work, but that preference includes the responsibility to understand its installation tools. Database security starts before a server accepts connections. An installer executing with elevated rights must resolve the programs it intends to run without delegating that choice to someone who can populate a working directory.
The May maintenance release has broader consequences
The release announcement accompanies that installer repair with more than 75 bug fixes. The server changes matter on installations that never run the Windows installer. In particular, generated columns could produce a crash or corrupted data when an expression returned an existing pass-by-reference value unchanged.
The announcement also says this is a cumulative minor update. Applying it does not require a database dump and reload or pg_upgrade. Replacing the binaries after shutdown installs the maintenance changes. A cluster that skipped earlier maintenance releases still needs the earlier release instructions, because an update can prevent a defect without reconstructing every database object or value previously affected by it.
This distinction is particularly useful here. The installer vulnerability concerns how an administrative program locates executables. The generated-column repair concerns values the server stores. Both belong in the maintenance decision, but their prerequisites and possible consequences differ. A platform-based reading of the security headline alone would miss the server-side reason to update.
Stored expressions still need independent values
The generated-column documentation shipped with 12.3 describes a stored generated column as a value computed when a row is written. PostgreSQL implements the stored form, and its syntax requires the STORED keyword. The expression uses the current row and immutable functions. Applications cannot override the generated value as if it were an ordinary input column.
For example, a schema can express a unit conversion directly:
CREATE TABLE measurements (
height_cm numeric,
height_in numeric
GENERATED ALWAYS AS (height_cm / 2.54) STORED
);
This example illustrates the documented calculation model. It is not a reproduction of the corruption bug. A generated expression differs from a default because the generated value changes when the row changes, and its expression can refer to another column in that row. A default supplies an initial value when insertion does not supply one.
I value putting this kind of relationship in the schema. It makes the database responsible for maintaining the derived value under its documented rules. That responsibility includes expressions whose result happens to reuse an input value, because a logically unchanged result is still a value that must remain valid when the executor constructs the stored row.
The patch copies the result
David Rowley's April 18 generated-column patch makes the implementation issue concrete. After evaluating a generated expression, the executor copies a non-null result with datumCopy before putting it into the values array. The added comment explains that the executor cannot assume where the memory for a pass-by-reference result resides.
The regression case uses a varchar column and a generated varchar column that directly references it. It inserts an ordinary string and a null, then reads the rows. Such a duplicate column looks unnecessary as an application schema, but it isolates the ownership problem. The release notes explain that a more useful expression can encounter the same condition through a function that sometimes returns its input unchanged.
The patch message also provides a way to assess suspected existing damage. After upgrading, it recommends a base backup restored onto an offline server, followed by comparing generated values with newly evaluated expressions. That procedure addresses stored contents already written by the old executor. Installing the corrected executor does not itself establish that those earlier values match their expressions.
Dependencies survive maintenance operations
Another repair concerns cancellation of concurrent index rebuilding. Michael Paquier's dependency-handling patch describes an old index left behind after cancellation following the index swap. Its dependency records could be missing, so dropping the parent table would fail to remove that index.
The repair exchanges dependencies in both directions between the old and new indexes. An invalid old index remaining after failure or cancellation can then retain the relationships needed for subsequent deletion. That is a useful property of an interrupted maintenance operation. The database must preserve enough information to manage the objects left behind, even when the requested rebuild does not finish normally.
The 12.3 release notes also describe pg_dump learning to preserve dependencies added by ALTER commands with DEPENDS ON EXTENSION. Previously, dump and restore or pg_upgrade could forget those relationships. The pg_dump change emits the required ALTER statements from the recorded extension dependencies. A logical reconstruction consequently needs to preserve lifecycle relationships as well as object definitions and table contents.
The implementation queries pg_depend and pg_extension for the relevant extension names, then appends an ALTER statement for each relationship. That approach reconstructs an explicit declaration from the catalogs. It does not try to infer the dependency by reading the function body or examining application queries. The distinction matters for restoration because an object can still exist and accept queries while having different behaviour when its associated extension is eventually removed.