PostgreSQL MSI ignores --datadir flag during minor upgrade on Windows

Started by Ben Caspiabout 2 months ago2 messagesbugs
Jump to latest
#1Ben Caspi
benc@aidoc.com

Hello,

Recently we tried to upgrade a client machine's PostgreSQL version from
15.13 to 15.16.
We often upgrade our client machines from versions 9/13 to 15 without
encountering any issues.
However, during this upgrade (15.13 --> 15.16) we've noticed that
post-upgrade the PostgreSQL service assigned data directory changed to the
default value "C:\Program Files\PostgreSQL\15\data".

Our client's data directory prior to the upgrade was
"F:\AidocData\PostgreSQL\15\data". This change caused data to be written to
the wrong location until we found the issue.

This is the command we use for the upgrade:

Start-Process $installer_exe -ArgumentList "--unattendedmodeui minimal
--mode unattended --superaccount $POSTGRES_ROOT_USER --superpassword
$POSTGRES_ROOT_USER_PWD --serverport $port --datadir `"$data_dir`" --locale
`"$locale_name`"" -Wait

I looked into your codebase and found that during an upgrade the installer
defaults to the Registry value for data directory and ignores the --datadir
flag I provided in my command.

In server/pgserver.xml.in, in the server component’s
preInstallationActionList:

*pgserver.xml.in <http://pgserver.xml.in&gt;*
Lines 1142-1153

<!-- Set datadir if an existing installation is found -->

<setInstallerVariable>
<name>datadir</name>
<value>${iDataDirectory}</value>
<ruleList>
<stringTest>
<text>${iDataDirectory}</text>
<type>not_empty</type>
</stringTest>
<isFalse value="${extract_mode}"/>
</ruleList>
</setInstallerVariable>

*iDataDirectory is read from the registry here:*
*pgserver.xml.in <http://pgserver.xml.in&gt;*
Lines 1003-1008

<!-- Get the existing data directory. -->

<registryGet>
<name>Data Directory</name>

<key>HKEY_LOCAL_MACHINE\SOFTWARE\PostgreSQL\Installations\postgresql${service_suffix}-${product_version}</key>
<variable>iDataDirectory</variable>
</registryGet>

*What goes wrong:*
When passing --datadir "F:\AidocData\PostgreSQL\15\data" on the command
line, the wizard sets datadir = "F:\AidocData\PostgreSQL\15\data".

Later, in preInstallationActionList, the installer reads iDataDirectory
from the registry.
If iDataDirectory is not empty, it overwrites datadir with that value.

1. There is no check that the user explicitly provided --datadir, so the
CLI value is ignored.

If the registry still has the old default path (e.g. C:\Program
Files\PostgreSQL\15\data), the service ends up re-registered with that path
instead of F:\AidocData\PostgreSQL\15\data.
When the registry can be wrong

- Initial install used the default data directory, then data was moved
to F:\AidocData\PostgreSQL\15\data and the service was updated manually,
but the PostgreSQL registry key was not.
- A previous install or reinstall wrote the default path to the registry.
- Any other case where the registry value does not match the actual data
location.

*Fix*
Only use the registry value when the user has not provided --datadir on the
command line. For example, add a condition so that datadir is set from
iDataDirectory only when datadir is empty:

