You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudberry.apache.org by dj...@apache.org on 2026/10/23 02:54:41 UTC
(cloudberry-backup) branch main updated (5db21713 -> 8b045de5)
This is an automated email from the ASF dual-hosted git repository.
tuhaihe pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry-backup.git
from 5db21713 Enable GitHub auto-merge for pull requests
new ee59c2cd Adapt tests to the PG16 kernel of Cloudberry main
new 5d90463f CI: test against both Cloudberry REL_2_STABLE and main
new 8b045de5 Fix nondeterministic order of foreign data wrappers and servers
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.github/workflows/cloudberry-backup-ci.yml | 57 ++++++++++++++++++++--------
backup/queries_functions.go | 6 ++-
end_to_end/end_to_end_suite_test.go | 10 ++++-
integration/metadata_globals_create_test.go | 6 ++-
integration/metadata_globals_queries_test.go | 26 +++++++++++--
integration/postdata_create_test.go | 7 +++-
testutils/functions.go | 20 ++++++++++
7 files changed, 106 insertions(+), 26 deletions(-)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cloudberry.apache.org
For additional commands, e-mail: commits-help@cloudberry.apache.org
(cloudberry-backup) 02/03: CI: test against both Cloudberry REL_2_STABLE and main
Posted by dj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
tuhaihe pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry-backup.git
commit 5d90463f8bd0f7bec1650c7f4faa4c20fd96c4a6
Author: Dianjin Wang <wa...@gmail.com>
AuthorDate: Tue Oct 20 17:08:53 2026 +0800
CI: test against both Cloudberry REL_2_STABLE and main
CI was pinned to Cloudberry REL_2_STABLE in deeb0946 because main moved
to the PG16 kernel and broke some tests. That left Cloudberry main
(the future 3.x) without any coverage.
Turn the Cloudberry branch into a matrix dimension, so that every test
target runs against both REL_2_STABLE and main. Artifact names and job
names now include the branch. The test job runs with !cancelled(), so a
failed build on one branch does not skip the test jobs of the other.
Also fix the regression target on main. Its minimal_schedule tests now
expect the shared tables (char_tbl, int2_tbl, ...) to exist already,
and those tables are created by test_setup. Without test_setup, 5 of
the 7 tests failed and the regression database being backed up was
almost empty. Run test_setup first wherever it exists. On
REL_2_STABLE all tests still pass and the schema diff is unchanged.
Tested by running every target on a demo cluster on Cloudberry main
in the CI build image.
Assisted-by: Claude Code
---
.github/workflows/cloudberry-backup-ci.yml | 57 ++++++++++++++++++++++--------
1 file changed, 42 insertions(+), 15 deletions(-)
diff --git a/.github/workflows/cloudberry-backup-ci.yml b/.github/workflows/cloudberry-backup-ci.yml
index e1682155..cd49096e 100644
--- a/.github/workflows/cloudberry-backup-ci.yml
+++ b/.github/workflows/cloudberry-backup-ci.yml
@@ -25,13 +25,16 @@
# and runs Cloudberry-backup tests against a demo Cloudberry cluster.
#
# Workflow Overview:
-# 1. Build Cloudberry from source and upload the installation as an artifact.
-# 2. For each test target (unit, integration, end_to_end), restore the
-# Cloudberry installation, create a demo cluster, and run tests.
+# 1. For each Cloudberry branch (REL_2_STABLE, main), build Cloudberry
+# from source and upload the installation as an artifact.
+# 2. For each Cloudberry branch and test target (unit, integration,
+# end_to_end, ...), restore the matching Cloudberry installation,
+# create a demo cluster, and run tests.
#
# Notes:
# - Each test job runs in an isolated environment and creates its own demo cluster.
# - Artifacts are used to avoid rebuilding Cloudberry for every test target.
+# - Artifact names carry the Cloudberry branch so the two builds never mix.
# --------------------------------------------------------------------
name: cloudberry-backup-ci
@@ -53,15 +56,16 @@ permissions:
env:
CLOUDBERRY_REPO: apache/cloudberry
- # Currently targeting REL_2_STABLE (2.x) branch only.
- # TODO: Switch back to "main" once Cloudberry 3.x / main branch stabilizes with PG16 support.
- CLOUDBERRY_REF: REL_2_STABLE
+ # The Cloudberry branches to test against are set by the
+ # `cloudberry_ref` matrix of each job:
+ # - REL_2_STABLE: Cloudberry 2.x (PG14 kernel), the current stable line.
+ # - main: the future Cloudberry 3.x (PG16 kernel).
CLOUDBERRY_DIR: cloudberry
CLOUDBERRY_BACKUP_DIR: cloudberry-backup
jobs:
build_cloudberry:
- name: Build Cloudberry From Source
+ name: Build Cloudberry From Source (${{ matrix.cloudberry_ref }})
runs-on: ubuntu-22.04
timeout-minutes: 180
container:
@@ -73,6 +77,11 @@ jobs:
-v /usr/local:/host_usr_local
-v /opt:/host_opt
+ strategy:
+ fail-fast: false
+ matrix:
+ cloudberry_ref: [REL_2_STABLE, main]
+
steps:
- name: Free Disk Space
run: |
@@ -99,7 +108,7 @@ jobs:
uses: actions/checkout@v4
with:
repository: ${{ env.CLOUDBERRY_REPO }}
- ref: ${{ env.CLOUDBERRY_REF }}
+ ref: ${{ matrix.cloudberry_ref }}
fetch-depth: 1
submodules: true
path: ${{ env.CLOUDBERRY_DIR }}
@@ -159,7 +168,7 @@ jobs:
- name: Upload Cloudberry Installation
uses: actions/upload-artifact@v4
with:
- name: cloudberry-db-install
+ name: cloudberry-db-install-${{ matrix.cloudberry_ref }}
path: cloudberry-db.tgz
if-no-files-found: error
retention-days: 7
@@ -167,14 +176,19 @@ jobs:
- name: Upload Cloudberry Source
uses: actions/upload-artifact@v4
with:
- name: cloudberry-source
+ name: cloudberry-source-${{ matrix.cloudberry_ref }}
path: cloudberry-src.tgz
if-no-files-found: error
retention-days: 7
test_cloudberry_backup:
- name: Cloudberry-backup Tests (${{ matrix.test_target }})
+ name: Cloudberry-backup Tests (${{ matrix.cloudberry_ref }}, ${{ matrix.test_target }})
needs: [build_cloudberry]
+ # `needs` on a matrix job fails as soon as any one of its legs fails, so
+ # run anyway and let each leg fail on its own if the Cloudberry build it
+ # downloads is missing. That keeps a broken main build from hiding the
+ # REL_2_STABLE results.
+ if: ${{ !cancelled() }}
runs-on: ubuntu-22.04
timeout-minutes: 180
container:
@@ -189,6 +203,7 @@ jobs:
strategy:
fail-fast: false
matrix:
+ cloudberry_ref: [REL_2_STABLE, main]
test_target: [smoke, unit, integration, end_to_end, s3_plugin_e2e, regression, scale, package_install]
steps:
@@ -222,12 +237,12 @@ jobs:
- name: Download Cloudberry Installation
uses: actions/download-artifact@v4
with:
- name: cloudberry-db-install
+ name: cloudberry-db-install-${{ matrix.cloudberry_ref }}
- name: Download Cloudberry Source
uses: actions/download-artifact@v4
with:
- name: cloudberry-source
+ name: cloudberry-source-${{ matrix.cloudberry_ref }}
- name: Restore Cloudberry Installation
run: |
@@ -281,6 +296,7 @@ jobs:
CLOUDBERRY_BACKUP_SRC: ${{ github.workspace }}/${{ env.CLOUDBERRY_BACKUP_DIR }}
CLOUDBERRY_SRC: ${{ github.workspace }}/${{ env.CLOUDBERRY_DIR }}
TEST_TARGET: ${{ matrix.test_target }}
+ CLOUDBERRY_REF: ${{ matrix.cloudberry_ref }}
run: |
set -euo pipefail
TEST_LOG_ROOT="${GITHUB_WORKSPACE}/test-logs/${TEST_TARGET}"
@@ -434,7 +450,17 @@ jobs:
;;
regression)
pushd ${CLOUDBERRY_SRC}/src/test/regress
- ./pg_regress --dbname=regression --host=localhost --port=7000 --init-file=init_file --schedule=./minimal_schedule || true
+ # On Cloudberry main (PG16 kernel) the shared test tables
+ # (char_tbl, int2_tbl, ...) are created by test_setup, which
+ # minimal_schedule does not list; without it most tests fail
+ # and the regression database ends up nearly empty. Run it
+ # first wherever it exists; on REL_2_STABLE it is harmless.
+ regress_schedule=./minimal_schedule
+ if [ -f sql/test_setup.sql ]; then
+ regress_schedule=/tmp/regression_minimal_schedule
+ { echo "test: test_setup"; cat ./minimal_schedule; } > "${regress_schedule}"
+ fi
+ ./pg_regress --dbname=regression --host=localhost --port=7000 --init-file=init_file --schedule="${regress_schedule}" || true
cat regression.diffs 2>/dev/null || true
popd
@@ -569,6 +595,7 @@ jobs:
{
echo "## Cloudberry-backup Test Summary"
+ echo "- Cloudberry: ${CLOUDBERRY_REF}"
echo "- Target: ${TEST_TARGET}"
if [ ${status} -eq 0 ]; then
echo "- Result: PASS"
@@ -584,7 +611,7 @@ jobs:
if: failure()
uses: actions/upload-artifact@v4
with:
- name: cloudberry-backup-logs-${{ matrix.test_target }}
+ name: cloudberry-backup-logs-${{ matrix.cloudberry_ref }}-${{ matrix.test_target }}
path: test-logs/${{ matrix.test_target }}
if-no-files-found: warn
retention-days: 7
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cloudberry.apache.org
For additional commands, e-mail: commits-help@cloudberry.apache.org
(cloudberry-backup) 01/03: Adapt tests to the PG16 kernel of Cloudberry main
Posted by dj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
tuhaihe pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry-backup.git
commit ee59c2cdae4e8943250a3730259593d50da48198
Author: Dianjin Wang <wa...@gmail.com>
AuthorDate: Tue Oct 20 17:08:53 2026 +0800
Adapt tests to the PG16 kernel of Cloudberry main
Cloudberry main (the future 3.x) is now on the PG16 kernel. Running the
suites against it gives 8 integration failures and 1 end_to_end
failure. Both suites pass on REL_2_STABLE. All of the failures come
from PG16 behavior changes, not from gpbackup bugs:
- A superuser that grants a membership without GRANTED BY is now
recorded as the bootstrap superuser, not as itself.
- A role named in GRANTED BY must hold ADMIN OPTION on the granted
role, even when it is a superuser.
- A role that granted a membership can no longer be dropped while
that membership exists, so the "dropped granter" case cannot be
set up at all.
- pg_get_viewdef() no longer qualifies the columns of a single-table
query.
Add testutils.IsCBDB3OrLater() and use it to set up and check these
cases per version. It compares SemVer.Major directly because a main
build reports "3.0.0-devel", which sorts before "3.0.0" under semver,
so Version.AtLeast("3") returns false.
The membership tests now also match on the member, since granting
ADMIN OPTION to testrole first adds a second row for usergroup.
Tested on a demo cluster on Cloudberry main (PG 16.9) and on
REL_2_STABLE (PG 14.10): integration and end_to_end pass on both.
See: https://github.com/apache/cloudberry-backup/issues/103
Assisted-by: Claude Code
---
end_to_end/end_to_end_suite_test.go | 10 ++++++++--
integration/metadata_globals_create_test.go | 6 ++++--
integration/metadata_globals_queries_test.go | 26 ++++++++++++++++++++++----
integration/postdata_create_test.go | 7 ++++++-
testutils/functions.go | 20 ++++++++++++++++++++
5 files changed, 60 insertions(+), 9 deletions(-)
diff --git a/end_to_end/end_to_end_suite_test.go b/end_to_end/end_to_end_suite_test.go
index 585c2057..468ee686 100644
--- a/end_to_end/end_to_end_suite_test.go
+++ b/end_to_end/end_to_end_suite_test.go
@@ -2158,8 +2158,14 @@ LANGUAGE plpgsql NO SQL;`)
Expect(contents).To(ContainSubstring("CREATE VIEW public.key_dependent_view AS \nSELECT\n\tNULL::integer AS key,\n\tNULL::character varying(20) COLLATE pg_catalog.\"C\" AS data;"))
Expect(contents).To(ContainSubstring("CREATE VIEW public.key_dependent_view_no_cols AS \nSELECT;"))
Expect(contents).To(ContainSubstring("ALTER TABLE ONLY public.view_base_table ADD CONSTRAINT view_base_table_pkey PRIMARY KEY (key);"))
- Expect(contents).To(ContainSubstring("CREATE OR REPLACE VIEW public.key_dependent_view AS SELECT view_base_table.key,\n (view_base_table.data COLLATE \"C\") AS data\n FROM public.view_base_table\n GROUP BY view_base_table.key;"))
- Expect(contents).To(ContainSubstring("CREATE OR REPLACE VIEW public.key_dependent_view_no_cols AS SELECT\n FROM public.view_base_table\n GROUP BY view_base_table.key\n HAVING (length((view_base_table.data)::text) > 0);"))
+ if testutils.IsCBDB3OrLater(backupConn) {
+ // PG16 no longer qualifies columns of a single-table query.
+ Expect(contents).To(ContainSubstring("CREATE OR REPLACE VIEW public.key_dependent_view AS SELECT key,\n (data COLLATE \"C\") AS data\n FROM public.view_base_table\n GROUP BY key;"))
+ Expect(contents).To(ContainSubstring("CREATE OR REPLACE VIEW public.key_dependent_view_no_cols AS SELECT\n FROM public.view_base_table\n GROUP BY key\n HAVING (length((data)::text) > 0);"))
+ } else {
+ Expect(contents).To(ContainSubstring("CREATE OR REPLACE VIEW public.key_dependent_view AS SELECT view_base_table.key,\n (view_base_table.data COLLATE \"C\") AS data\n FROM public.view_base_table\n GROUP BY view_base_table.key;"))
+ Expect(contents).To(ContainSubstring("CREATE OR REPLACE VIEW public.key_dependent_view_no_cols AS SELECT\n FROM public.view_base_table\n GROUP BY view_base_table.key\n HAVING (length((view_base_table.data)::text) > 0);"))
+ }
gprestore(gprestorePath, restoreHelperPath, timestamp,
"--redirect-db", "restoredb",
diff --git a/integration/metadata_globals_create_test.go b/integration/metadata_globals_create_test.go
index 2063c3a1..15551390 100644
--- a/integration/metadata_globals_create_test.go
+++ b/integration/metadata_globals_create_test.go
@@ -416,6 +416,7 @@ var _ = Describe("backup integration create statement tests", func() {
defer testhelper.AssertQueryRuns(connectionPool, `DROP ROLE testuser`)
})
It("grants a role without ADMIN OPTION", func() {
+ testutils.GrantAdminToGrantorIfRequired(connectionPool, "usergroup", "testrole")
numRoleMembers := len(backup.GetRoleMembers(connectionPool))
expectedRoleMember := backup.RoleMember{Role: "usergroup", Member: "testuser", Grantor: "testrole", IsAdmin: false}
backup.PrintRoleMembershipStatements(backupfile, tocfile, []backup.RoleMember{expectedRoleMember})
@@ -425,7 +426,7 @@ var _ = Describe("backup integration create statement tests", func() {
resultRoleMembers := backup.GetRoleMembers(connectionPool)
Expect(resultRoleMembers).To(HaveLen(numRoleMembers + 1))
for _, roleMember := range resultRoleMembers {
- if roleMember.Role == "usergroup" {
+ if roleMember.Role == "usergroup" && roleMember.Member == "testuser" {
structmatcher.ExpectStructsToMatch(&expectedRoleMember, &roleMember)
return
}
@@ -433,6 +434,7 @@ var _ = Describe("backup integration create statement tests", func() {
Fail("Role 'testuser' is not a member of role 'usergroup'")
})
It("grants a role WITH ADMIN OPTION", func() {
+ testutils.GrantAdminToGrantorIfRequired(connectionPool, "usergroup", "testrole")
numRoleMembers := len(backup.GetRoleMembers(connectionPool))
expectedRoleMember := backup.RoleMember{Role: "usergroup", Member: "testuser", Grantor: "testrole", IsAdmin: true}
backup.PrintRoleMembershipStatements(backupfile, tocfile, []backup.RoleMember{expectedRoleMember})
@@ -442,7 +444,7 @@ var _ = Describe("backup integration create statement tests", func() {
resultRoleMembers := backup.GetRoleMembers(connectionPool)
Expect(resultRoleMembers).To(HaveLen(numRoleMembers + 1))
for _, roleMember := range resultRoleMembers {
- if roleMember.Role == "usergroup" {
+ if roleMember.Role == "usergroup" && roleMember.Member == "testuser" {
structmatcher.ExpectStructsToMatch(&expectedRoleMember, &roleMember)
return
}
diff --git a/integration/metadata_globals_queries_test.go b/integration/metadata_globals_queries_test.go
index d6182e69..650fef14 100644
--- a/integration/metadata_globals_queries_test.go
+++ b/integration/metadata_globals_queries_test.go
@@ -506,6 +506,17 @@ CREATEEXTTABLE (protocol='gphdfs', type='writable')`
})
})
Describe("GetRoleMembers", func() {
+ /*
+ * Since PG16 (Cloudberry 3.x) a superuser that grants a membership
+ * without GRANTED BY is recorded as the bootstrap superuser rather
+ * than as itself.
+ */
+ implicitGrantor := func(currentRole string) string {
+ if testutils.IsCBDB3OrLater(connectionPool) {
+ return testutils.GetUserByID(connectionPool, 10)
+ }
+ return currentRole
+ }
BeforeEach(func() {
testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE usergroup`)
testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE testuser`)
@@ -516,7 +527,7 @@ CREATEEXTTABLE (protocol='gphdfs', type='writable')`
})
It("returns a role without ADMIN OPTION", func() {
testhelper.AssertQueryRuns(connectionPool, "GRANT usergroup TO testuser")
- expectedRoleMember := backup.RoleMember{Role: "usergroup", Member: "testuser", Grantor: "testrole", IsAdmin: false}
+ expectedRoleMember := backup.RoleMember{Role: "usergroup", Member: "testuser", Grantor: implicitGrantor("testrole"), IsAdmin: false}
roleMembers := backup.GetRoleMembers(connectionPool)
@@ -529,13 +540,14 @@ CREATEEXTTABLE (protocol='gphdfs', type='writable')`
Fail("Role 'testuser' is not a member of role 'usergroup'")
})
It("returns a role WITH ADMIN OPTION", func() {
+ testutils.GrantAdminToGrantorIfRequired(connectionPool, "usergroup", "testrole")
testhelper.AssertQueryRuns(connectionPool, "GRANT usergroup TO testuser WITH ADMIN OPTION GRANTED BY testrole")
expectedRoleMember := backup.RoleMember{Role: "usergroup", Member: "testuser", Grantor: "testrole", IsAdmin: true}
roleMembers := backup.GetRoleMembers(connectionPool)
for _, roleMember := range roleMembers {
- if roleMember.Role == "usergroup" {
+ if roleMember.Role == "usergroup" && roleMember.Member == "testuser" {
structmatcher.ExpectStructsToMatch(&expectedRoleMember, &roleMember)
return
}
@@ -552,7 +564,7 @@ CREATEEXTTABLE (protocol='gphdfs', type='writable')`
testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE "1testuser"`)
defer testhelper.AssertQueryRuns(connectionPool, `DROP ROLE "1testuser"`)
testhelper.AssertQueryRuns(connectionPool, `GRANT "1usergroup" TO "1testuser"`)
- expectedRoleMember := backup.RoleMember{Role: `"1usergroup"`, Member: `"1testuser"`, Grantor: `"1testrole"`, IsAdmin: false}
+ expectedRoleMember := backup.RoleMember{Role: `"1usergroup"`, Member: `"1testuser"`, Grantor: implicitGrantor(`"1testrole"`), IsAdmin: false}
roleMembers := backup.GetRoleMembers(connectionPool)
@@ -565,6 +577,12 @@ CREATEEXTTABLE (protocol='gphdfs', type='writable')`
Fail(`Role "1testuser" is not a member of role "1usergroup"`)
})
It("handles dropped granter", func() {
+ if testutils.IsCBDB3OrLater(connectionPool) {
+ // Since PG16 a role that granted a membership cannot be
+ // dropped while that membership exists, so a membership
+ // with a dropped grantor can no longer be produced.
+ Skip("Test not applicable to Cloudberry 3.x and later")
+ }
testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE testdropgranter_role`)
defer testhelper.AssertQueryRuns(connectionPool, `DROP ROLE testdropgranter_role`)
testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE testdropgranter_member`)
@@ -583,7 +601,7 @@ CREATEEXTTABLE (protocol='gphdfs', type='writable')`
testhelper.AssertQueryRuns(connectionPool, "CREATE CAST (oid AS text) WITH FUNCTION pg_catalog.text(oid) AS IMPLICIT;")
defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION pg_catalog.text(oid) CASCADE;")
testhelper.AssertQueryRuns(connectionPool, "GRANT usergroup TO testuser")
- expectedRoleMember := backup.RoleMember{Role: "usergroup", Member: "testuser", Grantor: "testrole", IsAdmin: false}
+ expectedRoleMember := backup.RoleMember{Role: "usergroup", Member: "testuser", Grantor: implicitGrantor("testrole"), IsAdmin: false}
roleMembers := backup.GetRoleMembers(connectionPool)
diff --git a/integration/postdata_create_test.go b/integration/postdata_create_test.go
index aba3cfb1..1e2ba5a9 100644
--- a/integration/postdata_create_test.go
+++ b/integration/postdata_create_test.go
@@ -402,11 +402,16 @@ AS $$ BEGIN RAISE EXCEPTION 'exception'; END; $$;`)
DROP TABLE public.view_base_table CASCADE;
`)
+ viewDef := " SELECT view_base_table.key,\n (view_base_table.data COLLATE \"C\") AS data\n FROM public.view_base_table\n GROUP BY view_base_table.key;"
+ if testutils.IsCBDB3OrLater(connectionPool) {
+ // PG16 no longer qualifies columns of a single-table query.
+ viewDef = " SELECT key,\n (data COLLATE \"C\") AS data\n FROM public.view_base_table\n GROUP BY key;"
+ }
view1 := backup.View{
Schema: "public",
Name: "key_dependent_view",
Definition: sql.NullString{
- String: " SELECT view_base_table.key,\n (view_base_table.data COLLATE \"C\") AS data\n FROM public.view_base_table\n GROUP BY view_base_table.key;",
+ String: viewDef,
Valid: true,
},
ColumnDefs: []backup.ColumnDefinition{
diff --git a/testutils/functions.go b/testutils/functions.go
index da86eb0d..7245ce94 100644
--- a/testutils/functions.go
+++ b/testutils/functions.go
@@ -559,6 +559,26 @@ func SkipIfBefore7(connectionPool *dbconn.DBConn) {
}
}
+/*
+ * Cloudberry 3.x is built on the PostgreSQL 16 kernel. Compare the major
+ * version directly: a development build reports a version such as
+ * "3.0.0-devel", which sorts before "3.0.0" under semver and so fails
+ * Version.AtLeast("3").
+ */
+func IsCBDB3OrLater(connectionPool *dbconn.DBConn) bool {
+ return connectionPool.Version.IsCBDB() && connectionPool.Version.SemVer.Major >= 3
+}
+
+/*
+ * Since PG16 (Cloudberry 3.x) the role named in GRANTED BY must hold ADMIN
+ * OPTION on the granted role, even when that role is a superuser.
+ */
+func GrantAdminToGrantorIfRequired(connectionPool *dbconn.DBConn, role string, grantor string) {
+ if IsCBDB3OrLater(connectionPool) {
+ testhelper.AssertQueryRuns(connectionPool, fmt.Sprintf("GRANT %s TO %s WITH ADMIN OPTION", role, grantor))
+ }
+}
+
func InitializeTestTOC(buffer io.Writer, which string) (*toc.TOC, *utils.FileWithByteCount) {
tocfile := &toc.TOC{}
tocfile.InitializeMetadataEntryMap()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cloudberry.apache.org
For additional commands, e-mail: commits-help@cloudberry.apache.org
(cloudberry-backup) 03/03: Fix nondeterministic order of foreign data wrappers and servers
Posted by dj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
tuhaihe pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry-backup.git
commit 8b045de59b4ea0014cc0eabc2a7963759e758cc2
Author: Dianjin Wang <wa...@gmail.com>
AuthorDate: Thu Oct 22 11:54:15 2026 +0800
Fix nondeterministic order of foreign data wrappers and servers
GetForeignDataWrappers() and GetForeignServers() have no ORDER BY, so
the database may return their rows in any order. The integration test
"creates foreign data wrappers with a validator and options" indexes
the result as [0] and [1], and it failed on the Cloudberry main leg of
CI with the two wrappers swapped. The same run had passed earlier on a
local main cluster only by chance.
Order both queries by oid. That makes the tests deterministic, and the
backup now writes these objects in a stable order too.
This change is taken from Jinbao Chen's PR #106.
See: https://github.com/apache/cloudberry-backup/pull/106
Co-authored-by: Jinbao Chen <ch...@gmail.com>
Assisted-by: Claude Code
---
backup/queries_functions.go | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/backup/queries_functions.go b/backup/queries_functions.go
index 8fb04069..98c90461 100644
--- a/backup/queries_functions.go
+++ b/backup/queries_functions.go
@@ -840,7 +840,8 @@ func GetForeignDataWrappers(connectionPool *dbconn.DBConn) []ForeignDataWrapper
SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)
FROM pg_options_to_table(fdwoptions) ORDER BY option_name), ', ') AS options
FROM pg_foreign_data_wrapper
- WHERE oid >= %d AND %s`, FIRST_NORMAL_OBJECT_ID, ExtensionFilterClause(""))
+ WHERE oid >= %d AND %s
+ ORDER BY oid`, FIRST_NORMAL_OBJECT_ID, ExtensionFilterClause(""))
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
@@ -889,7 +890,8 @@ func GetForeignServers(connectionPool *dbconn.DBConn) []ForeignServer {
FROM pg_options_to_table(fs.srvoptions) ORDER BY option_name), ', ') AS options
FROM pg_foreign_server fs
LEFT JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srvfdw
- WHERE fs.oid >= %d AND %s`, FIRST_NORMAL_OBJECT_ID, ExtensionFilterClause("fs"))
+ WHERE fs.oid >= %d AND %s
+ ORDER BY fs.oid`, FIRST_NORMAL_OBJECT_ID, ExtensionFilterClause("fs"))
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cloudberry.apache.org
For additional commands, e-mail: commits-help@cloudberry.apache.org