--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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;
+ }
+}
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * Routines 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
+ *
+ * src/include/fe_utils/version.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_VERSION_H
+#define PG_VERSION_H
+
+/*
+ * Retrieve the version major number, useful for major version checks
+ * based on PG_MAJORVERSION_NUM.
+ */
+#define GET_PG_MAJORVERSION_NUM(v) ((v) / 10000)
+
+extern uint32 get_pg_version(const char *datadir, char **version_str);
+
+#endif /* PG_VERSION_H */