PostgreSQL MSI ignores --datadir flag during minor upgrade on Windows - Mailing list pgsql-bugs
| From | Ben Caspi |
|---|---|
| Subject | PostgreSQL MSI ignores --datadir flag during minor upgrade on Windows |
| Date | |
| Msg-id | CABv1Mx7basCao7xTOjNs0imLwm98YUgRcOupbMwNGaPVLKSjaw@mail.gmail.com Whole thread Raw |
| Responses |
Re: PostgreSQL MSI ignores --datadir flag during minor upgrade on Windows
|
| List | pgsql-bugs |
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
Lines 1142-1153
iDataDirectory is read from the registry here:
pgserver.xml.in
Lines 1003-1008
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.
pgserver.xml.in
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
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.
- 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
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:
This keeps the current behavior when --datadir is not passed, but ensures that an explicit --datadir is not overridden by the registry.
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!
pgsql-bugs by date:

