Skip to content

Commit 0151888

Browse files
committed
feat(dbconn): Map HDW 3.x versions to GPDB for compatibility
This change introduces a version mapping mechanism to address compatibility issues between HashData Warehouse 3.x and Greenplum Database (GPDB). Previously, features designed for specific GPDB versions (e.g., 6.x) could not be enabled on compatible HDW instances (e.g., 3.x) because version checks would fail due to the different versioning schemes. The new `getComparableSemVer` function intelligently maps versions: - When the target of a version comparison is GPDB 4.0.0 or greater, it translates the HDW version to its GPDB equivalent (e.g., HDW 3.x is treated as GPDB 6.x). - For comparisons against target versions less than 4.0.0, the native HDW version is used, preserving HDW-specific logic. This allows HDW 3.x to correctly pass compatibility checks for GPDB features while maintaining its own version identity for other checks. The `IsGPDB()` check has also been updated to treat HDW as part of the GPDB family.
1 parent abe6d79 commit 0151888

2 files changed

Lines changed: 156 additions & 4 deletions

File tree

internal/dbconn/version.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dbconn
22

33
import (
44
"regexp"
5+
"strconv"
56
"strings"
67

78
"github.com/greenplum-db/gp-common-go-libs/gplog"
@@ -173,19 +174,55 @@ func (dbversion GPDBVersion) StringToSemVerRange(versionStr string) semver.Range
173174
return validRange
174175
}
175176

177+
// getComparableSemVer returns a version object suitable for comparison.
178+
// It maps HDW versions to corresponding GPDB major versions for compatibility checks,
179+
// but only when comparing against a target version that appears to be a GPDB version (e.g., major version >= 4).
180+
// This allows for native version checks for HDW-specific features (e.g., AtLeast("3.1.0")).
181+
func (dbversion GPDBVersion) getComparableSemVer(targetVersion string) semver.Version {
182+
v := dbversion.SemVer
183+
184+
if !dbversion.IsHDW() {
185+
return v
186+
}
187+
188+
// Heuristic to decide if we're comparing against a GPDB version.
189+
// We only map HDW versions if the target comparison version is for GPDB 4 or greater.
190+
targetMajorStr := strings.Split(targetVersion, ".")[0]
191+
targetMajor, err := strconv.Atoi(targetMajorStr)
192+
// If targetVersion is not a valid number string, we don't map.
193+
if err != nil {
194+
return v
195+
}
196+
197+
// Based on product versioning, HDW has a max major version of 3,
198+
// while GPDB has a min major version of 4. Therefore, any target
199+
// version >= 4 is considered a check against GPDB features.
200+
if targetMajor >= 4 {
201+
switch v.Major {
202+
// HDW 2.x is compatible with GPDB 5.x
203+
case 2:
204+
v.Major = 5
205+
// HDW 3.x is compatible with GPDB 6.x
206+
case 3:
207+
v.Major = 6
208+
}
209+
}
210+
return v
211+
}
212+
176213
func (dbversion GPDBVersion) Before(targetVersion string) bool {
177214
validRange := dbversion.StringToSemVerRange("<" + targetVersion)
178-
return validRange(dbversion.SemVer)
215+
return validRange(dbversion.getComparableSemVer(targetVersion))
179216
}
180217

181218
func (dbversion GPDBVersion) AtLeast(targetVersion string) bool {
182219
validRange := dbversion.StringToSemVerRange(">=" + targetVersion)
183-
return validRange(dbversion.SemVer)
220+
return validRange(dbversion.getComparableSemVer(targetVersion))
184221
}
185222

186223
func (dbversion GPDBVersion) Is(targetVersion string) bool {
187224
validRange := dbversion.StringToSemVerRange("==" + targetVersion)
188-
return validRange(dbversion.SemVer)
225+
return validRange(dbversion.getComparableSemVer(targetVersion))
189226
}
190227