<!-- Set datadir if an existing installation is found (only when user

didn't provide --datadir) -->
<setInstallerVariable>
<name>datadir</name>
<value>${iDataDirectory}</value>
<ruleList>
<stringTest>
<text>${iDataDirectory}</text>
<type>not_empty</type>
</stringTest>
<stringTest>
<text>${datadir}</text>
<type>empty</type>
</stringTest>
<isFalse value="${extract_mode}"/>
</ruleList>
</setInstallerVariable>

This keeps the current behavior when --datadir is not passed, but ensures
that an explicit --datadir is not overridden by the registry.

Please consider investigating this issue and its solution.
If I misunderstood anything please let me know. Thanks!
--

[image: photo]

Ben Caspi
DevOps Engineer

www.aidoc.com | benc@aidoc.com

[image: linkedin] <https://www.linkedin.com/company/aidoc/&gt;

[image: twitter] <https://twitter.com/aidocmed&gt;

[image: App Banner Image] <https://www.aidoc.com/book-a-demo/&gt;

#2Sandeep Thakkar
sandeep.thakkar@enterprisedb.com
In reply to: Ben Caspi (#1)
Re: PostgreSQL MSI ignores --datadir flag during minor upgrade on Windows

On Fri, Feb 20, 2026 at 1:51 PM Ben Caspi <benc@aidoc.com> wrote:

Hello,

Recently we tried to upgrade a client machine's PostgreSQL version from
15.13 to 15.16.
We often upgrade our client machines from versions 9/13 to 15 without
encountering any issues.
However, during this upgrade (15.13 --> 15.16) we've noticed that
post-upgrade the PostgreSQL service assigned data directory changed to the
default value "C:\Program Files\PostgreSQL\15\data".

Our client's data directory prior to the upgrade was
"F:\AidocData\PostgreSQL\15\data". This change caused data to be written to
the wrong location until we found the issue.

This is the command we use for the upgrade:

Start-Process $installer_exe -ArgumentList "--unattendedmodeui minimal
--mode unattended --superaccount $POSTGRES_ROOT_USER --superpassword
$POSTGRES_ROOT_USER_PWD --serverport $port --datadir `"$data_dir`" --locale
`"$locale_name`"" -Wait

I looked into your codebase and found that during an upgrade the installer
defaults to the Registry value for data directory and ignores the --datadir
flag I provided in my command.

That behaviour is by design. The command-line options override the default

values only during the new installation. In upgrade mode, the registry
values are the source of truth for the installer.

In server/pgserver.xml.in, in the server component’s

preInstallationActionList:

*pgserver.xml.in <http://pgserver.xml.in&gt;*
Lines 1142-1153

<!-- Set datadir if an existing installation is found -->

<setInstallerVariable>
<name>datadir</name>
<value>${iDataDirectory}</value>
<ruleList>
<stringTest>
<text>${iDataDirectory}</text>
<type>not_empty</type>
</stringTest>
<isFalse value="${extract_mode}"/>
</ruleList>
</setInstallerVariable>

*iDataDirectory is read from the registry here:*
*pgserver.xml.in <http://pgserver.xml.in&gt;*
Lines 1003-1008

<!-- Get the existing data directory. -->

<registryGet>
<name>Data Directory</name>

<key>HKEY_LOCAL_MACHINE\SOFTWARE\PostgreSQL\Installations\postgresql${service_suffix}-${product_version}</key>
<variable>iDataDirectory</variable>
</registryGet>

*What goes wrong:*
When passing --datadir "F:\AidocData\PostgreSQL\15\data" on the command
line, the wizard sets datadir = "F:\AidocData\PostgreSQL\15\data".

Later, in preInstallationActionList, the installer reads iDataDirectory
from the registry.
If iDataDirectory is not empty, it overwrites datadir with that value.

1. There is no check that the user explicitly provided --datadir, so
the CLI value is ignored.

If the registry still has the old default path (e.g. C:\Program
Files\PostgreSQL\15\data), the service ends up re-registered with that path
instead of F:\AidocData\PostgreSQL\15\data.
When the registry can be wrong

- Initial install used the default data directory, then data was moved
to F:\AidocData\PostgreSQL\15\data and the service was updated manually,
but the PostgreSQL registry key was not.

This is the problem for the installer. If you change the paths later that

were given during installation, you must also change the registry key value
for the installer to know.

- A previous install or reinstall wrote the default path to the
registry.
- Any other case where the registry value does not match the actual
data location.

*Fix*
Only use the registry value when the user has not provided --datadir on
the command line. For example, add a condition so that datadir is set from
iDataDirectory only when datadir is empty:

<!-- Set datadir if an existing installation is found (only when user

didn't provide --datadir) -->
<setInstallerVariable>
<name>datadir</name>
<value>${iDataDirectory}</value>
<ruleList>
<stringTest>
<text>${iDataDirectory}</text>
<type>not_empty</type>
</stringTest>
<stringTest>
<text>${datadir}</text>
<type>empty</type>
</stringTest>
<isFalse value="${extract_mode}"/>
</ruleList>
</setInstallerVariable>

This keeps the current behavior when --datadir is not passed, but ensures
that an explicit --datadir is not overridden by the registry.

Thanks, but this change in behaviour constitutes a design change and

should probably also apply to other options. We'll evaluate this further.
But for now, the fix is to update your registry keys to deflect the change
you made to the datadir.

Please consider investigating this issue and its solution.
If I misunderstood anything please let me know. Thanks!
--

[image: photo]

Ben Caspi
DevOps Engineer

www.aidoc.com | benc@aidoc.com

[image: linkedin] <https://www.linkedin.com/company/aidoc/&gt;

[image: twitter] <https://twitter.com/aidocmed&gt;

[image: App Banner Image] <https://www.aidoc.com/book-a-demo/&gt;

--
Sandeep Thakkar