diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 33bba98d5..9c0b011f0 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -68,7 +68,7 @@ USER citus
# build postgres versions separately for effective parrallelism and caching of already built versions when changing only certain versions
FROM base AS pg14
-RUN MAKEFLAGS="-j $(nproc)" pgenv build 14.12
+RUN MAKEFLAGS="-j $(nproc)" pgenv build 14.15
RUN rm .pgenv/src/*.tar*
RUN make -C .pgenv/src/postgresql-*/ clean
RUN make -C .pgenv/src/postgresql-*/src/include install
@@ -80,7 +80,7 @@ RUN cp -r .pgenv/src .pgenv/pgsql-* .pgenv/config .pgenv-staging/
RUN rm .pgenv-staging/config/default.conf
FROM base AS pg15
-RUN MAKEFLAGS="-j $(nproc)" pgenv build 15.7
+RUN MAKEFLAGS="-j $(nproc)" pgenv build 15.10
RUN rm .pgenv/src/*.tar*
RUN make -C .pgenv/src/postgresql-*/ clean
RUN make -C .pgenv/src/postgresql-*/src/include install
@@ -92,7 +92,7 @@ RUN cp -r .pgenv/src .pgenv/pgsql-* .pgenv/config .pgenv-staging/
RUN rm .pgenv-staging/config/default.conf
FROM base AS pg16
-RUN MAKEFLAGS="-j $(nproc)" pgenv build 16.3
+RUN MAKEFLAGS="-j $(nproc)" pgenv build 16.6
RUN rm .pgenv/src/*.tar*
RUN make -C .pgenv/src/postgresql-*/ clean
RUN make -C .pgenv/src/postgresql-*/src/include install
@@ -211,7 +211,7 @@ COPY --chown=citus:citus .psqlrc .
RUN sudo chown --from=root:root citus:citus -R ~
# sets default pg version
-RUN pgenv switch 16.3
+RUN pgenv switch 16.6
# make connecting to the coordinator easy
ENV PGPORT=9700
diff --git a/.github/actions/save_logs_and_results/action.yml b/.github/actions/save_logs_and_results/action.yml
index 0f238835d..b344c68f2 100644
--- a/.github/actions/save_logs_and_results/action.yml
+++ b/.github/actions/save_logs_and_results/action.yml
@@ -6,7 +6,7 @@ inputs:
runs:
using: composite
steps:
- - uses: actions/upload-artifact@v3.1.1
+ - uses: actions/upload-artifact@v4.6.0
name: Upload logs
with:
name: ${{ inputs.folder }}
diff --git a/.github/actions/setup_extension/action.yml b/.github/actions/setup_extension/action.yml
index 96b408e7e..33129f17d 100644
--- a/.github/actions/setup_extension/action.yml
+++ b/.github/actions/setup_extension/action.yml
@@ -17,7 +17,7 @@ runs:
echo "PG_MAJOR=${{ inputs.pg_major }}" >> $GITHUB_ENV
fi
shell: bash
- - uses: actions/download-artifact@v3.0.1
+ - uses: actions/download-artifact@v4.1.8
with:
name: build-${{ env.PG_MAJOR }}
- name: Install Extension
diff --git a/.github/actions/upload_coverage/action.yml b/.github/actions/upload_coverage/action.yml
index 0b5f581a6..ba80ba63a 100644
--- a/.github/actions/upload_coverage/action.yml
+++ b/.github/actions/upload_coverage/action.yml
@@ -21,7 +21,7 @@ runs:
mkdir -p /tmp/codeclimate
cc-test-reporter format-coverage -t lcov -o /tmp/codeclimate/${{ inputs.flags }}.json lcov.info
shell: bash
- - uses: actions/upload-artifact@v3.1.1
+ - uses: actions/upload-artifact@v4.6.0
with:
path: "/tmp/codeclimate/*.json"
- name: codeclimate
+ name: codeclimate-${{ inputs.flags }}
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index 70bc0bcb9..594834a1c 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -31,14 +31,14 @@ jobs:
pgupgrade_image_name: "ghcr.io/citusdata/pgupgradetester"
style_checker_image_name: "ghcr.io/citusdata/stylechecker"
style_checker_tools_version: "0.8.18"
- sql_snapshot_pg_version: "16.3"
- image_suffix: "-v13fd57c"
- pg14_version: '{ "major": "14", "full": "14.12" }'
- pg15_version: '{ "major": "15", "full": "15.7" }'
- pg16_version: '{ "major": "16", "full": "16.3" }'
- upgrade_pg_versions: "14.12-15.7-16.3"
+ sql_snapshot_pg_version: "16.6"
+ image_suffix: "-v5779674"
+ pg14_version: '{ "major": "14", "full": "14.15" }'
+ pg15_version: '{ "major": "15", "full": "15.10" }'
+ pg16_version: '{ "major": "16", "full": "16.6" }'
+ upgrade_pg_versions: "14.15-15.10-16.6"
steps:
- # Since GHA jobs needs at least one step we use a noop step here.
+ # Since GHA jobs need at least one step we use a noop step here.
- name: Set up parameters
run: echo 'noop'
check-sql-snapshots:
@@ -48,7 +48,7 @@ jobs:
image: ${{ needs.params.outputs.build_image_name }}:${{ needs.params.outputs.sql_snapshot_pg_version }}${{ needs.params.outputs.image_suffix }}
options: --user root
steps:
- - uses: actions/checkout@v3.5.0
+ - uses: actions/checkout@v4
- name: Check Snapshots
run: |
git config --global --add safe.directory ${GITHUB_WORKSPACE}
@@ -125,7 +125,7 @@ jobs:
- name: Build
run: "./ci/build-citus.sh"
shell: bash
- - uses: actions/upload-artifact@v3.1.1
+ - uses: actions/upload-artifact@v4.6.0
with:
name: build-${{ env.PG_MAJOR }}
path: |-
@@ -284,10 +284,12 @@ jobs:
check-arbitrary-configs parallel=4 CONFIGS=$TESTS
- uses: "./.github/actions/save_logs_and_results"
if: always()
+ with:
+ folder: ${{ env.PG_MAJOR }}_arbitrary_configs_${{ matrix.parallel }}
- uses: "./.github/actions/upload_coverage"
if: always()
with:
- flags: ${{ env.pg_major }}_upgrade
+ flags: ${{ env.PG_MAJOR }}_arbitrary_configs_${{ matrix.parallel }}
codecov_token: ${{ secrets.CODECOV_TOKEN }}
test-pg-upgrade:
name: PG${{ matrix.old_pg_major }}-PG${{ matrix.new_pg_major }} - check-pg-upgrade
@@ -335,6 +337,8 @@ jobs:
if: failure()
- uses: "./.github/actions/save_logs_and_results"
if: always()
+ with:
+ folder: ${{ env.old_pg_major }}_${{ env.new_pg_major }}_upgrade
- uses: "./.github/actions/upload_coverage"
if: always()
with:
@@ -380,10 +384,12 @@ jobs:
done;
- uses: "./.github/actions/save_logs_and_results"
if: always()
+ with:
+ folder: ${{ env.PG_MAJOR }}_citus_upgrade
- uses: "./.github/actions/upload_coverage"
if: always()
with:
- flags: ${{ env.pg_major }}_upgrade
+ flags: ${{ env.PG_MAJOR }}_citus_upgrade
codecov_token: ${{ secrets.CODECOV_TOKEN }}
upload-coverage:
if: always()
@@ -399,10 +405,11 @@ jobs:
- test-citus-upgrade
- test-pg-upgrade
steps:
- - uses: actions/download-artifact@v3.0.1
+ - uses: actions/download-artifact@v4.1.8
with:
- name: "codeclimate"
- path: "codeclimate"
+ pattern: codeclimate*
+ path: codeclimate
+ merge-multiple: true
- name: Upload coverage results to Code Climate
run: |-
cc-test-reporter sum-coverage codeclimate/*.json -o total.json
@@ -444,7 +451,7 @@ jobs:
chmod +x run_hammerdb.sh
run_hammerdb.sh citusbot_tpcc_benchmark_rg
prepare_parallelization_matrix_32:
- name: Parallel 32
+ name: Prepare parallelization matrix
if: ${{ needs.test-flakyness-pre.outputs.tests != ''}}
needs: test-flakyness-pre
runs-on: ubuntu-20.04
@@ -516,6 +523,7 @@ jobs:
matrix: ${{ fromJson(needs.prepare_parallelization_matrix_32.outputs.json) }}
steps:
- uses: actions/checkout@v4
+ - uses: actions/download-artifact@v4.1.8
- uses: "./.github/actions/setup_extension"
- name: Run minimal tests
run: |-
@@ -529,3 +537,5 @@ jobs:
shell: bash
- uses: "./.github/actions/save_logs_and_results"
if: always()
+ with:
+ folder: test_flakyness_parallel_${{ matrix.id }}
diff --git a/.github/workflows/flaky_test_debugging.yml b/.github/workflows/flaky_test_debugging.yml
index 7135f99fa..055ba6c6a 100644
--- a/.github/workflows/flaky_test_debugging.yml
+++ b/.github/workflows/flaky_test_debugging.yml
@@ -34,7 +34,7 @@ jobs:
echo "PG_MAJOR=${PG_MAJOR}" >> $GITHUB_ENV
./ci/build-citus.sh
shell: bash
- - uses: actions/upload-artifact@v3.1.1
+ - uses: actions/upload-artifact@v4.6.0
with:
name: build-${{ env.PG_MAJOR }}
path: |-
@@ -76,4 +76,4 @@ jobs:
- uses: "./.github/actions/save_logs_and_results"
if: always()
with:
- folder: ${{ matrix.id }}
+ folder: check_flakyness_parallel_${{ matrix.id }}
diff --git a/.github/workflows/packaging-test-pipelines.yml b/.github/workflows/packaging-test-pipelines.yml
index 26b5cfc95..db0fd08ef 100644
--- a/.github/workflows/packaging-test-pipelines.yml
+++ b/.github/workflows/packaging-test-pipelines.yml
@@ -116,7 +116,6 @@ jobs:
# for each deb based image and we use POSTGRES_VERSION to set
# PG_CONFIG variable in each of those runs.
packaging_docker_image:
- - debian-buster-all
- debian-bookworm-all
- debian-bullseye-all
- ubuntu-focal-all
@@ -130,7 +129,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Set pg_config path and python parameters for deb based distros
run: |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 78d1d2a7c..ee3f2d0a2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,51 @@
+### citus v13.0.1 (February 4th, 2025) ###
+
+* Drops support for PostgreSQL 14 (#7753)
+
+### citus v13.0.0 (January 17, 2025) ###
+
+* Adds support for PostgreSQL 17 (#7699, #7661)
+
+* Adds `JSON_TABLE()` support in distributed queries (#7816)
+
+* Propagates `MERGE ... WHEN NOT MATCHED BY SOURCE` (#7807)
+
+* Propagates `MEMORY` and `SERIALIZE` options of `EXPLAIN` (#7802)
+
+* Adds support for identity columns in distributed partitioned tables (#7785)
+
+* Allows specifying an access method for distributed partitioned tables (#7818)
+
+* Allows exclusion constraints on distributed partitioned tables (#7733)
+
+* Allows configuring sslnegotiation using `citus.node_conn_info` (#7821)
+
+* Avoids wal receiver timeouts during large shard splits (#7229)
+
+* Fixes a bug causing incorrect writing of data to target `MERGE` repartition
+ command (#7659)
+
+* Fixes a crash that happens because of unsafe catalog access when re-assigning
+ the global pid after `application_name` changes (#7791)
+
+* Fixes incorrect `VALID UNTIL` setting assumption made for roles when syncing
+ them to new nodes (#7534)
+
+* Fixes segfault when calling distributed procedure with a parameterized
+ distribution argument (#7242)
+
+* Fixes server crash when trying to execute `activate_node_snapshot()` on a
+ single-node cluster (#7552)
+
+* Improves `citus_move_shard_placement()` to fail early if there is a new node
+ without reference tables yet (#7467)
+
+### citus v12.1.6 (Nov 14, 2024) ###
+
+* Propagates `SECURITY LABEL .. ON ROLE` statements (#7304)
+
+* Fixes crash caused by running queries with window partition (#7718)
+
### citus v12.1.5 (July 17, 2024) ###
* Adds support for MERGE commands with single shard distributed target tables
diff --git a/README.md b/README.md
index 2cf17098f..44fd65f50 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-| **
The Citus database is 100% open source.
![]()
Learn what's new in the [Citus 12.1 release blog](https://www.citusdata.com/blog/2023/09/22/adding-postgres-16-support-to-citus-12-1/) and the [Citus Updates page](https://www.citusdata.com/updates/).
**|
+| **
The Citus database is 100% open source.
![]()
Learn what's new in the [Citus 13.0 release blog](https://www.citusdata.com/blog/2025/02/06/distribute-postgresql-17-with-citus-13/) and the [Citus Updates page](https://www.citusdata.com/updates/).
**|
|---|
@@ -95,14 +95,14 @@ Install packages on Ubuntu / Debian:
```bash
curl https://install.citusdata.com/community/deb.sh > add-citus-repo.sh
sudo bash add-citus-repo.sh
-sudo apt-get -y install postgresql-16-citus-12.1
+sudo apt-get -y install postgresql-17-citus-13.0
```
-Install packages on CentOS / Red Hat:
+Install packages on Red Hat:
```bash
curl https://install.citusdata.com/community/rpm.sh > add-citus-repo.sh
sudo bash add-citus-repo.sh
-sudo yum install -y citus121_16
+sudo yum install -y citus130_17
```
To add Citus to your local PostgreSQL database, add the following to `postgresql.conf`:
diff --git a/citus-tools b/citus-tools
deleted file mode 160000
index 3376bd684..000000000
--- a/citus-tools
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 3376bd6845f0614908ed304f5033bd644c82d3bf
diff --git a/src/backend/columnar/columnar_tableam.c b/src/backend/columnar/columnar_tableam.c
index ca3a5f4c4..fd3d171c6 100644
--- a/src/backend/columnar/columnar_tableam.c
+++ b/src/backend/columnar/columnar_tableam.c
@@ -3021,6 +3021,8 @@ AvailableExtensionVersionColumnar(void)
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("citus extension is not found")));
+
+ return NULL; /* keep compiler happy */
}
diff --git a/src/backend/distributed/metadata/metadata_cache.c b/src/backend/distributed/metadata/metadata_cache.c
index 402dedb8a..4f1b942a0 100644
--- a/src/backend/distributed/metadata/metadata_cache.c
+++ b/src/backend/distributed/metadata/metadata_cache.c
@@ -2522,6 +2522,8 @@ AvailableExtensionVersion(void)
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("citus extension is not found")));
+
+ return NULL; /* keep compiler happy */
}
diff --git a/src/backend/distributed/metadata/metadata_sync.c b/src/backend/distributed/metadata/metadata_sync.c
index ef7c56dc7..1b86b06f1 100644
--- a/src/backend/distributed/metadata/metadata_sync.c
+++ b/src/backend/distributed/metadata/metadata_sync.c
@@ -4688,7 +4688,7 @@ void
SendOrCollectCommandListToMetadataNodes(MetadataSyncContext *context, List *commands)
{
/*
- * do not send any command to workers if we collcet commands.
+ * do not send any command to workers if we collect commands.
* Collect commands into metadataSyncContext's collected command
* list.
*/
diff --git a/src/backend/distributed/planner/insert_select_planner.c b/src/backend/distributed/planner/insert_select_planner.c
index 60d6ce466..155880253 100644
--- a/src/backend/distributed/planner/insert_select_planner.c
+++ b/src/backend/distributed/planner/insert_select_planner.c
@@ -1810,6 +1810,8 @@ CastExpr(Expr *expr, Oid sourceType, Oid targetType, Oid targetCollation,
ereport(ERROR, (errmsg("could not find a conversion path from type %d to %d",
sourceType, targetType)));
}
+
+ return NULL; /* keep compiler happy */
}
diff --git a/src/backend/distributed/planner/multi_explain.c b/src/backend/distributed/planner/multi_explain.c
index 4584e7740..db30f4b60 100644
--- a/src/backend/distributed/planner/multi_explain.c
+++ b/src/backend/distributed/planner/multi_explain.c
@@ -190,6 +190,14 @@ PG_FUNCTION_INFO_V1(worker_save_query_explain_analyze);
void
CitusExplainScan(CustomScanState *node, List *ancestors, struct ExplainState *es)
{
+#if PG_VERSION_NUM >= PG_VERSION_16
+ if (es->generic)
+ {
+ ereport(ERROR, (errmsg(
+ "EXPLAIN GENERIC_PLAN is currently not supported for Citus tables")));
+ }
+#endif
+
CitusScanState *scanState = (CitusScanState *) node;
DistributedPlan *distributedPlan = scanState->distributedPlan;
EState *executorState = ScanStateGetExecutorState(scanState);
@@ -992,18 +1000,12 @@ BuildRemoteExplainQuery(char *queryString, ExplainState *es)
appendStringInfo(explainQuery,
"EXPLAIN (ANALYZE %s, VERBOSE %s, "
"COSTS %s, BUFFERS %s, WAL %s, "
-#if PG_VERSION_NUM >= PG_VERSION_16
- "GENERIC_PLAN %s, "
-#endif
"TIMING %s, SUMMARY %s, FORMAT %s) %s",
es->analyze ? "TRUE" : "FALSE",
es->verbose ? "TRUE" : "FALSE",
es->costs ? "TRUE" : "FALSE",
es->buffers ? "TRUE" : "FALSE",
es->wal ? "TRUE" : "FALSE",
-#if PG_VERSION_NUM >= PG_VERSION_16
- es->generic ? "TRUE" : "FALSE",
-#endif
es->timing ? "TRUE" : "FALSE",
es->summary ? "TRUE" : "FALSE",
formatStr,
diff --git a/src/backend/distributed/planner/multi_logical_optimizer.c b/src/backend/distributed/planner/multi_logical_optimizer.c
index 371ba54e6..28680deb0 100644
--- a/src/backend/distributed/planner/multi_logical_optimizer.c
+++ b/src/backend/distributed/planner/multi_logical_optimizer.c
@@ -1557,9 +1557,10 @@ MasterAggregateMutator(Node *originalNode, MasterAggregateWalkerContext *walkerC
}
else if (IsA(originalNode, Var))
{
- Var *newColumn = copyObject((Var *) originalNode);
- newColumn->varno = masterTableId;
- newColumn->varattno = walkerContext->columnId;
+ Var *origColumn = (Var *) originalNode;
+ Var *newColumn = makeVar(masterTableId, walkerContext->columnId,
+ origColumn->vartype, origColumn->vartypmod,
+ origColumn->varcollid, origColumn->varlevelsup);
walkerContext->columnId++;
newNode = (Node *) newColumn;
diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c
index bd65fa60c..8b182fa6c 100644
--- a/src/backend/distributed/shared_library_init.c
+++ b/src/backend/distributed/shared_library_init.c
@@ -1834,16 +1834,6 @@ RegisterCitusConfigVariables(void)
GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_UNIT_MS,
NULL, NULL, NULL);
- DefineCustomStringVariable(
- "citus.main_db",
- gettext_noop("Which database is designated as the main_db"),
- NULL,
- &MainDb,
- "",
- PGC_POSTMASTER,
- GUC_STANDARD,
- NULL, NULL, NULL);
-
DefineCustomIntVariable(
"citus.max_adaptive_executor_pool_size",
gettext_noop("Sets the maximum number of connections per worker node used by "
@@ -2890,14 +2880,27 @@ ApplicationNameAssignHook(const char *newval, void *extra)
DetermineCitusBackendType(newval);
/*
- * AssignGlobalPID might read from catalog tables to get the the local
- * nodeid. But ApplicationNameAssignHook might be called before catalog
- * access is available to the backend (such as in early stages of
- * authentication). We use StartupCitusBackend to initialize the global pid
- * after catalogs are available. After that happens this hook becomes
- * responsible to update the global pid on later application_name changes.
- * So we set the FinishedStartupCitusBackend flag in StartupCitusBackend to
- * indicate when this responsibility handoff has happened.
+ * We use StartupCitusBackend to initialize the global pid after catalogs
+ * are available. After that happens this hook becomes responsible to update
+ * the global pid on later application_name changes. So we set the
+ * FinishedStartupCitusBackend flag in StartupCitusBackend to indicate when
+ * this responsibility handoff has happened.
+ *
+ * Also note that when application_name changes, we don't actually need to
+ * try re-assigning the global pid for external client backends and
+ * background workers because application_name doesn't affect the global
+ * pid for such backends - note that !IsExternalClientBackend() check covers
+ * both types of backends. Plus,
+ * trying to re-assign the global pid for such backends would unnecessarily
+ * cause performing a catalog access when the cached local node id is
+ * invalidated. However, accessing to the catalog tables is dangerous in
+ * certain situations like when we're not in a transaction block. And for
+ * the other types of backends, i.e., the Citus internal backends, we need
+ * to re-assign the global pid when the application_name changes because for
+ * such backends we simply extract the global pid inherited from the
+ * originating backend from the application_name -that's specified by
+ * originating backend when openning that connection- and this doesn't require
+ * catalog access.
*
* Another solution to the catalog table acccess problem would be to update
* global pid lazily, like we do for HideShards. But that's not possible
@@ -2907,7 +2910,7 @@ ApplicationNameAssignHook(const char *newval, void *extra)
* as reasonably possible, which is also why we extract global pids in the
* AuthHook already (extracting doesn't require catalog access).
*/
- if (FinishedStartupCitusBackend)
+ if (FinishedStartupCitusBackend && !IsExternalClientBackend())
{
AssignGlobalPID(newval);
}
diff --git a/src/backend/distributed/sql/citus--12.1-1--12.2-1.sql b/src/backend/distributed/sql/citus--12.1-1--12.2-1.sql
index 1bec0f429..b1a2c5554 100644
--- a/src/backend/distributed/sql/citus--12.1-1--12.2-1.sql
+++ b/src/backend/distributed/sql/citus--12.1-1--12.2-1.sql
@@ -4,29 +4,21 @@
#include "udfs/citus_internal_database_command/12.2-1.sql"
#include "udfs/citus_add_rebalance_strategy/12.2-1.sql"
-#include "udfs/start_management_transaction/12.2-1.sql"
-#include "udfs/execute_command_on_remote_nodes_as_user/12.2-1.sql"
-#include "udfs/mark_object_distributed/12.2-1.sql"
DROP FUNCTION pg_catalog.citus_unmark_object_distributed(oid, oid, int);
#include "udfs/citus_unmark_object_distributed/12.2-1.sql"
-#include "udfs/commit_management_command_2pc/12.2-1.sql"
ALTER TABLE pg_catalog.pg_dist_transaction ADD COLUMN outer_xid xid8;
#include "udfs/citus_internal_acquire_citus_advisory_object_class_lock/12.2-1.sql"
GRANT USAGE ON SCHEMA citus_internal TO PUBLIC;
-REVOKE ALL ON FUNCTION citus_internal.commit_management_command_2pc FROM PUBLIC;
-REVOKE ALL ON FUNCTION citus_internal.execute_command_on_remote_nodes_as_user FROM PUBLIC;
REVOKE ALL ON FUNCTION citus_internal.find_groupid_for_node FROM PUBLIC;
-REVOKE ALL ON FUNCTION citus_internal.mark_object_distributed FROM PUBLIC;
REVOKE ALL ON FUNCTION citus_internal.pg_dist_node_trigger_func FROM PUBLIC;
REVOKE ALL ON FUNCTION citus_internal.pg_dist_rebalance_strategy_trigger_func FROM PUBLIC;
REVOKE ALL ON FUNCTION citus_internal.pg_dist_shard_placement_trigger_func FROM PUBLIC;
REVOKE ALL ON FUNCTION citus_internal.refresh_isolation_tester_prepared_statement FROM PUBLIC;
REVOKE ALL ON FUNCTION citus_internal.replace_isolation_tester_func FROM PUBLIC;
REVOKE ALL ON FUNCTION citus_internal.restore_isolation_tester_func FROM PUBLIC;
-REVOKE ALL ON FUNCTION citus_internal.start_management_transaction FROM PUBLIC;
#include "udfs/citus_internal_add_colocation_metadata/12.2-1.sql"
#include "udfs/citus_internal_add_object_metadata/12.2-1.sql"
diff --git a/src/backend/distributed/sql/downgrades/citus--12.2-1--12.1-1.sql b/src/backend/distributed/sql/downgrades/citus--12.2-1--12.1-1.sql
index 099bf8d87..c574ba158 100644
--- a/src/backend/distributed/sql/downgrades/citus--12.2-1--12.1-1.sql
+++ b/src/backend/distributed/sql/downgrades/citus--12.2-1--12.1-1.sql
@@ -5,24 +5,9 @@ DROP FUNCTION citus_internal.acquire_citus_advisory_object_class_lock(int, cstri
#include "../udfs/citus_add_rebalance_strategy/10.1-1.sql"
-DROP FUNCTION citus_internal.start_management_transaction(
- outer_xid xid8
-);
-
-DROP FUNCTION citus_internal.execute_command_on_remote_nodes_as_user(
- query text,
- username text
-);
-
-DROP FUNCTION citus_internal.mark_object_distributed(
- classId Oid, objectName text, objectId Oid, connectionUser text
-);
-
DROP FUNCTION pg_catalog.citus_unmark_object_distributed(oid,oid,int,boolean);
#include "../udfs/citus_unmark_object_distributed/10.0-1.sql"
-DROP FUNCTION citus_internal.commit_management_command_2pc();
-
ALTER TABLE pg_catalog.pg_dist_transaction DROP COLUMN outer_xid;
REVOKE USAGE ON SCHEMA citus_internal FROM PUBLIC;
diff --git a/src/backend/distributed/sql/udfs/execute_command_on_remote_nodes_as_user/12.2-1.sql b/src/backend/distributed/sql/udfs/execute_command_on_remote_nodes_as_user/12.2-1.sql
deleted file mode 100644
index fc1076e9c..000000000
--- a/src/backend/distributed/sql/udfs/execute_command_on_remote_nodes_as_user/12.2-1.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE OR REPLACE FUNCTION citus_internal.execute_command_on_remote_nodes_as_user(query text, username text)
- RETURNS VOID
- LANGUAGE C
-AS 'MODULE_PATHNAME', $$execute_command_on_remote_nodes_as_user$$;
-
-COMMENT ON FUNCTION citus_internal.execute_command_on_remote_nodes_as_user(query text, username text)
- IS 'executes a query on the nodes other than the current one';
diff --git a/src/backend/distributed/sql/udfs/execute_command_on_remote_nodes_as_user/latest.sql b/src/backend/distributed/sql/udfs/execute_command_on_remote_nodes_as_user/latest.sql
deleted file mode 100644
index fc1076e9c..000000000
--- a/src/backend/distributed/sql/udfs/execute_command_on_remote_nodes_as_user/latest.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE OR REPLACE FUNCTION citus_internal.execute_command_on_remote_nodes_as_user(query text, username text)
- RETURNS VOID
- LANGUAGE C
-AS 'MODULE_PATHNAME', $$execute_command_on_remote_nodes_as_user$$;
-
-COMMENT ON FUNCTION citus_internal.execute_command_on_remote_nodes_as_user(query text, username text)
- IS 'executes a query on the nodes other than the current one';
diff --git a/src/backend/distributed/sql/udfs/mark_object_distributed/12.2-1.sql b/src/backend/distributed/sql/udfs/mark_object_distributed/12.2-1.sql
deleted file mode 100644
index 25d35c028..000000000
--- a/src/backend/distributed/sql/udfs/mark_object_distributed/12.2-1.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE OR REPLACE FUNCTION citus_internal.mark_object_distributed(classId Oid, objectName text, objectId Oid, connectionUser text)
- RETURNS VOID
- LANGUAGE C
-AS 'MODULE_PATHNAME', $$mark_object_distributed$$;
-
-COMMENT ON FUNCTION citus_internal.mark_object_distributed(classId Oid, objectName text, objectId Oid, connectionUser text)
- IS 'adds an object to pg_dist_object on all nodes';
diff --git a/src/backend/distributed/sql/udfs/mark_object_distributed/latest.sql b/src/backend/distributed/sql/udfs/mark_object_distributed/latest.sql
deleted file mode 100644
index 25d35c028..000000000
--- a/src/backend/distributed/sql/udfs/mark_object_distributed/latest.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE OR REPLACE FUNCTION citus_internal.mark_object_distributed(classId Oid, objectName text, objectId Oid, connectionUser text)
- RETURNS VOID
- LANGUAGE C
-AS 'MODULE_PATHNAME', $$mark_object_distributed$$;
-
-COMMENT ON FUNCTION citus_internal.mark_object_distributed(classId Oid, objectName text, objectId Oid, connectionUser text)
- IS 'adds an object to pg_dist_object on all nodes';
diff --git a/src/backend/distributed/sql/udfs/start_management_transaction/12.2-1.sql b/src/backend/distributed/sql/udfs/start_management_transaction/12.2-1.sql
deleted file mode 100644
index ec1f416d0..000000000
--- a/src/backend/distributed/sql/udfs/start_management_transaction/12.2-1.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE OR REPLACE FUNCTION citus_internal.start_management_transaction(outer_xid xid8)
- RETURNS VOID
- LANGUAGE C
-AS 'MODULE_PATHNAME', $$start_management_transaction$$;
-
-COMMENT ON FUNCTION citus_internal.start_management_transaction(outer_xid xid8)
- IS 'internal Citus function that starts a management transaction in the main database';
diff --git a/src/backend/distributed/sql/udfs/start_management_transaction/latest.sql b/src/backend/distributed/sql/udfs/start_management_transaction/latest.sql
deleted file mode 100644
index ec1f416d0..000000000
--- a/src/backend/distributed/sql/udfs/start_management_transaction/latest.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE OR REPLACE FUNCTION citus_internal.start_management_transaction(outer_xid xid8)
- RETURNS VOID
- LANGUAGE C
-AS 'MODULE_PATHNAME', $$start_management_transaction$$;
-
-COMMENT ON FUNCTION citus_internal.start_management_transaction(outer_xid xid8)
- IS 'internal Citus function that starts a management transaction in the main database';
diff --git a/src/backend/distributed/test/run_from_same_connection.c b/src/backend/distributed/test/run_from_same_connection.c
index 52b2e0b18..d22ee4428 100644
--- a/src/backend/distributed/test/run_from_same_connection.c
+++ b/src/backend/distributed/test/run_from_same_connection.c
@@ -190,6 +190,9 @@ run_commands_on_session_level_connection_to_node(PG_FUNCTION_ARGS)
/*
* override_backend_data_gpid is a wrapper around SetBackendDataGpid().
+ * Also sets distributedCommandOriginator to true since the only caller of
+ * this method calls this function actually wants this backend to
+ * be treated as a distributed command originator with the given global pid.
*/
Datum
override_backend_data_gpid(PG_FUNCTION_ARGS)
@@ -199,6 +202,7 @@ override_backend_data_gpid(PG_FUNCTION_ARGS)
uint64 gpid = PG_GETARG_INT64(0);
SetBackendDataGlobalPID(gpid);
+ SetBackendDataDistributedCommandOriginator(true);
PG_RETURN_VOID();
}
diff --git a/src/backend/distributed/transaction/backend_data.c b/src/backend/distributed/transaction/backend_data.c
index 67acadd29..9b6e7d122 100644
--- a/src/backend/distributed/transaction/backend_data.c
+++ b/src/backend/distributed/transaction/backend_data.c
@@ -855,6 +855,16 @@ GetCurrentDistributedTransactionId(void)
void
AssignDistributedTransactionId(void)
{
+ /*
+ * MyBackendData should always be available. However, we observed some
+ * crashes where certain hooks were not executed.
+ * Bug 3697586: Server crashes when assigning distributed transaction
+ */
+ if (!MyBackendData)
+ {
+ ereport(ERROR, (errmsg("backend is not ready for distributed transactions")));
+ }
+
pg_atomic_uint64 *transactionNumberSequence =
&backendManagementShmemData->nextTransactionNumber;
@@ -964,6 +974,23 @@ SetBackendDataGlobalPID(uint64 gpid)
}
+/*
+ * SetBackendDataDistributedCommandOriginator sets the distributedCommandOriginator
+ * field on MyBackendData.
+ */
+void
+SetBackendDataDistributedCommandOriginator(bool distributedCommandOriginator)
+{
+ if (!MyBackendData)
+ {
+ return;
+ }
+ SpinLockAcquire(&MyBackendData->mutex);
+ MyBackendData->distributedCommandOriginator = distributedCommandOriginator;
+ SpinLockRelease(&MyBackendData->mutex);
+}
+
+
/*
* GetGlobalPID returns the global process id of the current backend.
*/
diff --git a/src/include/distributed/backend_data.h b/src/include/distributed/backend_data.h
index 8014fe5a6..5b3fcf2ac 100644
--- a/src/include/distributed/backend_data.h
+++ b/src/include/distributed/backend_data.h
@@ -61,6 +61,7 @@ extern void AssignGlobalPID(const char *applicationName);
extern uint64 GetGlobalPID(void);
extern void SetBackendDataDatabaseId(void);
extern void SetBackendDataGlobalPID(uint64 gpid);
+extern void SetBackendDataDistributedCommandOriginator(bool distributedCommandOriginator);
extern uint64 ExtractGlobalPID(const char *applicationName);
extern int ExtractNodeIdFromGlobalPID(uint64 globalPID, bool missingOk);
extern int ExtractProcessIdFromGlobalPID(uint64 globalPID);
diff --git a/src/test/regress/citus_tests/test/test_maintenancedeamon.py b/src/test/regress/citus_tests/test/test_maintenancedeamon.py
deleted file mode 100644
index 3f6cb501e..000000000
--- a/src/test/regress/citus_tests/test/test_maintenancedeamon.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# This test checks that once citus.main_db is set and the
-# server is restarted. A Citus Maintenance Daemon for the main_db
-# is launched. This should happen even if there is no query run
-# in main_db yet.
-import time
-
-
-def wait_until_maintenance_deamons_start(deamoncount, cluster):
- i = 0
- n = 0
-
- while i < 10:
- i += 1
- n = cluster.coordinator.sql_value(
- "SELECT count(*) FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon';"
- )
-
- if n == deamoncount:
- break
-
- time.sleep(0.1)
-
- assert n == deamoncount
-
-
-def test_set_maindb(cluster_factory):
- cluster = cluster_factory(0)
-
- # Test that once citus.main_db is set to a database name
- # there are two maintenance deamons running upon restart.
- # One maintenance deamon for the database of the current connection
- # and one for the citus.main_db.
- cluster.coordinator.create_database("mymaindb")
- cluster.coordinator.configure("citus.main_db='mymaindb'")
- cluster.coordinator.restart()
-
- assert cluster.coordinator.sql_value("SHOW citus.main_db;") == "mymaindb"
-
- wait_until_maintenance_deamons_start(2, cluster)
-
- assert (
- cluster.coordinator.sql_value(
- "SELECT count(*) FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon' AND datname='mymaindb';"
- )
- == 1
- )
-
- # Test that once citus.main_db is set to empty string
- # there is only one maintenance deamon for the database
- # of the current connection.
- cluster.coordinator.configure("citus.main_db=''")
- cluster.coordinator.restart()
- assert cluster.coordinator.sql_value("SHOW citus.main_db;") == ""
-
- wait_until_maintenance_deamons_start(1, cluster)
-
- # Test that after citus.main_db is dropped. The maintenance
- # deamon for this database is terminated.
- cluster.coordinator.configure("citus.main_db='mymaindb'")
- cluster.coordinator.restart()
- assert cluster.coordinator.sql_value("SHOW citus.main_db;") == "mymaindb"
-
- wait_until_maintenance_deamons_start(2, cluster)
-
- cluster.coordinator.sql("DROP DATABASE mymaindb;")
-
- wait_until_maintenance_deamons_start(1, cluster)
-
- assert (
- cluster.coordinator.sql_value(
- "SELECT count(*) FROM pg_stat_activity WHERE application_name = 'Citus Maintenance Daemon' AND datname='mymaindb';"
- )
- == 0
- )
diff --git a/src/test/regress/citus_tests/test/test_other_databases.py b/src/test/regress/citus_tests/test/test_other_databases.py
deleted file mode 100644
index 494301692..000000000
--- a/src/test/regress/citus_tests/test/test_other_databases.py
+++ /dev/null
@@ -1,198 +0,0 @@
-def test_main_commited_outer_not_yet(cluster):
- c = cluster.coordinator
- w0 = cluster.workers[0]
-
- # create a non-main database
- c.sql("CREATE DATABASE db1")
-
- # we will use cur1 to simulate non-main database user and
- # cur2 to manually do the steps we would do in the main database
- with c.cur(dbname="db1") as cur1, c.cur() as cur2:
- # let's start a transaction and find its transaction id
- cur1.execute("BEGIN")
- cur1.execute("SELECT txid_current()")
- txid = cur1.fetchall()
-
- # using the transaction id of the cur1 simulate the main database commands manually
- cur2.execute("BEGIN")
- cur2.execute(
- "SELECT citus_internal.start_management_transaction(%s)", (str(txid[0][0]),)
- )
- cur2.execute(
- "SELECT citus_internal.execute_command_on_remote_nodes_as_user('CREATE USER u1;', 'postgres')"
- )
- cur2.execute(
- "SELECT citus_internal.mark_object_distributed(1260, 'u1', 123123, 'postgres')"
- )
- cur2.execute("COMMIT")
-
- # run the transaction recovery
- c.sql("SELECT recover_prepared_transactions()")
-
- # user should not be created on the worker because outer transaction is not committed yet
- role_before_commit = w0.sql_value(
- "SELECT count(*) FROM pg_roles WHERE rolname = 'u1'"
- )
-
- assert (
- int(role_before_commit) == 0
- ), "role is in pg_dist_object despite not committing"
-
- # user should not be in pg_dist_object on the coordinator because outer transaction is not committed yet
- pdo_coordinator_before_commit = c.sql_value(
- "SELECT count(*) FROM pg_dist_object WHERE objid = 123123"
- )
-
- assert (
- int(pdo_coordinator_before_commit) == 0
- ), "role is in pg_dist_object on coordinator despite not committing"
-
- # user should not be in pg_dist_object on the worker because outer transaction is not committed yet
- pdo_worker_before_commit = w0.sql_value(
- "SELECT count(*) FROM pg_dist_object WHERE objid::regrole::text = 'u1'"
- )
-
- assert (
- int(pdo_worker_before_commit) == 0
- ), "role is in pg_dist_object on worker despite not committing"
-
- # commit in cur1 so the transaction recovery thinks this is a successful transaction
- cur1.execute("COMMIT")
-
- # run the transaction recovery again after committing
- c.sql("SELECT recover_prepared_transactions()")
-
- # check that the user is created by the transaction recovery on the worker
- role_after_commit = w0.sql_value(
- "SELECT count(*) FROM pg_roles WHERE rolname = 'u1'"
- )
-
- assert (
- int(role_after_commit) == 1
- ), "role is not created during recovery despite committing"
-
- # check that the user is in pg_dist_object on the coordinator after transaction recovery
- pdo_coordinator_after_commit = c.sql_value(
- "SELECT count(*) FROM pg_dist_object WHERE objid = 123123"
- )
-
- assert (
- int(pdo_coordinator_after_commit) == 1
- ), "role is not in pg_dist_object on coordinator after recovery despite committing"
-
- # check that the user is in pg_dist_object on the worker after transaction recovery
- pdo_worker_after_commit = w0.sql_value(
- "SELECT count(*) FROM pg_dist_object WHERE objid::regrole::text = 'u1'"
- )
-
- assert (
- int(pdo_worker_after_commit) == 1
- ), "role is not in pg_dist_object on worker after recovery despite committing"
-
- c.sql("DROP DATABASE db1")
- c.sql(
- "SELECT citus_internal.execute_command_on_remote_nodes_as_user('DROP USER u1', 'postgres')"
- )
- c.sql(
- """
- SELECT run_command_on_workers($$
- DELETE FROM pg_dist_object
- WHERE objid::regrole::text = 'u1'
- $$)
- """
- )
- c.sql(
- """
- DELETE FROM pg_dist_object
- WHERE objid = 123123
- """
- )
-
-
-def test_main_commited_outer_aborted(cluster):
- c = cluster.coordinator
- w0 = cluster.workers[0]
-
- # create a non-main database
- c.sql("CREATE DATABASE db2")
-
- # we will use cur1 to simulate non-main database user and
- # cur2 to manually do the steps we would do in the main database
- with c.cur(dbname="db2") as cur1, c.cur() as cur2:
- # let's start a transaction and find its transaction id
- cur1.execute("BEGIN")
- cur1.execute("SELECT txid_current()")
- txid = cur1.fetchall()
-
- # using the transaction id of the cur1 simulate the main database commands manually
- cur2.execute("BEGIN")
- cur2.execute(
- "SELECT citus_internal.start_management_transaction(%s)", (str(txid[0][0]),)
- )
- cur2.execute(
- "SELECT citus_internal.execute_command_on_remote_nodes_as_user('CREATE USER u2;', 'postgres')"
- )
- cur2.execute(
- "SELECT citus_internal.mark_object_distributed(1260, 'u2', 321321, 'postgres')"
- )
- cur2.execute("COMMIT")
-
- # abort cur1 so the transaction recovery thinks this is an aborted transaction
- cur1.execute("ABORT")
-
- # check that the user is not yet created on the worker
- role_before_recovery = w0.sql_value(
- "SELECT count(*) FROM pg_roles WHERE rolname = 'u2'"
- )
-
- assert int(role_before_recovery) == 0, "role is already created before recovery"
-
- # check that the user is not in pg_dist_object on the coordinator
- pdo_coordinator_before_recovery = c.sql_value(
- "SELECT count(*) FROM pg_dist_object WHERE objid = 321321"
- )
-
- assert (
- int(pdo_coordinator_before_recovery) == 0
- ), "role is already in pg_dist_object on coordinator before recovery"
-
- # check that the user is not in pg_dist_object on the worker
- pdo_worker_before_recovery = w0.sql_value(
- "SELECT count(*) FROM pg_dist_object WHERE objid::regrole::text = 'u2'"
- )
-
- assert (
- int(pdo_worker_before_recovery) == 0
- ), "role is already in pg_dist_object on worker before recovery"
-
- # run the transaction recovery
- c.sql("SELECT recover_prepared_transactions()")
-
- # check that the user is not created by the transaction recovery on the worker
- role_after_recovery = w0.sql_value(
- "SELECT count(*) FROM pg_roles WHERE rolname = 'u2'"
- )
-
- assert (
- int(role_after_recovery) == 0
- ), "role is created during recovery despite aborting"
-
- # check that the user is not in pg_dist_object on the coordinator after transaction recovery
- pdo_coordinator_after_recovery = c.sql_value(
- "SELECT count(*) FROM pg_dist_object WHERE objid = 321321"
- )
-
- assert (
- int(pdo_coordinator_after_recovery) == 0
- ), "role is in pg_dist_object on coordinator after recovery despite aborting"
-
- # check that the user is not in pg_dist_object on the worker after transaction recovery
- pdo_worker_after_recovery = w0.sql_value(
- "SELECT count(*) FROM pg_dist_object WHERE objid::regrole::text = 'u2'"
- )
-
- assert (
- int(pdo_worker_after_recovery) == 0
- ), "role is in pg_dist_object on worker after recovery despite aborting"
-
- c.sql("DROP DATABASE db2")
diff --git a/src/test/regress/citus_tests/upgrade/citus_upgrade_test.py b/src/test/regress/citus_tests/upgrade/citus_upgrade_test.py
index 1ab448031..c25a34482 100755
--- a/src/test/regress/citus_tests/upgrade/citus_upgrade_test.py
+++ b/src/test/regress/citus_tests/upgrade/citus_upgrade_test.py
@@ -62,10 +62,16 @@ def run_citus_upgrade_tests(config, before_upgrade_schedule, after_upgrade_sched
install_citus(config.post_tar_path)
+ # disable 2pc recovery for all nodes to work around https://github.com/citusdata/citus/issues/7875
+ disable_2pc_recovery_for_all_nodes(config.bindir, config)
+
restart_databases(config.bindir, config.datadir, config.mixed_mode, config)
run_alter_citus(config.bindir, config.mixed_mode, config)
verify_upgrade(config, config.mixed_mode, config.node_name_to_ports.values())
+ # re-enable 2pc recovery for all nodes
+ enable_2pc_recovery_for_all_nodes(config.bindir, config)
+
run_test_on_coordinator(config, after_upgrade_schedule)
remove_citus(config.post_tar_path)
@@ -146,6 +152,18 @@ def restart_database(pg_path, abs_data_path, node_name, node_ports, logfile_pref
subprocess.run(command, check=True)
+def disable_2pc_recovery_for_all_nodes(pg_path, config):
+ for port in config.node_name_to_ports.values():
+ utils.psql(pg_path, port, "ALTER SYSTEM SET citus.recover_2pc_interval TO -1;")
+ utils.psql(pg_path, port, "SELECT pg_reload_conf();")
+
+
+def enable_2pc_recovery_for_all_nodes(pg_path, config):
+ for port in config.node_name_to_ports.values():
+ utils.psql(pg_path, port, "ALTER SYSTEM RESET citus.recover_2pc_interval;")
+ utils.psql(pg_path, port, "SELECT pg_reload_conf();")
+
+
def run_alter_citus(pg_path, mixed_mode, config):
for port in config.node_name_to_ports.values():
if mixed_mode and port in (
diff --git a/src/test/regress/expected/citus_internal_access.out b/src/test/regress/expected/citus_internal_access.out
index 21464b38f..eaa2a15c2 100644
--- a/src/test/regress/expected/citus_internal_access.out
+++ b/src/test/regress/expected/citus_internal_access.out
@@ -2,8 +2,6 @@
CREATE USER nonsuperuser CREATEROLE;
SET ROLE nonsuperuser;
--- The non-superuser role should not be able to access citus_internal functions
-SELECT citus_internal.commit_management_command_2pc();
-ERROR: permission denied for function commit_management_command_2pc
SELECT citus_internal.replace_isolation_tester_func();
ERROR: permission denied for function replace_isolation_tester_func
RESET ROLE;
diff --git a/src/test/regress/expected/create_drop_database_propagation_pg15.out b/src/test/regress/expected/create_drop_database_propagation_pg15.out
index 7e76d87f3..9a501558a 100644
--- a/src/test/regress/expected/create_drop_database_propagation_pg15.out
+++ b/src/test/regress/expected/create_drop_database_propagation_pg15.out
@@ -78,11 +78,5 @@ SELECT * FROM public.check_database_on_all_nodes('test_locale_provider') ORDER B
worker node (remote) | {"database_properties": {"datacl": null, "datname": "test_locale_provider", "datctype": "C", "encoding": "UTF8", "datcollate": "C", "tablespace": "pg_default", "daticurules": null, "datallowconn": true, "datconnlimit": -1, "daticulocale": null, "datistemplate": false, "database_owner": "postgres", "datcollversion": null, "datlocprovider": "c"}, "pg_dist_object_record_for_db_exists": true, "stale_pg_dist_object_record_for_a_db_exists": false}
(3 rows)
-\c test_locale_provider - - :worker_2_port
-set citus.enable_create_database_propagation to on;
-create database unsupported_option_from_non_main_db with oid = 12345;
-ERROR: CREATE DATABASE option "oid" is not supported
-\c regression - - :master_port
-set citus.enable_create_database_propagation to on;
drop database test_locale_provider;
\c - - - :master_port
diff --git a/src/test/regress/expected/issue_7705.out b/src/test/regress/expected/issue_7705.out
new file mode 100644
index 000000000..20b078226
--- /dev/null
+++ b/src/test/regress/expected/issue_7705.out
@@ -0,0 +1,248 @@
+--- Test for verifying that column references (var nodes) in targets that cannot be pushed down
+--- do not cause issues for the postgres planner, in particular postgres versions 16+, where the
+--- varnullingrels field of a VAR node may contain relids of join relations that can make the var
+--- NULL; in a rewritten distributed query without a join such relids do not have a meaning.
+--- Issue #7705: [SEGFAULT] Querying distributed tables with window partition causes segmentation fault
+--- https://github.com/citusdata/citus/issues/7705
+CREATE SCHEMA issue_7705;
+SET search_path to 'issue_7705';
+SET citus.next_shard_id TO 30070000;
+SET citus.shard_replication_factor TO 1;
+SET citus.enable_local_execution TO ON;
+CREATE TABLE t1 (id INT PRIMARY KEY);
+INSERT INTO t1 VALUES (1), (2);
+CREATE TABLE t2 (id INT, account_id INT, a2 INT, PRIMARY KEY(id, account_id));
+INSERT INTO t2 VALUES (3, 1, 10), (4, 2, 20), (5, 1, NULL);
+SELECT create_distributed_table('t1', 'id');
+NOTICE: Copying data from local table...
+NOTICE: copying the data has completed
+DETAIL: The local data in the table is no longer visible, but is still on disk.
+HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$issue_7705.t1$$)
+ create_distributed_table
+---------------------------------------------------------------------
+
+(1 row)
+
+SELECT create_distributed_table('t2', 'account_id');
+NOTICE: Copying data from local table...
+NOTICE: copying the data has completed
+DETAIL: The local data in the table is no longer visible, but is still on disk.
+HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$issue_7705.t2$$)
+ create_distributed_table
+---------------------------------------------------------------------
+
+(1 row)
+
+-- Test the issue seen in #7705; a target expression with
+-- a window function that cannot be pushed down because the
+-- partion by is not on the distribution column also includes
+-- a column from the inner side of a left outer join, which
+-- produces a non-empty varnullingrels set in PG 16 (and higher)
+SELECT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id;
+ id | max
+---------------------------------------------------------------------
+ 1 | 10
+ 2 | 20
+ 1 |
+(3 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id;
+ QUERY PLAN
+---------------------------------------------------------------------
+ WindowAgg
+ Output: remote_scan.id, max(remote_scan.max) OVER (?), remote_scan.worker_column_3
+ -> Sort
+ Output: remote_scan.worker_column_3, remote_scan.id, remote_scan.max
+ Sort Key: remote_scan.worker_column_3
+ -> Custom Scan (Citus Adaptive)
+ Output: remote_scan.worker_column_3, remote_scan.id, remote_scan.max
+ Task Count: 4
+ Tasks Shown: One of 4
+ -> Task
+ Query: SELECT worker_column_1 AS id, worker_column_2 AS max, worker_column_3 FROM (SELECT t1.id AS worker_column_1, t2.a2 AS worker_column_2, t2.id AS worker_column_3 FROM (issue_7705.t1_30070000 t1 LEFT JOIN issue_7705.t2_30070004 t2 ON ((t1.id OPERATOR(pg_catalog.=) t2.account_id)))) worker_subquery
+ Node: host=localhost port=xxxxx dbname=regression
+ -> Hash Right Join
+ Output: t1.id, t2.a2, t2.id
+ Inner Unique: true
+ Hash Cond: (t2.account_id = t1.id)
+ -> Seq Scan on issue_7705.t2_30070004 t2
+ Output: t2.id, t2.account_id, t2.a2
+ -> Hash
+ Output: t1.id
+ -> Seq Scan on issue_7705.t1_30070000 t1
+ Output: t1.id
+(22 rows)
+
+SELECT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t2 RIGHT OUTER JOIN t1 ON t1.id = t2.account_id;
+ id | max
+---------------------------------------------------------------------
+ 1 | 10
+ 2 | 20
+ 1 |
+(3 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t2 RIGHT OUTER JOIN t1 ON t1.id = t2.account_id;
+ QUERY PLAN
+---------------------------------------------------------------------
+ WindowAgg
+ Output: remote_scan.id, max(remote_scan.max) OVER (?), remote_scan.worker_column_3
+ -> Sort
+ Output: remote_scan.worker_column_3, remote_scan.id, remote_scan.max
+ Sort Key: remote_scan.worker_column_3
+ -> Custom Scan (Citus Adaptive)
+ Output: remote_scan.worker_column_3, remote_scan.id, remote_scan.max
+ Task Count: 4
+ Tasks Shown: One of 4
+ -> Task
+ Query: SELECT worker_column_1 AS id, worker_column_2 AS max, worker_column_3 FROM (SELECT t1.id AS worker_column_1, t2.a2 AS worker_column_2, t2.id AS worker_column_3 FROM (issue_7705.t2_30070004 t2 RIGHT JOIN issue_7705.t1_30070000 t1 ON ((t1.id OPERATOR(pg_catalog.=) t2.account_id)))) worker_subquery
+ Node: host=localhost port=xxxxx dbname=regression
+ -> Hash Right Join
+ Output: t1.id, t2.a2, t2.id
+ Inner Unique: true
+ Hash Cond: (t2.account_id = t1.id)
+ -> Seq Scan on issue_7705.t2_30070004 t2
+ Output: t2.id, t2.account_id, t2.a2
+ -> Hash
+ Output: t1.id
+ -> Seq Scan on issue_7705.t1_30070000 t1
+ Output: t1.id
+(22 rows)
+
+SELECT DISTINCT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id;
+ id | max
+---------------------------------------------------------------------
+ 1 |
+ 1 | 10
+ 2 | 20
+(3 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT DISTINCT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id;
+ QUERY PLAN
+---------------------------------------------------------------------
+ HashAggregate
+ Output: remote_scan.id, (max(remote_scan.max) OVER (?)), remote_scan.worker_column_3
+ Group Key: remote_scan.id, max(remote_scan.max) OVER (?)
+ -> WindowAgg
+ Output: remote_scan.id, max(remote_scan.max) OVER (?), remote_scan.worker_column_3
+ -> Sort
+ Output: remote_scan.worker_column_3, remote_scan.id, remote_scan.max
+ Sort Key: remote_scan.worker_column_3
+ -> Custom Scan (Citus Adaptive)
+ Output: remote_scan.worker_column_3, remote_scan.id, remote_scan.max
+ Task Count: 4
+ Tasks Shown: One of 4
+ -> Task
+ Query: SELECT worker_column_1 AS id, worker_column_2 AS max, worker_column_3 FROM (SELECT t1.id AS worker_column_1, t2.a2 AS worker_column_2, t2.id AS worker_column_3 FROM (issue_7705.t1_30070000 t1 LEFT JOIN issue_7705.t2_30070004 t2 ON ((t1.id OPERATOR(pg_catalog.=) t2.account_id)))) worker_subquery
+ Node: host=localhost port=xxxxx dbname=regression
+ -> Hash Right Join
+ Output: t1.id, t2.a2, t2.id
+ Inner Unique: true
+ Hash Cond: (t2.account_id = t1.id)
+ -> Seq Scan on issue_7705.t2_30070004 t2
+ Output: t2.id, t2.account_id, t2.a2
+ -> Hash
+ Output: t1.id
+ -> Seq Scan on issue_7705.t1_30070000 t1
+ Output: t1.id
+(25 rows)
+
+CREATE SEQUENCE test_seq START 101;
+CREATE OR REPLACE FUNCTION TEST_F(int) returns INT language sql stable as $$ select $1 + 42; $$ ;
+-- Issue #7705 also occurs if a target expression includes a column
+-- of a distributed table that is on the inner side of a left outer
+-- join and a call to nextval(), because nextval() cannot be pushed
+-- down, and must be run on the coordinator
+SELECT t1.id, TEST_F(t2.a2 + nextval('test_seq') :: int)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id
+ORDER BY t1.id;
+ id | test_f
+---------------------------------------------------------------------
+ 1 | 153
+ 1 |
+ 2 | 165
+(3 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT t1.id, TEST_F(t2.a2 + nextval('test_seq') :: int)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id
+ORDER BY t1.id;
+ QUERY PLAN
+---------------------------------------------------------------------
+ Result
+ Output: remote_scan.id, ((remote_scan.test_f + (nextval('test_seq'::regclass))::integer) + 42)
+ -> Sort
+ Output: remote_scan.id, remote_scan.test_f
+ Sort Key: remote_scan.id
+ -> Custom Scan (Citus Adaptive)
+ Output: remote_scan.id, remote_scan.test_f
+ Task Count: 4
+ Tasks Shown: One of 4
+ -> Task
+ Query: SELECT worker_column_1 AS id, worker_column_2 AS test_f FROM (SELECT t1.id AS worker_column_1, t2.a2 AS worker_column_2 FROM (issue_7705.t1_30070000 t1 LEFT JOIN issue_7705.t2_30070004 t2 ON ((t1.id OPERATOR(pg_catalog.=) t2.account_id)))) worker_subquery
+ Node: host=localhost port=xxxxx dbname=regression
+ -> Hash Right Join
+ Output: t1.id, t2.a2
+ Inner Unique: true
+ Hash Cond: (t2.account_id = t1.id)
+ -> Seq Scan on issue_7705.t2_30070004 t2
+ Output: t2.id, t2.account_id, t2.a2
+ -> Hash
+ Output: t1.id
+ -> Seq Scan on issue_7705.t1_30070000 t1
+ Output: t1.id
+(22 rows)
+
+SELECT t1.id, CASE nextval('test_seq') % 2 = 0 WHEN true THEN t2.a2 ELSE 1 END
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id
+ORDER BY t1.id;
+ id | case
+---------------------------------------------------------------------
+ 1 | 10
+ 1 | 1
+ 2 | 20
+(3 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT t1.id, CASE nextval('test_seq') %2 = 0 WHEN true THEN t2.a2 ELSE 1 END
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id
+ORDER BY t1.id;
+ QUERY PLAN
+---------------------------------------------------------------------
+ Result
+ Output: remote_scan.id, CASE ((nextval('test_seq'::regclass) % '2'::bigint) = 0) WHEN CASE_TEST_EXPR THEN remote_scan."case" ELSE 1 END
+ -> Sort
+ Output: remote_scan.id, remote_scan."case"
+ Sort Key: remote_scan.id
+ -> Custom Scan (Citus Adaptive)
+ Output: remote_scan.id, remote_scan."case"
+ Task Count: 4
+ Tasks Shown: One of 4
+ -> Task
+ Query: SELECT worker_column_1 AS id, worker_column_2 AS "case" FROM (SELECT t1.id AS worker_column_1, t2.a2 AS worker_column_2 FROM (issue_7705.t1_30070000 t1 LEFT JOIN issue_7705.t2_30070004 t2 ON ((t1.id OPERATOR(pg_catalog.=) t2.account_id)))) worker_subquery
+ Node: host=localhost port=xxxxx dbname=regression
+ -> Hash Right Join
+ Output: t1.id, t2.a2
+ Inner Unique: true
+ Hash Cond: (t2.account_id = t1.id)
+ -> Seq Scan on issue_7705.t2_30070004 t2
+ Output: t2.id, t2.account_id, t2.a2
+ -> Hash
+ Output: t1.id
+ -> Seq Scan on issue_7705.t1_30070000 t1
+ Output: t1.id
+(22 rows)
+
+--- cleanup
+\set VERBOSITY TERSE
+DROP SCHEMA issue_7705 CASCADE;
+NOTICE: drop cascades to 4 other objects
+RESET all;
diff --git a/src/test/regress/expected/multi_extension.out b/src/test/regress/expected/multi_extension.out
index aaafce715..ab9a7d931 100644
--- a/src/test/regress/expected/multi_extension.out
+++ b/src/test/regress/expected/multi_extension.out
@@ -1431,20 +1431,16 @@ SELECT * FROM multi_extension.print_extension_changes();
| function citus_internal.add_shard_metadata(regclass,bigint,"char",text,text) void
| function citus_internal.add_tenant_schema(oid,integer) void
| function citus_internal.adjust_local_clock_to_remote(cluster_clock) void
- | function citus_internal.commit_management_command_2pc() void
| function citus_internal.database_command(text) void
| function citus_internal.delete_colocation_metadata(integer) void
| function citus_internal.delete_partition_metadata(regclass) void
| function citus_internal.delete_placement_metadata(bigint) void
| function citus_internal.delete_shard_metadata(bigint) void
| function citus_internal.delete_tenant_schema(oid) void
- | function citus_internal.execute_command_on_remote_nodes_as_user(text,text) void
| function citus_internal.global_blocked_processes() SETOF record
| function citus_internal.is_replication_origin_tracking_active() boolean
| function citus_internal.local_blocked_processes() SETOF record
| function citus_internal.mark_node_not_synced(integer,integer) void
- | function citus_internal.mark_object_distributed(oid,text,oid,text) void
- | function citus_internal.start_management_transaction(xid8) void
| function citus_internal.start_replication_origin_tracking() void
| function citus_internal.stop_replication_origin_tracking() void
| function citus_internal.unregister_tenant_schema_globally(oid,text) void
@@ -1452,7 +1448,7 @@ SELECT * FROM multi_extension.print_extension_changes();
| function citus_internal.update_placement_metadata(bigint,integer,integer) void
| function citus_internal.update_relation_colocation(oid,integer) void
| function citus_unmark_object_distributed(oid,oid,integer,boolean) void
-(30 rows)
+(26 rows)
DROP TABLE multi_extension.prev_objects, multi_extension.extension_diff;
-- show running version
diff --git a/src/test/regress/expected/pg16.out b/src/test/regress/expected/pg16.out
index a035fcfc4..546c0a832 100644
--- a/src/test/regress/expected/pg16.out
+++ b/src/test/regress/expected/pg16.out
@@ -81,29 +81,9 @@ SELECT create_distributed_table('tenk1', 'unique1');
(1 row)
SET citus.log_remote_commands TO on;
-EXPLAIN (GENERIC_PLAN) SELECT unique1 FROM tenk1 WHERE thousand = 1000;
-NOTICE: issuing BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;SELECT assign_distributed_transaction_id(xx, xx, 'xxxxxxx');
-DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
-NOTICE: issuing SAVEPOINT citus_explain_savepoint
-DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
-NOTICE: issuing EXPLAIN (ANALYZE FALSE, VERBOSE FALSE, COSTS TRUE, BUFFERS FALSE, WAL FALSE, GENERIC_PLAN TRUE, TIMING FALSE, SUMMARY FALSE, FORMAT TEXT) SELECT unique1 FROM pg16.tenk1_950001 tenk1 WHERE (thousand OPERATOR(pg_catalog.=) 1000)
-DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
-NOTICE: issuing ROLLBACK TO SAVEPOINT citus_explain_savepoint
-DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
-NOTICE: issuing COMMIT
-DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
- QUERY PLAN
----------------------------------------------------------------------
- Custom Scan (Citus Adaptive) (cost=0.00..0.00 rows=0 width=0)
- Task Count: 1
- Tasks Shown: All
- -> Task
- Node: host=localhost port=xxxxx dbname=regression
- -> Seq Scan on tenk1_950001 tenk1 (cost=0.00..35.50 rows=10 width=4)
- Filter: (thousand = 1000)
-(7 rows)
-
-EXPLAIN (GENERIC_PLAN, ANALYZE) SELECT unique1 FROM tenk1 WHERE thousand = 1000;
+EXPLAIN (GENERIC_PLAN) SELECT unique1 FROM tenk1 WHERE thousand = $1;
+ERROR: EXPLAIN GENERIC_PLAN is currently not supported for Citus tables
+EXPLAIN (GENERIC_PLAN, ANALYZE) SELECT unique1 FROM tenk1 WHERE thousand = $1;
ERROR: EXPLAIN options ANALYZE and GENERIC_PLAN cannot be used together
SET citus.log_remote_commands TO off;
-- Proper error when creating statistics without a name on a Citus table
diff --git a/src/test/regress/expected/remove_coordinator.out b/src/test/regress/expected/remove_coordinator.out
index 0226a7cd0..e2fd5df02 100644
--- a/src/test/regress/expected/remove_coordinator.out
+++ b/src/test/regress/expected/remove_coordinator.out
@@ -5,6 +5,37 @@ SELECT master_remove_node('localhost', :master_port);
(1 row)
+-- to silence -potentially flaky- "could not establish connection after" warnings in below test
+SET client_min_messages TO ERROR;
+-- to fail fast when the hostname is not resolvable, as it will be the case below
+SET citus.node_connection_timeout to '1s';
+BEGIN;
+ SET application_name TO 'new_app_name';
+ -- that should fail because of bad hostname & port
+ SELECT citus_add_node('200.200.200.200', 1, 200);
+ERROR: connection to the remote node postgres@200.200.200.200:1 failed
+ -- Since above command failed, now Postgres will need to revert the
+ -- application_name change made in this transaction and this will
+ -- happen within abort-transaction callback, so we won't be in a
+ -- transaction block while Postgres does that.
+ --
+ -- And when the application_name changes, Citus tries to re-assign
+ -- the global pid but it does so only for Citus internal backends,
+ -- and doing so for Citus internal backends doesn't require being
+ -- in a transaction block and is safe.
+ --
+ -- However, for the client external backends (like us here), Citus
+ -- doesn't re-assign the global pid because it's not needed and it's
+ -- not safe to do so outside of a transaction block. This is because,
+ -- it would require performing a catalog access to retrive the local
+ -- node id when the cached local node is invalidated like what just
+ -- happened here because of the failed citus_add_node() call made
+ -- above.
+ --
+ -- So by failing here (rather than crashing), we ensure this behavior.
+ROLLBACK;
+RESET client_min_messages;
+RESET citus.node_connection_timeout;
-- restore coordinator for the rest of the tests
SELECT citus_set_coordinator_host('localhost', :master_port);
citus_set_coordinator_host
diff --git a/src/test/regress/expected/system_queries.out b/src/test/regress/expected/system_queries.out
index cd2aef4d2..174f4cc10 100644
--- a/src/test/regress/expected/system_queries.out
+++ b/src/test/regress/expected/system_queries.out
@@ -1,3 +1,5 @@
+BEGIN;
+SET LOCAL citus.show_shards_for_app_name_prefixes = '';
-- The following query retrieves the foreign key constraints of the table "pg_dist_background_job"
-- along with their details. This modification includes a fix for a null pointer exception that occurred
-- in the "HasRangeTableRef" method of "worker_shard_visibility". The issue was resolved with PR #7604.
@@ -31,3 +33,4 @@ order by
pg_dist_background_task_depend_job_id_fkey | job_id | pg_dist_background_job | pg_catalog
(2 rows)
+END;
diff --git a/src/test/regress/expected/upgrade_list_citus_objects.out b/src/test/regress/expected/upgrade_list_citus_objects.out
index ca31b222b..9f404dead 100644
--- a/src/test/regress/expected/upgrade_list_citus_objects.out
+++ b/src/test/regress/expected/upgrade_list_citus_objects.out
@@ -64,27 +64,23 @@ ORDER BY 1;
function citus_internal.add_shard_metadata(regclass,bigint,"char",text,text)
function citus_internal.add_tenant_schema(oid,integer)
function citus_internal.adjust_local_clock_to_remote(cluster_clock)
- function citus_internal.commit_management_command_2pc()
function citus_internal.database_command(text)
function citus_internal.delete_colocation_metadata(integer)
function citus_internal.delete_partition_metadata(regclass)
function citus_internal.delete_placement_metadata(bigint)
function citus_internal.delete_shard_metadata(bigint)
function citus_internal.delete_tenant_schema(oid)
- function citus_internal.execute_command_on_remote_nodes_as_user(text,text)
function citus_internal.find_groupid_for_node(text,integer)
function citus_internal.global_blocked_processes()
function citus_internal.is_replication_origin_tracking_active()
function citus_internal.local_blocked_processes()
function citus_internal.mark_node_not_synced(integer,integer)
- function citus_internal.mark_object_distributed(oid,text,oid,text)
function citus_internal.pg_dist_node_trigger_func()
function citus_internal.pg_dist_rebalance_strategy_trigger_func()
function citus_internal.pg_dist_shard_placement_trigger_func()
function citus_internal.refresh_isolation_tester_prepared_statement()
function citus_internal.replace_isolation_tester_func()
function citus_internal.restore_isolation_tester_func()
- function citus_internal.start_management_transaction(xid8)
function citus_internal.start_replication_origin_tracking()
function citus_internal.stop_replication_origin_tracking()
function citus_internal.unregister_tenant_schema_globally(oid,text)
@@ -371,5 +367,5 @@ ORDER BY 1;
view citus_stat_tenants_local
view pg_dist_shard_placement
view time_partitions
-(361 rows)
+(357 rows)
diff --git a/src/test/regress/expected/upgrade_pg_dist_cleanup_after_0.out b/src/test/regress/expected/upgrade_pg_dist_cleanup_after_0.out
index d71fad887..168c64cca 100644
--- a/src/test/regress/expected/upgrade_pg_dist_cleanup_after_0.out
+++ b/src/test/regress/expected/upgrade_pg_dist_cleanup_after_0.out
@@ -28,3 +28,12 @@ SELECT * FROM pg_dist_cleanup;
CALL citus_cleanup_orphaned_resources();
NOTICE: cleaned up 1 orphaned resources
DROP TABLE table_with_orphaned_shards;
+-- Re-enable automatic shard cleanup by maintenance daemon as
+-- we have disabled it in upgrade_pg_dist_cleanup_before.sql
+ALTER SYSTEM RESET citus.defer_shard_delete_interval;
+SELECT pg_reload_conf();
+ pg_reload_conf
+---------------------------------------------------------------------
+ t
+(1 row)
+
diff --git a/src/test/regress/expected/upgrade_pg_dist_cleanup_before_0.out b/src/test/regress/expected/upgrade_pg_dist_cleanup_before_0.out
index a0cf9ceb1..dd6c8868e 100644
--- a/src/test/regress/expected/upgrade_pg_dist_cleanup_before_0.out
+++ b/src/test/regress/expected/upgrade_pg_dist_cleanup_before_0.out
@@ -30,6 +30,23 @@ SELECT COUNT(*) FROM pg_dist_placement WHERE shardstate = 1 AND shardid IN (SELE
(1 row)
-- create an orphaned placement based on an existing one
+--
+-- But before doing that, first disable automatic shard cleanup
+-- by maintenance daemon so that we can reliably test the cleanup
+-- in upgrade_pg_dist_cleanup_after.sql.
+ALTER SYSTEM SET citus.defer_shard_delete_interval TO -1;
+SELECT pg_reload_conf();
+ pg_reload_conf
+---------------------------------------------------------------------
+ t
+(1 row)
+
+SELECT pg_sleep(0.1);
+ pg_sleep
+---------------------------------------------------------------------
+
+(1 row)
+
INSERT INTO pg_dist_placement(placementid, shardid, shardstate, shardlength, groupid)
SELECT nextval('pg_dist_placement_placementid_seq'::regclass), shardid, 4, shardlength, 3-groupid
FROM pg_dist_placement
diff --git a/src/test/regress/failure_schedule b/src/test/regress/failure_schedule
index 8b992422e..7487ced3f 100644
--- a/src/test/regress/failure_schedule
+++ b/src/test/regress/failure_schedule
@@ -34,7 +34,6 @@ test: failure_multi_row_insert
test: failure_mx_metadata_sync
test: failure_mx_metadata_sync_multi_trans
test: failure_connection_establishment
-test: failure_non_main_db_2pc
test: failure_create_database
# this test syncs metadata to the workers
diff --git a/src/test/regress/multi_1_schedule b/src/test/regress/multi_1_schedule
index 015f74973..cfff00942 100644
--- a/src/test/regress/multi_1_schedule
+++ b/src/test/regress/multi_1_schedule
@@ -40,7 +40,6 @@ test: create_drop_database_propagation_pg15
test: create_drop_database_propagation_pg16
test: comment_on_database
test: comment_on_role
-test: metadata_sync_from_non_maindb
# don't parallelize single_shard_table_udfs to make sure colocation ids are sequential
test: single_shard_table_udfs
test: schema_based_sharding
@@ -58,7 +57,7 @@ test: multi_metadata_attributes
test: multi_read_from_secondaries
-test: grant_on_database_propagation grant_on_database_propagation_from_non_maindb
+test: grant_on_database_propagation
test: alter_database_propagation
test: citus_shards
diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule
index 220ce1964..535ef1d62 100644
--- a/src/test/regress/multi_schedule
+++ b/src/test/regress/multi_schedule
@@ -103,12 +103,11 @@ test: multi_dropped_column_aliases foreign_key_restriction_enforcement
test: binary_protocol
test: alter_table_set_access_method
test: alter_distributed_table
-test: issue_5248 issue_5099 issue_5763 issue_6543 issue_6758 issue_7477
+test: issue_5248 issue_5099 issue_5763 issue_6543 issue_6758 issue_7477 issue_7705
test: object_propagation_debug
test: undistribute_table
test: run_command_on_all_nodes
test: background_task_queue_monitor
-test: other_databases grant_role_from_non_maindb role_operations_from_non_maindb seclabel_non_maindb
test: citus_internal_access
test: function_with_case_when
diff --git a/src/test/regress/pg_regress_multi.pl b/src/test/regress/pg_regress_multi.pl
index 35671ad26..84207cd2e 100755
--- a/src/test/regress/pg_regress_multi.pl
+++ b/src/test/regress/pg_regress_multi.pl
@@ -492,7 +492,6 @@ push(@pgOptions, "citus.stat_statements_track = 'all'");
push(@pgOptions, "citus.enable_change_data_capture=on");
push(@pgOptions, "citus.stat_tenants_limit = 2");
push(@pgOptions, "citus.stat_tenants_track = 'ALL'");
-push(@pgOptions, "citus.main_db = 'regression'");
push(@pgOptions, "citus.superuser = 'postgres'");
# Some tests look at shards in pg_class, make sure we can usually see them:
diff --git a/src/test/regress/sql/citus_internal_access.sql b/src/test/regress/sql/citus_internal_access.sql
index 8e97448f3..9198180f9 100644
--- a/src/test/regress/sql/citus_internal_access.sql
+++ b/src/test/regress/sql/citus_internal_access.sql
@@ -3,7 +3,6 @@ CREATE USER nonsuperuser CREATEROLE;
SET ROLE nonsuperuser;
--- The non-superuser role should not be able to access citus_internal functions
-SELECT citus_internal.commit_management_command_2pc();
SELECT citus_internal.replace_isolation_tester_func();
RESET ROLE;
diff --git a/src/test/regress/sql/create_drop_database_propagation_pg15.sql b/src/test/regress/sql/create_drop_database_propagation_pg15.sql
index 4e006c54f..40d1b9e09 100644
--- a/src/test/regress/sql/create_drop_database_propagation_pg15.sql
+++ b/src/test/regress/sql/create_drop_database_propagation_pg15.sql
@@ -60,14 +60,6 @@ CREATE DATABASE test_locale_provider
SELECT * FROM public.check_database_on_all_nodes('test_locale_provider') ORDER BY node_type;
-\c test_locale_provider - - :worker_2_port
-
-set citus.enable_create_database_propagation to on;
-create database unsupported_option_from_non_main_db with oid = 12345;
-
-\c regression - - :master_port
-
-set citus.enable_create_database_propagation to on;
drop database test_locale_provider;
\c - - - :master_port
diff --git a/src/test/regress/sql/failure_non_main_db_2pc.sql b/src/test/regress/sql/failure_non_main_db_2pc.sql
deleted file mode 100644
index 74061ae34..000000000
--- a/src/test/regress/sql/failure_non_main_db_2pc.sql
+++ /dev/null
@@ -1,75 +0,0 @@
-SELECT citus.mitmproxy('conn.allow()');
-
-CREATE SCHEMA failure_non_main_db_2pc;
-SET SEARCH_PATH TO 'failure_non_main_db_2pc';
-
-CREATE DATABASE other_db1;
-
-SELECT citus.mitmproxy('conn.onQuery(query="COMMIT PREPARED").kill()');
-
-\c other_db1
-
-CREATE USER user_1;
-
-\c regression
-
-SELECT citus.mitmproxy('conn.allow()');
-
-SELECT nodeid, result FROM run_command_on_all_nodes($$SELECT rolname FROM pg_roles WHERE rolname::TEXT = 'user_1'$$) ORDER BY 1;
-
-SELECT recover_prepared_transactions();
-
-SELECT nodeid, result FROM run_command_on_all_nodes($$SELECT rolname FROM pg_roles WHERE rolname::TEXT = 'user_1'$$) ORDER BY 1;
-
-
-SELECT citus.mitmproxy('conn.onQuery(query="CREATE USER user_2").kill()');
-
-\c other_db1
-
-CREATE USER user_2;
-
-\c regression
-
-SELECT citus.mitmproxy('conn.allow()');
-
-SELECT nodeid, result FROM run_command_on_all_nodes($$SELECT rolname FROM pg_roles WHERE rolname::TEXT = 'user_2'$$) ORDER BY 1;
-
-SELECT recover_prepared_transactions();
-
-SELECT nodeid, result FROM run_command_on_all_nodes($$SELECT rolname FROM pg_roles WHERE rolname::TEXT = 'user_2'$$) ORDER BY 1;
-
-DROP DATABASE other_db1;
--- user_2 should not exist because the query to create it will fail
--- but let's make sure we try to drop it just in case
-DROP USER IF EXISTS user_1, user_2;
-
-SELECT citus_set_coordinator_host('localhost');
-
-\c - - - :worker_1_port
-
-CREATE DATABASE other_db2;
-
-SELECT citus.mitmproxy('conn.onQuery(query="COMMIT PREPARED").kill()');
-
-\c other_db2
-
-CREATE USER user_3;
-
-\c regression
-
-SELECT citus.mitmproxy('conn.allow()');
-
-SELECT result FROM run_command_on_all_nodes($$SELECT rolname FROM pg_roles WHERE rolname::TEXT = 'user_3'$$) ORDER BY 1;
-
-SELECT recover_prepared_transactions();
-
-SELECT result FROM run_command_on_all_nodes($$SELECT rolname FROM pg_roles WHERE rolname::TEXT = 'user_3'$$) ORDER BY 1;
-
-DROP DATABASE other_db2;
-DROP USER user_3;
-
-\c - - - :master_port
-
-SELECT result FROM run_command_on_all_nodes($$DELETE FROM pg_dist_node WHERE groupid = 0$$);
-
-DROP SCHEMA failure_non_main_db_2pc;
diff --git a/src/test/regress/sql/grant_on_database_propagation_from_non_maindb.sql b/src/test/regress/sql/grant_on_database_propagation_from_non_maindb.sql
deleted file mode 100644
index f83472b36..000000000
--- a/src/test/regress/sql/grant_on_database_propagation_from_non_maindb.sql
+++ /dev/null
@@ -1,246 +0,0 @@
--- Public role has connect,temp,temporary privileges on database
--- To test these scenarios, we need to revoke these privileges from public role
--- since public role privileges are inherited by new roles/users
-set citus.enable_create_database_propagation to on;
-create database test_2pc_db;
-show citus.main_db;
-revoke connect,temp,temporary on database test_2pc_db from public;
-
-CREATE SCHEMA grant_on_database_propagation_non_maindb;
-SET search_path TO grant_on_database_propagation_non_maindb;
-
--- test grant/revoke CREATE privilege propagation on database
-create user "myuser'_test";
-
-\c test_2pc_db - - :master_port
-grant create on database test_2pc_db to "myuser'_test";
-
-\c regression - - :master_port;
-select check_database_privileges('myuser''_test','test_2pc_db',ARRAY['CREATE']);
-
-\c test_2pc_db - - :master_port
-revoke create on database test_2pc_db from "myuser'_test";
-
-\c regression - - :master_port;
-select check_database_privileges('myuser''_test','test_2pc_db',ARRAY['CREATE']);
-
-drop user "myuser'_test";
------------------------------------------------------------------------
-
--- test grant/revoke CONNECT privilege propagation on database
-\c regression - - :master_port
-create user myuser2;
-
-\c test_2pc_db - - :master_port
-grant CONNECT on database test_2pc_db to myuser2;
-
-\c regression - - :master_port;
-select check_database_privileges('myuser2','test_2pc_db',ARRAY['CONNECT']);
-
-\c test_2pc_db - - :master_port
-revoke connect on database test_2pc_db from myuser2;
-
-\c regression - - :master_port
-select check_database_privileges('myuser2','test_2pc_db',ARRAY['CONNECT']);
-
-drop user myuser2;
-
------------------------------------------------------------------------
-
--- test grant/revoke TEMP privilege propagation on database
-\c regression - - :master_port
-create user myuser3;
-
--- test grant/revoke temp on database
-\c test_2pc_db - - :master_port
-grant TEMP on database test_2pc_db to myuser3;
-
-\c regression - - :master_port;
-select check_database_privileges('myuser3','test_2pc_db',ARRAY['TEMP']);
-
-
-\c test_2pc_db - - :worker_1_port
-revoke TEMP on database test_2pc_db from myuser3;
-
-\c regression - - :master_port;
-select check_database_privileges('myuser3','test_2pc_db',ARRAY['TEMP']);
-
-drop user myuser3;
-
------------------------------------------------------------------------
-
-\c regression - - :master_port
--- test temporary privilege on database
-create user myuser4;
-
--- test grant/revoke temporary on database
-\c test_2pc_db - - :worker_1_port
-grant TEMPORARY on database test_2pc_db to myuser4;
-
-\c regression - - :master_port
-select check_database_privileges('myuser4','test_2pc_db',ARRAY['TEMPORARY']);
-
-\c test_2pc_db - - :master_port
-revoke TEMPORARY on database test_2pc_db from myuser4;
-
-\c regression - - :master_port;
-select check_database_privileges('myuser4','test_2pc_db',ARRAY['TEMPORARY']);
-
-drop user myuser4;
------------------------------------------------------------------------
-
--- test ALL privileges with ALL statement on database
-create user myuser5;
-
-grant ALL on database test_2pc_db to myuser5;
-
-\c regression - - :master_port
-select check_database_privileges('myuser5','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-
-
-\c test_2pc_db - - :master_port
-revoke ALL on database test_2pc_db from myuser5;
-
-\c regression - - :master_port
-select check_database_privileges('myuser5','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-
-drop user myuser5;
------------------------------------------------------------------------
-
--- test CREATE,CONNECT,TEMP,TEMPORARY privileges one by one on database
-create user myuser6;
-
-\c test_2pc_db - - :master_port
-grant CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db to myuser6;
-
-\c regression - - :master_port
-select check_database_privileges('myuser6','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-
-\c test_2pc_db - - :master_port
-revoke CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db from myuser6;
-
-\c regression - - :master_port
-select check_database_privileges('myuser6','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-
-
-drop user myuser6;
------------------------------------------------------------------------
-
--- test CREATE,CONNECT,TEMP,TEMPORARY privileges one by one on database with grant option
-create user myuser7;
-create user myuser_1;
-
-\c test_2pc_db - - :master_port
-grant CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db to myuser7;
-
-set role myuser7;
---here since myuser7 does not have grant option, it should fail
-grant CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db to myuser_1;
-
-\c regression - - :master_port
-select check_database_privileges('myuser_1','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-
-\c test_2pc_db - - :master_port
-
-RESET ROLE;
-
-grant CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db to myuser7 with grant option;
-set role myuser7;
-
---here since myuser have grant option, it should succeed
-grant CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db to myuser_1 granted by myuser7;
-
-\c regression - - :master_port
-select check_database_privileges('myuser_1','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-
-\c test_2pc_db - - :master_port
-
-RESET ROLE;
-
---below test should fail and should throw an error since myuser_1 still have the dependent privileges
-revoke CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db from myuser7 restrict;
---below test should fail and should throw an error since myuser_1 still have the dependent privileges
-revoke grant option for CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db from myuser7 restrict ;
-
---below test should succeed and should not throw any error since myuser_1 privileges are revoked with cascade
-revoke grant option for CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db from myuser7 cascade ;
-
---here we test if myuser7 still have the privileges after revoke grant option for
-
-\c regression - - :master_port
-select check_database_privileges('myuser7','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-
-
-\c test_2pc_db - - :master_port
-
-reset role;
-
-revoke CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db from myuser7;
-revoke CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db from myuser_1;
-
-\c regression - - :master_port
-drop user myuser_1;
-drop user myuser7;
-
------------------------------------------------------------------------
-
--- test CREATE,CONNECT,TEMP,TEMPORARY privileges one by one on database multi database
--- and multi user
-\c regression - - :master_port
-create user myuser8;
-create user myuser_2;
-
-set citus.enable_create_database_propagation to on;
-create database test_db;
-
-revoke connect,temp,temporary on database test_db from public;
-
-\c test_2pc_db - - :master_port
-grant CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db,test_db to myuser8,myuser_2;
-
-\c regression - - :master_port
-select check_database_privileges('myuser8','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-select check_database_privileges('myuser8','test_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-select check_database_privileges('myuser_2','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-select check_database_privileges('myuser_2','test_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-
-
-\c test_2pc_db - - :master_port
-
-RESET ROLE;
-revoke CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db,test_db from myuser8 ;
-
---below test should succeed and should not throw any error
-revoke CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db,test_db from myuser_2;
-
---below test should succeed and should not throw any error
-revoke CREATE,CONNECT,TEMP,TEMPORARY on database test_2pc_db,test_db from myuser8 cascade;
-
-\c regression - - :master_port
-select check_database_privileges('myuser8','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-select check_database_privileges('myuser8','test_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-select check_database_privileges('myuser_2','test_2pc_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-select check_database_privileges('myuser_2','test_db',ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
-
-
-\c test_2pc_db - - :master_port
-
-reset role;
-
-\c regression - - :master_port
-drop user myuser_2;
-drop user myuser8;
-
-set citus.enable_create_database_propagation to on;
-drop database test_db;
-
----------------------------------------------------------------------------
--- rollbacks public role database privileges to original state
-grant connect,temp,temporary on database test_2pc_db to public;
-drop database test_2pc_db;
-set citus.enable_create_database_propagation to off;
-DROP SCHEMA grant_on_database_propagation_non_maindb CASCADE;
-
-reset citus.enable_create_database_propagation;
-reset search_path;
----------------------------------------------------------------------------
diff --git a/src/test/regress/sql/grant_role_from_non_maindb.sql b/src/test/regress/sql/grant_role_from_non_maindb.sql
deleted file mode 100644
index b74b5092d..000000000
--- a/src/test/regress/sql/grant_role_from_non_maindb.sql
+++ /dev/null
@@ -1,147 +0,0 @@
-CREATE SCHEMA grant_role2pc;
-SET search_path TO grant_role2pc;
-set citus.enable_create_database_propagation to on;
-
-CREATE DATABASE grant_role2pc_db;
-
-\c grant_role2pc_db
-SHOW citus.main_db;
-
-SET citus.superuser TO 'postgres';
-CREATE USER grant_role2pc_user1;
-CREATE USER grant_role2pc_user2;
-CREATE USER grant_role2pc_user3;
-CREATE USER grant_role2pc_user4;
-CREATE USER grant_role2pc_user5;
-CREATE USER grant_role2pc_user6;
-CREATE USER grant_role2pc_user7;
-
-\c grant_role2pc_db
-
---test with empty superuser
-SET citus.superuser TO '';
-grant grant_role2pc_user1 to grant_role2pc_user2;
-
-SET citus.superuser TO 'postgres';
-grant grant_role2pc_user1 to grant_role2pc_user2 with admin option granted by CURRENT_USER;
-
-\c regression
-
-select result FROM run_command_on_all_nodes(
- $$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
- FROM pg_auth_members
- WHERE member::regrole::text = 'grant_role2pc_user2'
- order by member::regrole::text, roleid::regrole::text
- ) t
- $$
-);
-
-\c grant_role2pc_db
---test grant under transactional context with multiple operations
-BEGIN;
-grant grant_role2pc_user1,grant_role2pc_user2 to grant_role2pc_user3 WITH ADMIN OPTION;
-grant grant_role2pc_user1 to grant_role2pc_user4 granted by grant_role2pc_user3 ;
-COMMIT;
-
-BEGIN;
-grant grant_role2pc_user1 to grant_role2pc_user5 WITH ADMIN OPTION granted by grant_role2pc_user3;
-grant grant_role2pc_user1 to grant_role2pc_user6;
-ROLLBACK;
-
-
-
-BEGIN;
-grant grant_role2pc_user1 to grant_role2pc_user7;
-SELECT 1/0;
-commit;
-
-
-\c regression
-
-select result FROM run_command_on_all_nodes($$
-SELECT array_to_json(array_agg(row_to_json(t)))
-FROM (
- SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
- FROM pg_auth_members
- WHERE member::regrole::text in
- ('grant_role2pc_user3','grant_role2pc_user4','grant_role2pc_user5','grant_role2pc_user6','grant_role2pc_user7')
- order by member::regrole::text, roleid::regrole::text
-) t
-$$);
-
-
-\c grant_role2pc_db
-
-grant grant_role2pc_user1,grant_role2pc_user2 to grant_role2pc_user5,grant_role2pc_user6,grant_role2pc_user7 granted by grant_role2pc_user3;
-
-\c regression
-
-select result FROM run_command_on_all_nodes($$
-SELECT array_to_json(array_agg(row_to_json(t)))
-FROM (
- SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
- FROM pg_auth_members
- WHERE member::regrole::text in
- ('grant_role2pc_user5','grant_role2pc_user6','grant_role2pc_user7')
- order by member::regrole::text, roleid::regrole::text
-) t
-$$);
-
-\c grant_role2pc_db
-revoke admin option for grant_role2pc_user1 from grant_role2pc_user5 granted by grant_role2pc_user3;
-
---test revoke under transactional context with multiple operations
-BEGIN;
-revoke grant_role2pc_user1 from grant_role2pc_user5 granted by grant_role2pc_user3 ;
-revoke grant_role2pc_user1 from grant_role2pc_user4 granted by grant_role2pc_user3;
-COMMIT;
-\c grant_role2pc_db - - :worker_1_port
-BEGIN;
-revoke grant_role2pc_user1 from grant_role2pc_user6,grant_role2pc_user7 granted by grant_role2pc_user3;
-revoke grant_role2pc_user1 from grant_role2pc_user3 cascade;
-COMMIT;
-
-\c regression
-
-select result FROM run_command_on_all_nodes($$
-SELECT array_to_json(array_agg(row_to_json(t)))
-FROM (
- SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
- FROM pg_auth_members
- WHERE member::regrole::text in
- ('grant_role2pc_user2','grant_role2pc_user3','grant_role2pc_user4','grant_role2pc_user5','grant_role2pc_user6','grant_role2pc_user7')
- order by member::regrole::text, roleid::regrole::text
-) t
-$$);
-
-\c grant_role2pc_db - - :worker_1_port
-BEGIN;
-grant grant_role2pc_user1 to grant_role2pc_user5 WITH ADMIN OPTION;
-grant grant_role2pc_user1 to grant_role2pc_user6;
-COMMIT;
-
-\c regression - - :master_port
-
-select result FROM run_command_on_all_nodes($$
-SELECT array_to_json(array_agg(row_to_json(t)))
-FROM (
- SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
- FROM pg_auth_members
- WHERE member::regrole::text in
- ('grant_role2pc_user5','grant_role2pc_user6')
- order by member::regrole::text, roleid::regrole::text
-) t
-$$);
-
-revoke grant_role2pc_user1 from grant_role2pc_user5,grant_role2pc_user6;
-
---clean resources
-DROP SCHEMA grant_role2pc;
-set citus.enable_create_database_propagation to on;
-DROP DATABASE grant_role2pc_db;
-drop user grant_role2pc_user2,grant_role2pc_user3,grant_role2pc_user4,grant_role2pc_user5,grant_role2pc_user6,grant_role2pc_user7;
-drop user grant_role2pc_user1;
-reset citus.enable_create_database_propagation;
diff --git a/src/test/regress/sql/issue_7705.sql b/src/test/regress/sql/issue_7705.sql
new file mode 100644
index 000000000..950933017
--- /dev/null
+++ b/src/test/regress/sql/issue_7705.sql
@@ -0,0 +1,72 @@
+--- Test for verifying that column references (var nodes) in targets that cannot be pushed down
+--- do not cause issues for the postgres planner, in particular postgres versions 16+, where the
+--- varnullingrels field of a VAR node may contain relids of join relations that can make the var
+--- NULL; in a rewritten distributed query without a join such relids do not have a meaning.
+--- Issue #7705: [SEGFAULT] Querying distributed tables with window partition causes segmentation fault
+--- https://github.com/citusdata/citus/issues/7705
+
+CREATE SCHEMA issue_7705;
+SET search_path to 'issue_7705';
+SET citus.next_shard_id TO 30070000;
+SET citus.shard_replication_factor TO 1;
+SET citus.enable_local_execution TO ON;
+
+CREATE TABLE t1 (id INT PRIMARY KEY);
+INSERT INTO t1 VALUES (1), (2);
+
+CREATE TABLE t2 (id INT, account_id INT, a2 INT, PRIMARY KEY(id, account_id));
+INSERT INTO t2 VALUES (3, 1, 10), (4, 2, 20), (5, 1, NULL);
+
+SELECT create_distributed_table('t1', 'id');
+SELECT create_distributed_table('t2', 'account_id');
+
+-- Test the issue seen in #7705; a target expression with
+-- a window function that cannot be pushed down because the
+-- partion by is not on the distribution column also includes
+-- a column from the inner side of a left outer join, which
+-- produces a non-empty varnullingrels set in PG 16 (and higher)
+SELECT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id;
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id;
+
+SELECT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t2 RIGHT OUTER JOIN t1 ON t1.id = t2.account_id;
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t2 RIGHT OUTER JOIN t1 ON t1.id = t2.account_id;
+
+SELECT DISTINCT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id;
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT DISTINCT t1.id, MAX(t2.a2) OVER (PARTITION BY t2.id)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id;
+
+CREATE SEQUENCE test_seq START 101;
+CREATE OR REPLACE FUNCTION TEST_F(int) returns INT language sql stable as $$ select $1 + 42; $$ ;
+
+-- Issue #7705 also occurs if a target expression includes a column
+-- of a distributed table that is on the inner side of a left outer
+-- join and a call to nextval(), because nextval() cannot be pushed
+-- down, and must be run on the coordinator
+SELECT t1.id, TEST_F(t2.a2 + nextval('test_seq') :: int)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id
+ORDER BY t1.id;
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT t1.id, TEST_F(t2.a2 + nextval('test_seq') :: int)
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id
+ORDER BY t1.id;
+
+SELECT t1.id, CASE nextval('test_seq') % 2 = 0 WHEN true THEN t2.a2 ELSE 1 END
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id
+ORDER BY t1.id;
+EXPLAIN (VERBOSE, COSTS OFF, TIMING OFF)
+SELECT t1.id, CASE nextval('test_seq') %2 = 0 WHEN true THEN t2.a2 ELSE 1 END
+FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.account_id
+ORDER BY t1.id;
+
+--- cleanup
+\set VERBOSITY TERSE
+DROP SCHEMA issue_7705 CASCADE;
+RESET all;
diff --git a/src/test/regress/sql/metadata_sync_from_non_maindb.sql b/src/test/regress/sql/metadata_sync_from_non_maindb.sql
deleted file mode 100644
index 62760c6cc..000000000
--- a/src/test/regress/sql/metadata_sync_from_non_maindb.sql
+++ /dev/null
@@ -1,188 +0,0 @@
-CREATE SCHEMA metadata_sync_2pc_schema;
-SET search_path TO metadata_sync_2pc_schema;
-set citus.enable_create_database_propagation to on;
-CREATE DATABASE metadata_sync_2pc_db;
-
-revoke connect,temp,temporary on database metadata_sync_2pc_db from public;
-
-\c metadata_sync_2pc_db
-SHOW citus.main_db;
-
-CREATE USER "grant_role2pc'_user1";
-CREATE USER "grant_role2pc'_user2";
-CREATE USER "grant_role2pc'_user3";
-CREATE USER grant_role2pc_user4;
-CREATE USER grant_role2pc_user5;
-
-\c regression
-select 1 from citus_remove_node('localhost', :worker_2_port);
-
-\c metadata_sync_2pc_db
-grant "grant_role2pc'_user1","grant_role2pc'_user2" to "grant_role2pc'_user3" WITH ADMIN OPTION;
--- This section was originally testing a scenario where a user with the 'admin option' grants the same role to another user, also with the 'admin option'.
--- However, we encountered inconsistent errors because the 'admin option' grant is executed after the grant below.
--- Once we establish the correct order of granting, we will reintroduce the 'granted by' clause.
--- For now, we are commenting out the grant below that includes 'granted by', and instead, we are adding a grant without the 'granted by' clause.
--- grant "grant_role2pc'_user1","grant_role2pc'_user2" to grant_role2pc_user4,grant_role2pc_user5 granted by "grant_role2pc'_user3";
-grant "grant_role2pc'_user1","grant_role2pc'_user2" to grant_role2pc_user4,grant_role2pc_user5;
-
---test for grant on database
-\c metadata_sync_2pc_db - - :master_port
-grant create on database metadata_sync_2pc_db to "grant_role2pc'_user1";
-grant connect on database metadata_sync_2pc_db to "grant_role2pc'_user2";
-grant ALL on database metadata_sync_2pc_db to "grant_role2pc'_user3";
-
-\c regression
-select check_database_privileges('grant_role2pc''_user1','metadata_sync_2pc_db',ARRAY['CREATE']);
-select check_database_privileges('grant_role2pc''_user2','metadata_sync_2pc_db',ARRAY['CONNECT']);
-select check_database_privileges('grant_role2pc''_user3','metadata_sync_2pc_db',ARRAY['CREATE','CONNECT','TEMP','TEMPORARY']);
-
--- test for security label on role
-\c metadata_sync_2pc_db - - :master_port
-SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE grant_role2pc_user4 IS 'citus_unclassified';
-SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE "grant_role2pc'_user1" IS 'citus_classified';
-
-\c regression
-SELECT node_type, result FROM get_citus_tests_label_provider_labels('grant_role2pc_user4') ORDER BY node_type;
-SELECT node_type, result FROM get_citus_tests_label_provider_labels($$"grant_role2pc''_user1"$$) ORDER BY node_type;
-
-set citus.enable_create_database_propagation to on;
-select 1 from citus_add_node('localhost', :worker_2_port);
-
-select result FROM run_command_on_all_nodes($$
-SELECT array_to_json(array_agg(row_to_json(t)))
-FROM (
- SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
- FROM pg_auth_members
- WHERE member::regrole::text in
- ('"grant_role2pc''_user2"','"grant_role2pc''_user3"','grant_role2pc_user4','grant_role2pc_user5')
- order by member::regrole::text
-) t
-$$);
-
-select check_database_privileges('grant_role2pc''_user1','metadata_sync_2pc_db',ARRAY['CREATE']);
-select check_database_privileges('grant_role2pc''_user2','metadata_sync_2pc_db',ARRAY['CONNECT']);
-select check_database_privileges('grant_role2pc''_user3','metadata_sync_2pc_db',ARRAY['CREATE','CONNECT','TEMP','TEMPORARY']);
-
-SELECT node_type, result FROM get_citus_tests_label_provider_labels('grant_role2pc_user4') ORDER BY node_type;
-SELECT node_type, result FROM get_citus_tests_label_provider_labels($$"grant_role2pc''_user1"$$) ORDER BY node_type;
-
-\c metadata_sync_2pc_db
-revoke "grant_role2pc'_user1","grant_role2pc'_user2" from grant_role2pc_user4,grant_role2pc_user5 ;
-
-revoke admin option for "grant_role2pc'_user1","grant_role2pc'_user2" from "grant_role2pc'_user3";
-
-revoke "grant_role2pc'_user1","grant_role2pc'_user2" from "grant_role2pc'_user3";
-revoke ALL on database metadata_sync_2pc_db from "grant_role2pc'_user3";
-revoke CONNECT on database metadata_sync_2pc_db from "grant_role2pc'_user2";
-revoke CREATE on database metadata_sync_2pc_db from "grant_role2pc'_user1";
-
-\c regression
-
-drop user "grant_role2pc'_user1","grant_role2pc'_user2","grant_role2pc'_user3",grant_role2pc_user4,grant_role2pc_user5;
---test for user operations
-
---test for create user
-\c regression - - :master_port
-select 1 from citus_remove_node('localhost', :worker_2_port);
-
-\c metadata_sync_2pc_db - - :master_port
-CREATE ROLE test_role1 WITH LOGIN PASSWORD 'password1';
-
-\c metadata_sync_2pc_db - - :worker_1_port
-CREATE USER "test_role2-needs\!escape"
-WITH
- SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN REPLICATION BYPASSRLS CONNECTION
-LIMIT 10 VALID UNTIL '2023-01-01' IN ROLE test_role1;
-
-create role test_role3;
-
-\c regression - - :master_port
-select 1 from citus_add_node('localhost', :worker_2_port);
-
-select result FROM run_command_on_all_nodes($$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb,
- rolcanlogin, rolreplication, rolbypassrls, rolconnlimit,
- (rolpassword != '') as pass_not_empty, DATE(rolvaliduntil)
- FROM pg_authid
- WHERE rolname in ('test_role1', 'test_role2-needs\!escape','test_role3')
- ORDER BY rolname
- ) t
-$$);
-
---test for alter user
-select 1 from citus_remove_node('localhost', :worker_2_port);
-\c metadata_sync_2pc_db - - :master_port
--- Test ALTER ROLE with various options
-ALTER ROLE test_role1 WITH PASSWORD 'new_password1';
-
-\c metadata_sync_2pc_db - - :worker_1_port
-ALTER USER "test_role2-needs\!escape"
-WITH
- NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION
-LIMIT 5 VALID UNTIL '2024-01-01';
-
-\c regression - - :master_port
-select 1 from citus_add_node('localhost', :worker_2_port);
-
-select result FROM run_command_on_all_nodes($$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb,
- rolcanlogin, rolreplication, rolbypassrls, rolconnlimit,
- (rolpassword != '') as pass_not_empty, DATE(rolvaliduntil)
- FROM pg_authid
- WHERE rolname in ('test_role1', 'test_role2-needs\!escape','test_role3')
- ORDER BY rolname
- ) t
-$$);
-
---test for drop user
-select 1 from citus_remove_node('localhost', :worker_2_port);
-
-\c metadata_sync_2pc_db - - :worker_1_port
-DROP ROLE test_role1, "test_role2-needs\!escape";
-
-\c metadata_sync_2pc_db - - :master_port
-DROP ROLE test_role3;
-
-\c regression - - :master_port
-select 1 from citus_add_node('localhost', :worker_2_port);
-
-select result FROM run_command_on_all_nodes($$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb,
- rolcanlogin, rolreplication, rolbypassrls, rolconnlimit,
- (rolpassword != '') as pass_not_empty, DATE(rolvaliduntil)
- FROM pg_authid
- WHERE rolname in ('test_role1', 'test_role2-needs\!escape','test_role3')
- ORDER BY rolname
- ) t
-$$);
-
--- Clean up: drop the database on worker node 2
-\c regression - - :worker_2_port
-DROP ROLE if exists test_role1, "test_role2-needs\!escape", test_role3;
-
-\c regression - - :master_port
-
-select result FROM run_command_on_all_nodes($$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb,
- rolcanlogin, rolreplication, rolbypassrls, rolconnlimit,
- (rolpassword != '') as pass_not_empty, DATE(rolvaliduntil)
- FROM pg_authid
- WHERE rolname in ('test_role1', 'test_role2-needs\!escape','test_role3')
- ORDER BY rolname
- ) t
-$$);
-
-set citus.enable_create_database_propagation to on;
-drop database metadata_sync_2pc_db;
-drop schema metadata_sync_2pc_schema;
-reset citus.enable_create_database_propagation;
-reset search_path;
diff --git a/src/test/regress/sql/other_databases.sql b/src/test/regress/sql/other_databases.sql
deleted file mode 100644
index aa936e507..000000000
--- a/src/test/regress/sql/other_databases.sql
+++ /dev/null
@@ -1,182 +0,0 @@
-CREATE SCHEMA other_databases;
-SET search_path TO other_databases;
-
-SET citus.next_shard_id TO 10231023;
-
-CREATE DATABASE other_db1;
-
-\c other_db1
-SHOW citus.main_db;
-
--- check that empty citus.superuser gives error
-SET citus.superuser TO '';
-CREATE USER empty_superuser;
-SET citus.superuser TO 'postgres';
-
-CREATE USER other_db_user1;
-CREATE USER other_db_user2;
-
-BEGIN;
-CREATE USER other_db_user3;
-CREATE USER other_db_user4;
-COMMIT;
-
-BEGIN;
-CREATE USER other_db_user5;
-CREATE USER other_db_user6;
-ROLLBACK;
-
-BEGIN;
-CREATE USER other_db_user7;
-SELECT 1/0;
-COMMIT;
-
-CREATE USER other_db_user8;
-
-\c regression
-SELECT usename FROM pg_user WHERE usename LIKE 'other\_db\_user%' ORDER BY 1;
-
-\c - - - :worker_1_port
-SELECT usename FROM pg_user WHERE usename LIKE 'other\_db\_user%' ORDER BY 1;
-
-\c - - - :master_port
--- some user creation commands will fail but let's make sure we try to drop them just in case
-DROP USER IF EXISTS other_db_user1, other_db_user2, other_db_user3, other_db_user4, other_db_user5, other_db_user6, other_db_user7, other_db_user8;
-
--- Make sure non-superuser roles cannot use internal GUCs
--- but they can still create a role
-CREATE USER nonsuperuser CREATEROLE;
-GRANT ALL ON SCHEMA citus_internal TO nonsuperuser;
-SET ROLE nonsuperuser;
-SELECT citus_internal.execute_command_on_remote_nodes_as_user($$SELECT 'dangerous query'$$, 'postgres');
-
-\c other_db1
-SET citus.local_hostname TO '127.0.0.1';
-SET ROLE nonsuperuser;
-
--- Make sure that we don't try to access pg_dist_node.
--- Otherwise, we would get the following error:
--- ERROR: cache lookup failed for pg_dist_node, called too early?
-CREATE USER other_db_user9;
-
-RESET ROLE;
-RESET citus.local_hostname;
-RESET ROLE;
-\c regression
-SELECT usename FROM pg_user WHERE usename LIKE 'other\_db\_user%' ORDER BY 1;
-
-\c - - - :worker_1_port
-SELECT usename FROM pg_user WHERE usename LIKE 'other\_db\_user%' ORDER BY 1;
-
-\c - - - :master_port
-REVOKE ALL ON SCHEMA citus_internal FROM nonsuperuser;
-DROP USER other_db_user9, nonsuperuser;
-
--- test from a worker
-\c - - - :worker_1_port
-
-CREATE DATABASE worker_other_db;
-
-\c worker_other_db
-
-CREATE USER worker_user1;
-
-BEGIN;
-CREATE USER worker_user2;
-COMMIT;
-
-BEGIN;
-CREATE USER worker_user3;
-ROLLBACK;
-
-\c regression
-SELECT usename FROM pg_user WHERE usename LIKE 'worker\_user%' ORDER BY 1;
-
-\c - - - :master_port
-SELECT usename FROM pg_user WHERE usename LIKE 'worker\_user%' ORDER BY 1;
-
--- some user creation commands will fail but let's make sure we try to drop them just in case
-DROP USER IF EXISTS worker_user1, worker_user2, worker_user3;
-
--- test creating and dropping a database from a Citus non-main database
-SELECT result FROM run_command_on_all_nodes($$ALTER SYSTEM SET citus.enable_create_database_propagation TO true$$);
-SELECT result FROM run_command_on_all_nodes($$SELECT pg_reload_conf()$$);
-SELECT pg_sleep(0.1);
-\c other_db1
-CREATE DATABASE other_db3;
-
-\c regression
-SELECT * FROM public.check_database_on_all_nodes('other_db3') ORDER BY node_type;
-
-\c other_db1
-DROP DATABASE other_db3;
-
-\c regression
-SELECT * FROM public.check_database_on_all_nodes('other_db3') ORDER BY node_type;
-
-\c worker_other_db - - :worker_1_port
-CREATE DATABASE other_db4;
-
-\c regression
-SELECT * FROM public.check_database_on_all_nodes('other_db4') ORDER BY node_type;
-
-\c worker_other_db
-DROP DATABASE other_db4;
-
-\c regression
-SELECT * FROM public.check_database_on_all_nodes('other_db4') ORDER BY node_type;
-
-DROP DATABASE worker_other_db;
-
-CREATE DATABASE other_db5;
-
--- disable create database propagation for the next test
-SELECT result FROM run_command_on_all_nodes($$ALTER SYSTEM SET citus.enable_create_database_propagation TO false$$);
-SELECT result FROM run_command_on_all_nodes($$SELECT pg_reload_conf()$$);
-SELECT pg_sleep(0.1);
-
-\c other_db5 - - :worker_2_port
-
--- locally create a database
-CREATE DATABASE local_db;
-
-\c regression - - -
-
--- re-enable create database propagation
-SELECT result FROM run_command_on_all_nodes($$ALTER SYSTEM SET citus.enable_create_database_propagation TO true$$);
-SELECT result FROM run_command_on_all_nodes($$SELECT pg_reload_conf()$$);
-SELECT pg_sleep(0.1);
-
-\c other_db5 - - :master_port
-
--- Test a scenario where create database fails because the database
--- already exists on another node and we don't crash etc.
-CREATE DATABASE local_db;
-
-\c regression - - -
-
-SELECT * FROM public.check_database_on_all_nodes('local_db') ORDER BY node_type, result;
-
-\c - - - :worker_2_port
-
--- locally drop the database for cleanup purposes
-SELECT result FROM run_command_on_all_nodes($$ALTER SYSTEM SET citus.enable_create_database_propagation TO false$$);
-SELECT result FROM run_command_on_all_nodes($$SELECT pg_reload_conf()$$);
-SELECT pg_sleep(0.1);
-
-DROP DATABASE local_db;
-
-SELECT result FROM run_command_on_all_nodes($$ALTER SYSTEM SET citus.enable_create_database_propagation TO true$$);
-SELECT result FROM run_command_on_all_nodes($$SELECT pg_reload_conf()$$);
-SELECT pg_sleep(0.1);
-
-\c - - - :master_port
-
-DROP DATABASE other_db5;
-
-SELECT result FROM run_command_on_all_nodes($$ALTER SYSTEM SET citus.enable_create_database_propagation TO false$$);
-SELECT result FROM run_command_on_all_nodes($$SELECT pg_reload_conf()$$);
-SELECT pg_sleep(0.1);
-
-DROP SCHEMA other_databases;
-DROP DATABASE other_db1;
diff --git a/src/test/regress/sql/pg16.sql b/src/test/regress/sql/pg16.sql
index 99024edcb..0312fcdff 100644
--- a/src/test/regress/sql/pg16.sql
+++ b/src/test/regress/sql/pg16.sql
@@ -58,8 +58,8 @@ CREATE TABLE tenk1 (
SELECT create_distributed_table('tenk1', 'unique1');
SET citus.log_remote_commands TO on;
-EXPLAIN (GENERIC_PLAN) SELECT unique1 FROM tenk1 WHERE thousand = 1000;
-EXPLAIN (GENERIC_PLAN, ANALYZE) SELECT unique1 FROM tenk1 WHERE thousand = 1000;
+EXPLAIN (GENERIC_PLAN) SELECT unique1 FROM tenk1 WHERE thousand = $1;
+EXPLAIN (GENERIC_PLAN, ANALYZE) SELECT unique1 FROM tenk1 WHERE thousand = $1;
SET citus.log_remote_commands TO off;
-- Proper error when creating statistics without a name on a Citus table
diff --git a/src/test/regress/sql/remove_coordinator.sql b/src/test/regress/sql/remove_coordinator.sql
index b0df327d1..35a8a5718 100644
--- a/src/test/regress/sql/remove_coordinator.sql
+++ b/src/test/regress/sql/remove_coordinator.sql
@@ -1,5 +1,41 @@
-- removing coordinator from pg_dist_node should update pg_dist_colocation
SELECT master_remove_node('localhost', :master_port);
+-- to silence -potentially flaky- "could not establish connection after" warnings in below test
+SET client_min_messages TO ERROR;
+
+-- to fail fast when the hostname is not resolvable, as it will be the case below
+SET citus.node_connection_timeout to '1s';
+
+BEGIN;
+ SET application_name TO 'new_app_name';
+
+ -- that should fail because of bad hostname & port
+ SELECT citus_add_node('200.200.200.200', 1, 200);
+
+ -- Since above command failed, now Postgres will need to revert the
+ -- application_name change made in this transaction and this will
+ -- happen within abort-transaction callback, so we won't be in a
+ -- transaction block while Postgres does that.
+ --
+ -- And when the application_name changes, Citus tries to re-assign
+ -- the global pid but it does so only for Citus internal backends,
+ -- and doing so for Citus internal backends doesn't require being
+ -- in a transaction block and is safe.
+ --
+ -- However, for the client external backends (like us here), Citus
+ -- doesn't re-assign the global pid because it's not needed and it's
+ -- not safe to do so outside of a transaction block. This is because,
+ -- it would require performing a catalog access to retrive the local
+ -- node id when the cached local node is invalidated like what just
+ -- happened here because of the failed citus_add_node() call made
+ -- above.
+ --
+ -- So by failing here (rather than crashing), we ensure this behavior.
+ROLLBACK;
+
+RESET client_min_messages;
+RESET citus.node_connection_timeout;
+
-- restore coordinator for the rest of the tests
SELECT citus_set_coordinator_host('localhost', :master_port);
diff --git a/src/test/regress/sql/role_operations_from_non_maindb.sql b/src/test/regress/sql/role_operations_from_non_maindb.sql
deleted file mode 100644
index 5f569208b..000000000
--- a/src/test/regress/sql/role_operations_from_non_maindb.sql
+++ /dev/null
@@ -1,106 +0,0 @@
--- Create a new database
-set citus.enable_create_database_propagation to on;
-CREATE DATABASE role_operations_test_db;
-SET citus.superuser TO 'postgres';
--- Connect to the new database
-\c role_operations_test_db
--- Test CREATE ROLE with various options
-CREATE ROLE test_role1 WITH LOGIN PASSWORD 'password1';
-
-\c role_operations_test_db - - :worker_1_port
-CREATE USER "test_role2-needs\!escape"
-WITH
- SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN REPLICATION BYPASSRLS CONNECTION
-LIMIT 10 VALID UNTIL '2023-01-01' IN ROLE test_role1;
-
-\c regression - - :master_port
-
-select result FROM run_command_on_all_nodes($$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb,
- rolcanlogin, rolreplication, rolbypassrls, rolconnlimit,
- (rolpassword != '') as pass_not_empty, DATE(rolvaliduntil)
- FROM pg_authid
- WHERE rolname in ('test_role1', 'test_role2-needs\!escape')
- ORDER BY rolname
- ) t
-$$);
-
-select result FROM run_command_on_all_nodes($$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT r.rolname
- FROM pg_dist_object d
- JOIN pg_roles r ON d.objid = r.oid
- WHERE r.rolname IN ('test_role1', 'test_role2-needs\!escape')
- order by r.rolname
- ) t
-$$);
-
-\c role_operations_test_db - - :master_port
--- Test ALTER ROLE with various options
-ALTER ROLE test_role1 WITH PASSWORD 'new_password1';
-
-\c role_operations_test_db - - :worker_1_port
-ALTER USER "test_role2-needs\!escape"
-WITH
- NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION
-LIMIT 5 VALID UNTIL '2024-01-01';
-
-\c regression - - :master_port
-select result FROM run_command_on_all_nodes($$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb,
- rolcanlogin, rolreplication, rolbypassrls, rolconnlimit,
- (rolpassword != '') as pass_not_empty, DATE(rolvaliduntil)
- FROM pg_authid
- WHERE rolname in ('test_role1', 'test_role2-needs\!escape')
- ORDER BY rolname
- ) t
-$$);
-
-\c role_operations_test_db - - :master_port
--- Test DROP ROLE
-DROP ROLE no_such_role; -- fails nicely
-DROP ROLE IF EXISTS no_such_role; -- doesn't fail
-
-CREATE ROLE new_role;
-DROP ROLE IF EXISTS no_such_role, new_role; -- doesn't fail
-DROP ROLE IF EXISTS test_role1, "test_role2-needs\!escape";
-
-\c regression - - :master_port
---verify that roles and dist_object are dropped
-select result FROM run_command_on_all_nodes($$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb,
- rolcanlogin, rolreplication, rolbypassrls, rolconnlimit,
- (rolpassword != '') as pass_not_empty, DATE(rolvaliduntil)
- FROM pg_authid
- WHERE rolname in ('test_role1', 'test_role2-needs\!escape','new_role','no_such_role')
- ORDER BY rolname
- ) t
-$$);
-
-select result FROM run_command_on_all_nodes($$
- SELECT array_to_json(array_agg(row_to_json(t)))
- FROM (
- SELECT r.rolname
- FROM pg_roles r
- WHERE r.rolname IN ('test_role1', 'test_role2-needs\!escape','new_role','no_such_role')
- order by r.rolname
- ) t
-$$);
-
-SELECT result FROM run_command_on_all_nodes($$
- SELECT count(*) leaked_pg_dist_object_records_for_roles
- FROM pg_dist_object LEFT JOIN pg_authid ON (objid = oid)
- WHERE classid = 1260 AND oid IS NULL
-$$);
-
--- Clean up: drop the database
-set citus.enable_create_database_propagation to on;
-DROP DATABASE role_operations_test_db;
-reset citus.enable_create_database_propagation;
diff --git a/src/test/regress/sql/seclabel_non_maindb.sql b/src/test/regress/sql/seclabel_non_maindb.sql
deleted file mode 100644
index 1833d4193..000000000
--- a/src/test/regress/sql/seclabel_non_maindb.sql
+++ /dev/null
@@ -1,71 +0,0 @@
--- SECLABEL
---
--- Test suite for running SECURITY LABEL ON ROLE statements from non-main databases
-
-SET citus.enable_create_database_propagation to ON;
-
-CREATE DATABASE database1;
-CREATE DATABASE database2;
-
-\c - - - :worker_1_port
-SET citus.enable_create_database_propagation to ON;
-CREATE DATABASE database_w1;
-
-
-\c - - - :master_port
-CREATE ROLE user1;
-\c database1
-SHOW citus.main_db;
-SHOW citus.superuser;
-
-CREATE ROLE "user 2";
-
--- Set a SECURITY LABEL on a role from a non-main database
-SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE user1 IS 'citus_classified';
-SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus_unclassified';
-
--- Check the result
-\c regression
-SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
-SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
-
-\c database1
--- Set a SECURITY LABEL on database, it should not be propagated
-SECURITY LABEL FOR "citus '!tests_label_provider" ON DATABASE database1 IS 'citus_classified';
-
--- Set a SECURITY LABEL on a table, it should not be propagated
-CREATE TABLE a (i int);
-SECURITY LABEL ON TABLE a IS 'citus_classified';
-
-\c regression
-SELECT node_type, result FROM get_citus_tests_label_provider_labels('database1') ORDER BY node_type;
-
--- Check that only the SECURITY LABEL for ROLES is propagated to the non-main databases on other nodes
-\c database_w1 - - :worker_1_port
-SELECT provider, objtype, label, objname FROM pg_seclabels ORDER BY objname;
-
-
--- Check the result after a transaction
-BEGIN;
-SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE user1 IS 'citus_unclassified';
-SECURITY LABEL FOR "citus '!tests_label_provider" ON DATABASE database_w1 IS 'citus_classified';
-COMMIT;
-
-\c regression
-SELECT node_type, result FROM get_citus_tests_label_provider_labels('database_w1') ORDER BY node_type;
-SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
-
-BEGIN;
-SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus_classified';
-ROLLBACK;
-
-SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
-
--- clean up
-SET citus.enable_create_database_propagation to ON;
-DROP DATABASE database1;
-DROP DATABASE database2;
-DROP DATABASE database_w1;
-DROP ROLE user1;
-DROP ROLE "user 2";
-RESET citus.enable_create_database_propagation;
diff --git a/src/test/regress/sql/system_queries.sql b/src/test/regress/sql/system_queries.sql
index 1e1d86876..d43d20d53 100644
--- a/src/test/regress/sql/system_queries.sql
+++ b/src/test/regress/sql/system_queries.sql
@@ -1,3 +1,5 @@
+BEGIN;
+SET LOCAL citus.show_shards_for_app_name_prefixes = '';
-- The following query retrieves the foreign key constraints of the table "pg_dist_background_job"
-- along with their details. This modification includes a fix for a null pointer exception that occurred
-- in the "HasRangeTableRef" method of "worker_shard_visibility". The issue was resolved with PR #7604.
@@ -25,3 +27,4 @@ where
and ns.nspname='pg_catalog'
order by
fns.nspname, fc.relname, a.attnum;
+END;
diff --git a/src/test/regress/sql/upgrade_pg_dist_cleanup_after.sql b/src/test/regress/sql/upgrade_pg_dist_cleanup_after.sql
index e84c35b60..333ac60ca 100644
--- a/src/test/regress/sql/upgrade_pg_dist_cleanup_after.sql
+++ b/src/test/regress/sql/upgrade_pg_dist_cleanup_after.sql
@@ -13,3 +13,8 @@ SELECT COUNT(*) FROM pg_dist_placement WHERE shardid IN (SELECT shardid FROM pg_
SELECT * FROM pg_dist_cleanup;
CALL citus_cleanup_orphaned_resources();
DROP TABLE table_with_orphaned_shards;
+
+-- Re-enable automatic shard cleanup by maintenance daemon as
+-- we have disabled it in upgrade_pg_dist_cleanup_before.sql
+ALTER SYSTEM RESET citus.defer_shard_delete_interval;
+SELECT pg_reload_conf();
diff --git a/src/test/regress/sql/upgrade_pg_dist_cleanup_before.sql b/src/test/regress/sql/upgrade_pg_dist_cleanup_before.sql
index 62ec8a1fb..ec0eef353 100644
--- a/src/test/regress/sql/upgrade_pg_dist_cleanup_before.sql
+++ b/src/test/regress/sql/upgrade_pg_dist_cleanup_before.sql
@@ -16,6 +16,16 @@ SELECT create_distributed_table('table_with_orphaned_shards', 'a');
-- show all 32 placements are active
SELECT COUNT(*) FROM pg_dist_placement WHERE shardstate = 1 AND shardid IN (SELECT shardid FROM pg_dist_shard WHERE logicalrelid='table_with_orphaned_shards'::regclass);
-- create an orphaned placement based on an existing one
+--
+-- But before doing that, first disable automatic shard cleanup
+-- by maintenance daemon so that we can reliably test the cleanup
+-- in upgrade_pg_dist_cleanup_after.sql.
+
+ALTER SYSTEM SET citus.defer_shard_delete_interval TO -1;
+SELECT pg_reload_conf();
+
+SELECT pg_sleep(0.1);
+
INSERT INTO pg_dist_placement(placementid, shardid, shardstate, shardlength, groupid)
SELECT nextval('pg_dist_placement_placementid_seq'::regclass), shardid, 4, shardlength, 3-groupid
FROM pg_dist_placement