Files
postgresql/src/fe_utils/version.c
Michael Paquier cd0be131ba Introduce frontend API able to retrieve the contents of PG_VERSION
get_pg_version() is able to return a version number, that can be used
for comparisons based on PG_VERSION_NUM.  A macro is added to convert
the result to a major version number, to work with PG_MAJORVERSION_NUM.

It is possible to pass to the routine an optional argument, where the
contents retrieved from PG_VERSION are saved.  This requirement matters
for some of the frontend code (one example: pg_upgrade wants that for
tablespace paths with a version number strictly older than v10).

This will be used by a set of follow-up patches, to be consumed in
various frontend tools that duplicate a logic similar to do what this
new routine does, like:
- pg_resetwal
- pg_combinebackup
- pg_createsubscriber
- pg_upgrade

This routine supports both the post-v10 version number and the older
flavor (aka 9.6), as required at least by pg_upgrade.

Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Discussion: https://postgr.es/m/aOiirvWJzwdVCXph@paquier.xyz
2025-10-14 16:20:42 +09:00

87 lines
2.2 KiB
C

/*-------------------------------------------------------------------------
*
* version.c
* Routine to retrieve information of PG_VERSION
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/fe_utils/version.c
*
*-------------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include <sys/stat.h>
#include "common/logging.h"
#include "fe_utils/version.h"
/*
* Assumed maximum size of PG_VERSION. This should be more than enough for
* any version numbers that need to be handled.
*/
#define PG_VERSION_MAX_SIZE 64
/*
* get_pg_version
*
* Retrieve the major version number of the given data folder, from
* PG_VERSION. The result returned is a version number, that can be used
* for comparisons based on PG_VERSION_NUM. For example, if PG_VERSION
* contains "18\n", this function returns 180000.
*
* This supports both the pre-v10 and the post-v10 version numbering.
*
* Optionally, "version_str" can be specified to store the contents
* retrieved from PG_VERSION. It is allocated by this routine; the
* caller is responsible for pg_free()-ing it.
*/
uint32
get_pg_version(const char *datadir, char **version_str)
{
FILE *version_fd;
char ver_filename[MAXPGPATH];
char buf[PG_VERSION_MAX_SIZE];
int v1 = 0,
v2 = 0;
struct stat st;
snprintf(ver_filename, sizeof(ver_filename), "%s/PG_VERSION",
datadir);
if ((version_fd = fopen(ver_filename, "r")) == NULL)
pg_fatal("could not open version file \"%s\": %m", ver_filename);
if (fstat(fileno(version_fd), &st) != 0)
pg_fatal("could not stat file \"%s\": %m", ver_filename);
if (st.st_size > PG_VERSION_MAX_SIZE)
pg_fatal("file \"%s\" is too large", ver_filename);
if (fscanf(version_fd, "%63s", buf) == 0 ||
sscanf(buf, "%d.%d", &v1, &v2) < 1)
pg_fatal("could not parse version file \"%s\"", ver_filename);
fclose(version_fd);
if (version_str)
{
*version_str = pg_malloc(PG_VERSION_MAX_SIZE);
memcpy(*version_str, buf, st.st_size);
}
if (v1 < 10)
{
/* pre-v10 style, e.g. 9.6.1 */
return v1 * 10000 + v2 * 100;
}
else
{
/* post-v10 style, e.g. 10.1 */
return v1 * 10000;
}
}