191228
func (dbversion GPDBVersion) IsCBDB() bool {
@@ -205,7 +242,8 @@ func (dbversion GPDBVersion) IsCBDBFamily() bool {
205242
}
206243

207244
func (dbversion GPDBVersion) IsGPDB() bool {
208-
return dbversion.Type == GPDB
245+
// we treat HDW as GPDB for now
246+
return dbversion.Type == GPDB || dbversion.Type == HDW
209247
}
210248

211249
func (dbversion GPDBVersion) IsHDW() bool {

internal/dbconn/version_test.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package dbconn_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/blang/semver"
7+
"github.com/cloudberrydb/cbcopy/internal/dbconn"
8+
9+
. "github.com/onsi/ginkgo/v2"
10+
. "github.com/onsi/gomega"
11+
)
12+
13+
func TestVersion(t *testing.T) {
14+
RegisterFailHandler(Fail)
15+
RunSpecs(t, "DBConn Version HDW Mapping Suite")
16+
}
17+
18+
var _ = Describe("internal/dbconn/version HDW Mapping", func() {
19+
20+
// --- Test Data Setup ---
21+
// Represents an HDW 2.x database, which should be treated as GPDB 5.x for comparison.
22+
hdw2_5_0 := dbconn.GPDBVersion{
23+
VersionString: "PostgreSQL 9.4.26 (HashData Warehouse 2.5.0)",
24+
SemVer: semver.MustParse("2.5.0"),
25+
Type: dbconn.HDW,
26+
}
27+
28+
// Represents an HDW 3.x database, which should be treated as GPDB 6.x for comparison.
29+
hdw3_5_0 := dbconn.GPDBVersion{
30+
VersionString: "PostgreSQL 9.4.26 (HashData Warehouse 3.5.0)",
31+
SemVer: semver.MustParse("3.5.0"),
32+
Type: dbconn.HDW,
33+
}
34+
35+
// Represents a standard GPDB database to ensure its logic is not affected.
36+
gpdb7_1_0 := dbconn.GPDBVersion{
37+
VersionString: "PostgreSQL 12.12 (Greenplum Database 7.1.0)",
38+
SemVer: semver.MustParse("7.1.0"),
39+
Type: dbconn.GPDB,
40+
}
41+
42+
Describe("AtLeast", func() {
43+
Context("with an HDW 3.x version (maps to GPDB 6.x)", func() {
44+
It("should pass native version checks (target < 4)", func() {
45+
Expect(hdw3_5_0.AtLeast("3.1.0")).To(BeTrue())
46+
Expect(hdw3_5_0.AtLeast("3.6.0")).To(BeFalse())
47+
})
48+
It("should pass mapped version checks (target >= 4)", func() {
49+
Expect(hdw3_5_0.AtLeast("4.0.0")).To(BeTrue())
50+
Expect(hdw3_5_0.AtLeast("6.0.0")).To(BeTrue())
51+
Expect(hdw3_5_0.AtLeast("7.0.0")).To(BeFalse())
52+
})
53+
})
54+
55+
Context("with an HDW 2.x version (maps to GPDB 5.x)", func() {
56+
It("should pass native version checks (target < 4)", func() {
57+
Expect(hdw2_5_0.AtLeast("2.1.0")).To(BeTrue())
58+
})
59+
It("should pass mapped version checks (target >= 4)", func() {
60+
Expect(hdw2_5_0.AtLeast("5.0.0")).To(BeTrue())
61+
Expect(hdw2_5_0.AtLeast("6.0.0")).To(BeFalse())
62+
})
63+
})
64+
65+
Context("with a standard GPDB version (no mapping)", func() {
66+
It("should behave normally", func() {
67+
Expect(gpdb7_1_0.AtLeast("7.0.0")).To(BeTrue())
68+
Expect(gpdb7_1_0.AtLeast("8.0.0")).To(BeFalse())
69+
})
70+
})
71+
})
72+
73+
Describe("Is", func() {
74+
Context("with an HDW 3.x version (maps to GPDB 6.x)", func() {
75+
It("should be true for its native major version", func() {
76+
Expect(hdw3_5_0.Is("3")).To(BeTrue())
77+
})
78+
It("should be true for its mapped major version", func() {
79+
Expect(hdw3_5_0.Is("6")).To(BeTrue())
80+
})
81+
It("should be false for other major versions", func() {
82+
Expect(hdw3_5_0.Is("5")).To(BeFalse())
83+
Expect(hdw3_5_0.Is("7")).To(BeFalse())
84+
})
85+
})
86+
87+
Context("with a standard GPDB version (no mapping)", func() {
88+
It("should behave normally", func() {
89+
Expect(gpdb7_1_0.Is("7")).To(BeTrue())
90+
Expect(gpdb7_1_0.Is("6")).To(BeFalse())
91+
})
92+
})
93+
})
94+
95+
Describe("Before", func() {
96+
Context("with an HDW 3.x version (maps to GPDB 6.x)", func() {
97+
It("should pass native version checks (target < 4)", func() {
98+
Expect(hdw3_5_0.Before("3.6.0")).To(BeTrue())
99+
Expect(hdw3_5_0.Before("3.5.0")).To(BeFalse())
100+
})
101+
It("should pass mapped version checks (target >= 4)", func() {
102+
Expect(hdw3_5_0.Before("7.0.0")).To(BeTrue())
103+
Expect(hdw3_5_0.Before("6.0.0")).To(BeFalse())
104+
})
105+
})
106+
107+
Context("with a standard GPDB version (no mapping)", func() {
108+
It("should behave normally", func() {
109+
Expect(gpdb7_1_0.Before("8.0.0")).To(BeTrue())
110+
Expect(gpdb7_1_0.Before("7.0.0")).To(BeFalse())
111+
})
112+
})
113+
})
114+
})

0 commit comments

Comments
 (0)