relaxed version check

eag/release-13.2/relax-test
eaydingol 2025-11-17 14:14:03 +03:00
parent f69a803fe5
commit 5b2eeeadda
4 changed files with 105 additions and 3 deletions

View File

@ -162,6 +162,8 @@ static bool CitusColumnarHasBeenLoadedInternal(void);
static bool CitusColumnarHasBeenLoaded(void); static bool CitusColumnarHasBeenLoaded(void);
static bool CheckCitusColumnarVersion(int elevel); static bool CheckCitusColumnarVersion(int elevel);
static bool MajorVersionsCompatibleColumnar(char *leftVersion, char *rightVersion); static bool MajorVersionsCompatibleColumnar(char *leftVersion, char *rightVersion);
static bool MinorVersionsCompatibleRelaxedColumnar(char *leftVersion, char *rightVersion);
static int ParseVersionComponent(const char *version, char **endPtr);
/* global variables for CheckCitusColumnarVersion */ /* global variables for CheckCitusColumnarVersion */
static bool extensionLoadedColumnar = false; static bool extensionLoadedColumnar = false;
@ -2939,7 +2941,7 @@ CheckInstalledVersionColumnar(int elevel)
char *installedVersion = InstalledExtensionVersionColumnar(); char *installedVersion = InstalledExtensionVersionColumnar();
if (!MajorVersionsCompatibleColumnar(installedVersion, CITUS_EXTENSIONVERSION)) if (!MinorVersionsCompatibleRelaxedColumnar(installedVersion, CITUS_EXTENSIONVERSION))
{ {
ereport(elevel, (errmsg("loaded Citus library version differs from installed " ereport(elevel, (errmsg("loaded Citus library version differs from installed "
"extension version"), "extension version"),
@ -2998,6 +3000,55 @@ MajorVersionsCompatibleColumnar(char *leftVersion, char *rightVersion)
} }
/*
* ParseVersionComponent parses the integer at the current position and
* advances endPtr past the parsed digits to the next character.
*/
static int
ParseVersionComponent(const char *version, char **endPtr)
{
errno = 0;
long int val = strtol(version, endPtr, 10);
if (errno == ERANGE || val > INT_MAX || val < INT_MIN)
{
ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("Invalid integer in version string")));
}
return (int) val;
}
/*
* MinorVersionsCompatibleRelaxedColumnar checks if two versions have the same major
* version and their minor versions differ by at most 1. The schema version
* (after '-') is ignored. Returns true if compatible, false otherwise.
*
* Version format expected: "major.minor-schema" (e.g., "13.1-2")
*/
bool
MinorVersionsCompatibleRelaxedColumnar(char *leftVersion, char *rightVersion)
{
char *leftSep;
char *rightSep;
int leftMajor = ParseVersionComponent(leftVersion, &leftSep);
int rightMajor = ParseVersionComponent(rightVersion, &rightSep);
if (leftMajor != rightMajor)
{
return false;
}
int leftMinor = (*leftSep == '.') ? ParseVersionComponent(leftSep + 1, &leftSep) : 0;
int rightMinor = (*rightSep == '.') ? ParseVersionComponent(rightSep + 1, &rightSep) :
0;
int diff = leftMinor - rightMinor;
return diff >= -1 && diff <= 1;
}
/* /*
* AvailableExtensionVersion returns the Citus version from citus.control file. It also * AvailableExtensionVersion returns the Citus version from citus.control file. It also
* saves the result, thus consecutive calls to CitusExtensionAvailableVersion will * saves the result, thus consecutive calls to CitusExtensionAvailableVersion will

View File

@ -80,7 +80,7 @@ ErrorIfUnstableCreateOrAlterExtensionStmt(Node *parseTree)
if (newExtensionVersion != NULL) if (newExtensionVersion != NULL)
{ {
/* explicit version provided in CREATE or ALTER EXTENSION UPDATE; verify */ /* explicit version provided in CREATE or ALTER EXTENSION UPDATE; verify */
if (!MajorVersionsCompatible(newExtensionVersion, CITUS_EXTENSIONVERSION)) if (!MinorVersionsCompatibleRelaxed(newExtensionVersion, CITUS_EXTENSIONVERSION))
{ {
ereport(ERROR, (errmsg("specified version incompatible with loaded " ereport(ERROR, (errmsg("specified version incompatible with loaded "
"Citus library"), "Citus library"),

View File

@ -339,6 +339,7 @@ static Oid DistAuthinfoRelationId(void);
static Oid DistAuthinfoIndexId(void); static Oid DistAuthinfoIndexId(void);
static Oid DistPoolinfoRelationId(void); static Oid DistPoolinfoRelationId(void);
static Oid DistPoolinfoIndexId(void); static Oid DistPoolinfoIndexId(void);
static int ParseVersionComponent(const char *version, char **endPtr);
/* exports for SQL callable functions */ /* exports for SQL callable functions */
PG_FUNCTION_INFO_V1(citus_dist_partition_cache_invalidate); PG_FUNCTION_INFO_V1(citus_dist_partition_cache_invalidate);
@ -2440,7 +2441,7 @@ CheckInstalledVersion(int elevel)
char *installedVersion = InstalledExtensionVersion(); char *installedVersion = InstalledExtensionVersion();
if (!MajorVersionsCompatible(installedVersion, CITUS_EXTENSIONVERSION)) if (!MinorVersionsCompatibleRelaxed(installedVersion, CITUS_EXTENSIONVERSION))
{ {
ereport(elevel, (errmsg("loaded Citus library version differs from installed " ereport(elevel, (errmsg("loaded Citus library version differs from installed "
"extension version"), "extension version"),
@ -2518,6 +2519,55 @@ MajorVersionsCompatible(char *leftVersion, char *rightVersion)
} }
/*
* ParseVersionComponent parses the integer at the current position and
* advances endPtr past the parsed digits to the next character.
*/
static int
ParseVersionComponent(const char *version, char **endPtr)
{
errno = 0;
long int val = strtol(version, endPtr, 10);
if (errno == ERANGE || val > INT_MAX || val < INT_MIN)
{
ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("Invalid integer in version string")));
}
return (int) val;
}
/*
* MinorVersionsCompatibleRelaxed checks if two versions have the same major
* version and their minor versions differ by at most 1. The schema version
* (after '-') is ignored. Returns true if compatible, false otherwise.
*
* Version format expected: "major.minor-schema" (e.g., "13.1-2")
*/
bool
MinorVersionsCompatibleRelaxed(char *leftVersion, char *rightVersion)
{
char *leftSep;
char *rightSep;
int leftMajor = ParseVersionComponent(leftVersion, &leftSep);
int rightMajor = ParseVersionComponent(rightVersion, &rightSep);
if (leftMajor != rightMajor)
{
return false;
}
int leftMinor = (*leftSep == '.') ? ParseVersionComponent(leftSep + 1, &leftSep) : 0;
int rightMinor = (*rightSep == '.') ? ParseVersionComponent(rightSep + 1, &rightSep) :
0;
int diff = leftMinor - rightMinor;
return diff >= -1 && diff <= 1;
}
/* /*
* AvailableExtensionVersion returns the Citus version from citus.control file. It also * AvailableExtensionVersion returns the Citus version from citus.control file. It also
* saves the result, thus consecutive calls to CitusExtensionAvailableVersion will * saves the result, thus consecutive calls to CitusExtensionAvailableVersion will

View File

@ -216,6 +216,7 @@ extern bool CheckCitusVersion(int elevel);
extern bool CheckAvailableVersion(int elevel); extern bool CheckAvailableVersion(int elevel);
extern bool InstalledAndAvailableVersionsSame(void); extern bool InstalledAndAvailableVersionsSame(void);
extern bool MajorVersionsCompatible(char *leftVersion, char *rightVersion); extern bool MajorVersionsCompatible(char *leftVersion, char *rightVersion);
extern bool MinorVersionsCompatibleRelaxed(char *leftVersion, char *rightVersion);
extern void ErrorIfInconsistentShardIntervals(CitusTableCacheEntry *cacheEntry); extern void ErrorIfInconsistentShardIntervals(CitusTableCacheEntry *cacheEntry);
extern void EnsureModificationsCanRun(void); extern void EnsureModificationsCanRun(void);
extern void EnsureModificationsCanRunOnRelation(Oid relationId); extern void EnsureModificationsCanRunOnRelation(Oid relationId);