Thread

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

    Ben Caspi <benc@aidoc.com> — 2026-02-18T13:17:50Z

    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>*
    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>*
    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/>
    
    [image: twitter] <https://twitter.com/aidocmed>
    
    [image: App Banner Image] <https://www.aidoc.com/book-a-demo/>
    
  2. Re: PostgreSQL MSI ignores --datadir flag during minor upgrade on Windows

    Sandeep Thakkar <sandeep.thakkar@enterprisedb.com> — 2026-02-25T16:07:36Z

    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>*
    > 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>*
    > 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/>
    >
    > [image: twitter] <https://twitter.com/aidocmed>
    >
    > [image: App Banner Image] <https://www.aidoc.com/book-a-demo/>
    >
    >
    >
    
    
    -- 
    Sandeep Thakkar